From 7769e4a04c873bb12c44859f2721f66ce017c40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0smail=20Y=C4=B1lmaz?= <32938453+ismail-yilmaz@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:14:25 +0300 Subject: [PATCH] Core/SSH: libssh2 upgraded to version 1.11.1 (#209) * Core/SSH: libssh2 upgraded to version 1.11.1 * Core/SSH: SFtpStream: Don't try to read file attrs if the file is newly created. * Core/SSH: Error log fix. --- uppsrc/Core/SSH/Copying | 4 +- uppsrc/Core/SSH/SFtp.cpp | 2 +- uppsrc/Core/SSH/SFtpStream.cpp | 3 +- uppsrc/Core/SSH/SSH.h | 2 + uppsrc/Core/SSH/SSH.upp | 6 +- uppsrc/Core/SSH/Session.cpp | 29 +- uppsrc/Core/SSH/Session.h | 15 +- uppsrc/Core/SSH/libssh2/{Copying => COPYING} | 15 +- uppsrc/Core/SSH/libssh2/ChangeLog | 1 - uppsrc/Core/SSH/libssh2/NEWS | 13705 ++++++++++------ uppsrc/Core/SSH/libssh2/NMakefile | 30 - uppsrc/Core/SSH/libssh2/README | 4 +- uppsrc/Core/SSH/libssh2/RELEASE-NOTES | 373 +- uppsrc/Core/SSH/libssh2/agent.c | 307 +- uppsrc/Core/SSH/libssh2/agent.h | 112 - uppsrc/Core/SSH/libssh2/agent_win.c | 48 +- uppsrc/Core/SSH/libssh2/bcrypt_pbkdf.c | 84 +- uppsrc/Core/SSH/libssh2/blf.h | 89 - uppsrc/Core/SSH/libssh2/blowfish.c | 168 +- uppsrc/Core/SSH/libssh2/chacha.c | 224 + uppsrc/Core/SSH/libssh2/chacha.h | 33 + uppsrc/Core/SSH/libssh2/channel.c | 512 +- uppsrc/Core/SSH/libssh2/channel.h | 11 +- uppsrc/Core/SSH/libssh2/cipher-chachapoly.c | 134 + uppsrc/Core/SSH/libssh2/cipher-chachapoly.h | 41 + uppsrc/Core/SSH/libssh2/comp.c | 63 +- uppsrc/Core/SSH/libssh2/comp.h | 9 +- uppsrc/Core/SSH/libssh2/crypt.c | 242 +- uppsrc/Core/SSH/libssh2/crypto.c | 19 + uppsrc/Core/SSH/libssh2/crypto.h | 171 +- uppsrc/Core/SSH/libssh2/crypto_config.h | 76 + uppsrc/Core/SSH/libssh2/global.c | 8 +- uppsrc/Core/SSH/libssh2/hostkey.c | 524 +- uppsrc/Core/SSH/libssh2/keepalive.c | 15 +- uppsrc/Core/SSH/libssh2/kex.c | 1802 +- uppsrc/Core/SSH/libssh2/knownhost.c | 71 +- uppsrc/Core/SSH/libssh2/libgcrypt.c | 340 +- uppsrc/Core/SSH/libssh2/libgcrypt.h | 160 +- uppsrc/Core/SSH/libssh2/libssh2.h | 477 +- uppsrc/Core/SSH/libssh2/libssh2.pc.in | 17 - uppsrc/Core/SSH/libssh2/libssh2.rc | 48 + uppsrc/Core/SSH/libssh2/libssh2_config.h | 20 +- uppsrc/Core/SSH/libssh2/libssh2_config.h.in | 252 - .../SSH/libssh2/libssh2_config_cmake.h.in | 61 +- uppsrc/Core/SSH/libssh2/libssh2_priv.h | 437 +- uppsrc/Core/SSH/libssh2/libssh2_publickey.h | 24 +- uppsrc/Core/SSH/libssh2/libssh2_setup.h | 103 + uppsrc/Core/SSH/libssh2/libssh2_sftp.h | 93 +- uppsrc/Core/SSH/libssh2/mac.c | 319 +- uppsrc/Core/SSH/libssh2/mac.h | 18 +- uppsrc/Core/SSH/libssh2/mbedtls.c | 674 +- uppsrc/Core/SSH/libssh2/mbedtls.h | 352 +- uppsrc/Core/SSH/libssh2/misc.c | 421 +- uppsrc/Core/SSH/libssh2/misc.h | 65 +- uppsrc/Core/SSH/libssh2/openssl.c | 3313 +++- uppsrc/Core/SSH/libssh2/openssl.h | 325 +- uppsrc/Core/SSH/libssh2/os400qc3.c | 2535 +++ uppsrc/Core/SSH/libssh2/os400qc3.h | 397 + uppsrc/Core/SSH/libssh2/packet.c | 614 +- uppsrc/Core/SSH/libssh2/packet.h | 13 +- uppsrc/Core/SSH/libssh2/pem.c | 232 +- uppsrc/Core/SSH/libssh2/poly1305.c | 206 + uppsrc/Core/SSH/libssh2/poly1305.h | 20 + uppsrc/Core/SSH/libssh2/publickey.c | 146 +- uppsrc/Core/SSH/libssh2/scp.c | 196 +- uppsrc/Core/SSH/libssh2/session.c | 626 +- uppsrc/Core/SSH/libssh2/session.h | 61 +- uppsrc/Core/SSH/libssh2/sftp.c | 933 +- uppsrc/Core/SSH/libssh2/sftp.h | 32 +- uppsrc/Core/SSH/libssh2/transport.c | 716 +- uppsrc/Core/SSH/libssh2/transport.h | 15 +- uppsrc/Core/SSH/libssh2/userauth.c | 1024 +- uppsrc/Core/SSH/libssh2/userauth.h | 18 +- uppsrc/Core/SSH/libssh2/userauth_kbd_packet.c | 166 + uppsrc/Core/SSH/libssh2/userauth_kbd_packet.h | 45 + uppsrc/Core/SSH/libssh2/version.c | 18 +- uppsrc/Core/SSH/libssh2/wincng.c | 2196 ++- uppsrc/Core/SSH/libssh2/wincng.h | 456 +- uppsrc/Core/SSH/libssh2upp.c | 32 - uppsrc/Core/SSH/libssh2upp.ext | 7 + .../SSH/src.tpp/Upp_Ssh_Session_en-us.tpp | 34 +- .../SSH/src.tpp/Upp_Ssh_Session_en-us.tppi | 35 +- 82 files changed, 26279 insertions(+), 10965 deletions(-) rename uppsrc/Core/SSH/libssh2/{Copying => COPYING} (82%) delete mode 100644 uppsrc/Core/SSH/libssh2/ChangeLog delete mode 100644 uppsrc/Core/SSH/libssh2/NMakefile delete mode 100644 uppsrc/Core/SSH/libssh2/agent.h delete mode 100644 uppsrc/Core/SSH/libssh2/blf.h create mode 100644 uppsrc/Core/SSH/libssh2/chacha.c create mode 100644 uppsrc/Core/SSH/libssh2/chacha.h create mode 100644 uppsrc/Core/SSH/libssh2/cipher-chachapoly.c create mode 100644 uppsrc/Core/SSH/libssh2/cipher-chachapoly.h create mode 100644 uppsrc/Core/SSH/libssh2/crypto.c create mode 100644 uppsrc/Core/SSH/libssh2/crypto_config.h delete mode 100644 uppsrc/Core/SSH/libssh2/libssh2.pc.in create mode 100644 uppsrc/Core/SSH/libssh2/libssh2.rc delete mode 100644 uppsrc/Core/SSH/libssh2/libssh2_config.h.in create mode 100644 uppsrc/Core/SSH/libssh2/libssh2_setup.h create mode 100644 uppsrc/Core/SSH/libssh2/os400qc3.c create mode 100644 uppsrc/Core/SSH/libssh2/os400qc3.h create mode 100644 uppsrc/Core/SSH/libssh2/poly1305.c create mode 100644 uppsrc/Core/SSH/libssh2/poly1305.h create mode 100644 uppsrc/Core/SSH/libssh2/userauth_kbd_packet.c create mode 100644 uppsrc/Core/SSH/libssh2/userauth_kbd_packet.h delete mode 100644 uppsrc/Core/SSH/libssh2upp.c create mode 100644 uppsrc/Core/SSH/libssh2upp.ext diff --git a/uppsrc/Core/SSH/Copying b/uppsrc/Core/SSH/Copying index 8fc6713bb..04dacbf87 100644 --- a/uppsrc/Core/SSH/Copying +++ b/uppsrc/Core/SSH/Copying @@ -1,6 +1,6 @@ -SSH package for Ultimate++ +SSH package for U++ -Copyright (c) 2016, 2022, İsmail Yılmaz +Copyright (c) 2016, 2024, İsmail Yılmaz All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted diff --git a/uppsrc/Core/SSH/SFtp.cpp b/uppsrc/Core/SSH/SFtp.cpp index d40861f45..740457e1a 100644 --- a/uppsrc/Core/SSH/SFtp.cpp +++ b/uppsrc/Core/SSH/SFtp.cpp @@ -204,7 +204,7 @@ bool SFtp::CopyData(Stream& dest, Stream& src, int64 maxsize) if(n > 0) { dest.Put(chunk, n); if(dest.IsError()) { - LLOG("Stream write error. " + src.GetErrorText()); + LLOG("Stream write error. " + dest.GetErrorText()); return false; } count += n; diff --git a/uppsrc/Core/SSH/SFtpStream.cpp b/uppsrc/Core/SSH/SFtpStream.cpp index f9cf10bfe..f8868c50d 100644 --- a/uppsrc/Core/SSH/SFtpStream.cpp +++ b/uppsrc/Core/SSH/SFtpStream.cpp @@ -58,7 +58,8 @@ bool SFtpStream::Open(SFtp& sftp_, const char *filename, dword mode, int acm) if(handle) { SFtpAttrs attrs; - if(!sftp->GetAttrs(handle, attrs)) { + Zero(attrs); + if(iomode != CREATE && !sftp->GetAttrs(handle, attrs)) { sftp->Close(handle); handle = nullptr; return false; diff --git a/uppsrc/Core/SSH/SSH.h b/uppsrc/Core/SSH/SSH.h index f4677b10f..d572bbc38 100644 --- a/uppsrc/Core/SSH/SSH.h +++ b/uppsrc/Core/SSH/SSH.h @@ -10,6 +10,8 @@ #include #endif + +#include "libssh2/libssh2_setup.h" #include "libssh2/libssh2.h" #include "libssh2/libssh2_sftp.h" #include "libssh2/libssh2_publickey.h" diff --git a/uppsrc/Core/SSH/SSH.upp b/uppsrc/Core/SSH/SSH.upp index 5660b96d9..6b81c23a3 100644 --- a/uppsrc/Core/SSH/SSH.upp +++ b/uppsrc/Core/SSH/SSH.upp @@ -42,9 +42,9 @@ file Hosts.h, Hosts.cpp, "Library Files" readonly separator, - libssh2upp.c, - libssh2\libssh2_config.h, - libssh2/Copying, + libssh2/libssh2_config.h, + libssh2upp.ext, + libssh2/COPYING, Docs readonly separator, src.tpp, Info readonly separator, diff --git a/uppsrc/Core/SSH/Session.cpp b/uppsrc/Core/SSH/Session.cpp index 903aec58f..54e2fa37b 100644 --- a/uppsrc/Core/SSH/Session.cpp +++ b/uppsrc/Core/SSH/Session.cpp @@ -247,36 +247,43 @@ bool SshSession::Connect(const String& host, int port, const String& user, const ? &sChangePasswordCallback : nullptr); break; - case PUBLICKEY: + case PUBLICKEY: { + // Allow computation of public key from private key. + const char *pubkey = !IsNull(session->pubkey) ? ~session->pubkey : nullptr; rc = session->keyfile ? libssh2_userauth_publickey_fromfile( - ssh->session, + ssh->session, ~user, - ~session->pubkey, + pubkey, ~session->prikey, ~session->phrase) : libssh2_userauth_publickey_frommemory( - ssh->session, + ssh->session, ~user, user.GetLength(), - ~session->pubkey, - session->pubkey.GetLength(), + pubkey, + ~session->pubkey.GetLength(), ~session->prikey, session->prikey.GetLength(), ~session->phrase); break; - case HOSTBASED: + } + case HOSTBASED: { if(!session->keyfile) ThrowError(-1, "Keys cannot be loaded from memory."); - else + else { + // Allow computation of public key from private key. + const char *pubkey = !IsNull(session->pubkey) ? ~session->pubkey : nullptr; rc = libssh2_userauth_hostbased_fromfile( - ssh->session, + ssh->session, ~user, - ~session->pubkey, + pubkey, ~session->prikey, ~session->phrase, ~host); + } break; + } case KEYBOARD: rc = libssh2_userauth_keyboard_interactive( ssh->session, @@ -302,7 +309,7 @@ bool SshSession::Connect(const String& host, int port, const String& user, const Finalize: #ifdef PLATFORM_POSIX - libssh2_session_callback_set(ssh->session, LIBSSH2_CALLBACK_X11, (void*) sX11RequestCallback); + libssh2_session_callback_set2(ssh->session, LIBSSH2_CALLBACK_X11, (libssh2_cb_generic*) sX11RequestCallback); LLOG("X11 dispatcher is set."); #endif return true; diff --git a/uppsrc/Core/SSH/Session.h b/uppsrc/Core/SSH/Session.h index 56bbc652b..467787b78 100644 --- a/uppsrc/Core/SSH/Session.h +++ b/uppsrc/Core/SSH/Session.h @@ -47,13 +47,6 @@ public: TcpSocket& GetSocket() { return session->socket; } ValueMap GetMethods() const; - SFtp CreateSFtp(); - SshChannel CreateChannel(); - SshExec CreateExec(); - Scp CreateScp(); - SshTunnel CreateTunnel(); - SshShell CreateShell(); - bool Connect(const String& url); bool Connect(const String& host, int port, const String& user, const String& password); void Disconnect(); @@ -72,6 +65,14 @@ public: SshSession(SshSession&&) = default; + // Deprecations. + [[deprecated("This method is deprecated and will be removed in U++ 2025.1. Use the class constructor instead.")]] SFtp CreateSFtp(); + [[deprecated("This method is deprecated and will be removed in U++ 2025.1. Use the class constructor instead.")]] SshChannel CreateChannel(); + [[deprecated("This method is deprecated and will be removed in U++ 2025.1. Use the class constructor instead.")]] SshExec CreateExec(); + [[deprecated("This method is deprecated and will be removed in U++ 2025.1. Use the class constructor instead.")]] Scp CreateScp(); + [[deprecated("This method is deprecated and will be removed in U++ 2025.1. Use the class constructor instead.")]] SshTunnel CreateTunnel(); + [[deprecated("This method is deprecated and will be removed in U++ 2025.1. Use the class constructor instead.")]] SshShell CreateShell(); + private: void Exit() override; String GetHostKeyHash(int type, int length) const; diff --git a/uppsrc/Core/SSH/libssh2/Copying b/uppsrc/Core/SSH/libssh2/COPYING similarity index 82% rename from uppsrc/Core/SSH/libssh2/Copying rename to uppsrc/Core/SSH/libssh2/COPYING index 937ed32e3..6eb514684 100644 --- a/uppsrc/Core/SSH/libssh2/Copying +++ b/uppsrc/Core/SSH/libssh2/COPYING @@ -1,11 +1,11 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2005,2006 Mikhail Gusarov - * Copyright (c) 2006-2007 The Written Word, Inc. - * Copyright (c) 2007 Eli Fant - * Copyright (c) 2009-2021 Daniel Stenberg +/* Copyright (C) 2004-2007 Sara Golemon + * Copyright (C) 2005,2006 Mikhail Gusarov + * Copyright (C) 2006-2007 The Written Word, Inc. + * Copyright (C) 2007 Eli Fant + * Copyright (C) 2009-2023 Daniel Stenberg * Copyright (C) 2008, 2009 Simon Josefsson - * Copyright (c) 2000 Markus Friedl - * Copyright (c) 2015 Microsoft Corp. + * Copyright (C) 2000 Markus Friedl + * Copyright (C) 2015 Microsoft Corp. * All rights reserved. * * Redistribution and use in source and binary forms, @@ -41,4 +41,3 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ - diff --git a/uppsrc/Core/SSH/libssh2/ChangeLog b/uppsrc/Core/SSH/libssh2/ChangeLog deleted file mode 100644 index 404c887c2..000000000 --- a/uppsrc/Core/SSH/libssh2/ChangeLog +++ /dev/null @@ -1 +0,0 @@ -see NEWS diff --git a/uppsrc/Core/SSH/libssh2/NEWS b/uppsrc/Core/SSH/libssh2/NEWS index 7e22b3dd8..b3bd14cba 100644 --- a/uppsrc/Core/SSH/libssh2/NEWS +++ b/uppsrc/Core/SSH/libssh2/NEWS @@ -1,5 +1,8890 @@ Changelog for the libssh2 project. Generated with git2news.pl +Daniel Stenberg (16 Oct 2024) +- RELEASE-NOTES: 1.11.1 + +Viktor Szakats (8 Oct 2024) +- RELEASE-NOTES: sync [ci skip] + +- [Anders Borum brought this change] + + session: support server banners up to 8192 bytes (was: 256) + + If server had banner exceeding 256 bytes there wasn't enough room in + `_LIBSSH2_SESSION.banner_TxRx_banner`. Only the first 256 bytes would be + read making the first packet read fail but also dooming key exchange as + `session->remote.banner` didn't include everything. + + This change bumps the banner buffer to 8KB to match OpenSSH. + + Fixes #1442 + Closes #1443 + +- RELEASE-NOTES: sync [ci skip] + +- cmake: sync and improve Find modules, add `pkg-config` native detection + + - sync code between Find modules. + - wolfssl: replace `pkg-config` hints with native detection. + - libgcrypt, mbedtls: add `pkg-config`-based native detection. + - libgcrypt: add version detection. + - limit `pkg-config` use for `UNIX`, vcpkg, and non-cross MinGW builds, + and builds with no manual customization via `*_INCLUDE_DIR` or + `*_LIBRARY`. + - replace and sync Find module header comments. + - ci: delete manual mbedTLS config that's now redundant. + + Based on similar work done in curl. + + Second attempt at #1420 + Closes #1445 + +- cmake: initialize `LIBSSH2_LIBDIRS` [ci skip] + + Follow-up to c87f12963037b22e6b60411c9c2d6513c06e2f03 #1466 + +- ci/appveyor: fix and bump OpenSSL 3 path, add path check + + Follow-up to b5e68bdc37c6afa0dc777794dda8307167919d04 #1461 + Closes #1468 + +- cmake: link to OpenSSL::Crypto, not OpenSSL::SSL + + Follow-up to 82b09f9b3aae97f641fbcc2d746d2a6383abe857 #1322 + Follow-up to c84745e34e53f863ffba997ceeee7d43d1c63a4b #1128 + Cherry-picked from #1445 + Closes #1467 + +- cmake: generate `LIBSSH2_PC_LIBS_PRIVATE` dynamically + + Generate `LIBSSH2_PC_LIBS_PRIVATE` from `LIBSSH2_LIBS`. + + Also add extra libdirs (`-L`) to `Libs` and `Libs.private`. + + Logic copied from curl. + + Closes #1466 + +- cmake: initialize `LIBSSH2_PC_REQUIRES_PRIVATE` [ci skip] + + Follow-up to 0fce9dcc2909ffff5f4a1a1bc3d359fc7f409299 #1464 + +- cmake: add comment about `ibssh2.pc.in` variables [ci skip] + +- cmake: support absolute `CMAKE_INSTALL_INCLUDEDIR`/`CMAKE_INSTALL_LIBDIR` + + in `libssh2.pc`. + + Also use `${exec_prefix}` (instead of `${prefix}`) as a base for `libdir`. + + Closes #1465 + +- cmake: rename two variables and initialize them + + - `LIBRARIES` -> `LIBSSH2_LIBS` + - `SOCKET_LIBRARIES` -> `LIBSSH2_LIBS_SOCKET` + + Also initialize them before use. + + Cherry-picked from #1445 + Closes #1464 + +- ci/appveyor: reduce test runs (workaround for infrastructure permafails) + + Jobs consistently fail to connect to the test server (run in GHA) since + 2024-Aug-29: + https://ci.appveyor.com/project/libssh2org/libssh2/builds/50498393 + + There was an earlier phase of failures one month before that, that got + fixed by increasing the wait for the server in + bf3af90b3f1bb14cf452df7a8eb55cc9088f3e7f. + + Thus, skip running tests in AppVeyor CI jobs, except: After some + experiments, it seems that running tests with the last OpenSSL job and + the last WinCrypt job _work_, which still leaves some coverage. + It remains to be seen how stable this is. + + This is meant as a temporary fix till there is a solution to make all + jobs run tests reliable like up until a few months ago. + + Closes #1461 + +- [Patrick Monnerat brought this change] + + os400: drop vsprintf() use + + Follow-up to discussion in #1457 + + Plus e-mail address update. + + Closes #1462 + +- RELEASE-NOTES: sync [ci skip] + +Daniel Stenberg (30 Sep 2024) +- openssl: free allocated resources when using openssl3 + + Reproduces consistently with curl test case 638 + + Closes #1459 + +Viktor Szakats (28 Sep 2024) +- checksrc: update, check all sources, fix fallouts + + update from curl: + https://github.com/curl/curl/blob/cff75acfeca65738da8297aee0b30427b004b240/scripts/checksrc.pl + + Closes #1457 + +- cmake: prefer `find_dependency()` in `libssh2-config.cmake` + + CMake manual suggest using `find_dependency()` (over `find_package()`) + in `config.cmake` scripts. + + Ref: https://cmake.org/cmake/help/latest/module/CMakeFindDependencyMacro.html + + Closes #1460 + +- ci: use Ninja with cmake + + Closes #1458 + +GitHub (27 Sep 2024) +- [dksslq brought this change] + + Fix memory leaks in _libssh2_ecdsa_curve_name_with_octal_new and _libssh2_ecdsa_verify (#1449) + + Better error handling in`_libssh2_ecdsa_curve_name_with_octal_new` and `_libssh2_ecdsa_verify` to prevent leaks. + + Credit: dksslq + +- [rolag brought this change] + + Fix unstable connections over nonblocking sockets (#1454) + + The `send_existing()` function allows partially sent packets to be sent + fully before any further packets are sent. Originally this returned + `LIBSSH2_ERROR_BAD_USE` when a different caller or thread tried to send + an existing packet created by a different caller or thread causing the + connection to disconnect. Commit 33dddd2f8ac3bc81 removed the return + allowing any caller to continue sending another caller's packet. This + caused connection instability as discussed in #1397 and confused the + client and server causing occasional duplicate packets to be sent and + giving the error `rcvd too much data` as discussed in #1431. We return + `LIBSSH2_ERROR_EAGAIN` instead to allow existing callers to finish + sending their own packets. + + Fixes #1397 + Fixes #1431 + Related #720 + + Credit: klux21, rolag + +- [Will Cosgrove brought this change] + + Prevent possible double free of hostkey (#1452) + + NULL server hostkey based on fuzzer failure case. + +Viktor Szakats (7 Sep 2024) +- cmake: tidy up syntax, minor improvements + + - make internal variables underscore-lowercase. + - unfold lines. + - fold lines setting header directories. + - fix indent. + - drop interim variable `EXAMPLES`. + - initialize some variables before populating them. + - clear a variable after use. + - add `libssh2_dumpvars()` function for debugging. + - allow to override default `CMAKE_UNITY_BUILD_BATCH_SIZE`. + - bump up default `CMAKE_UNITY_BUILD_BATCH_SIZE` to 0 (was 32). + - tidy up option descriptions. + + Closes #1446 + +- cmake: rename mbedTLS and wolfSSL Find modules + + To match the curl ones. + + Cherry-picked from #1445 + +- RELEASE-NOTES: sync [ci skip] + +- cmake: fixup version detection in mbedTLS find module + + - avoid warning with 2.x versions about missing header file while + extracting the version number. + + - clear temp variables. + + Closes #1444 + +- buildconf: drop + + Use `autoreconf -fi` instead. + + Follow-up to fc5d77881eb6bb179f831e626d15f4f29179aad5 + Closes #1441 + +- [Michael Buckley brought this change] + + Implement chacha20-poly1305@openssh.com + + Probably the biggest and potentially most controversial change we have + to upstream. + + Because earlier versions of OpenSSL implemented the algorithm before + standardization, using an older version of OpenSSL can cause problems + connecting to OpenSSH servers. Because of this, we use the public domain + reference implementation instead of the crypto backends, just like + OpenSSH does. + + We've been holding this one for a few years. We were about to upstream + it around the same time as aes128gcm landed upstream, and the two + changes were completely incompatible. Honestly, it took me weeks to + reconcile these two implementations, and it could be much better. + + Our original implementation changed every crypt method to decrypt the + entire message at once. the AESGCM implementation instead went with this + firstlast design, where a firstlast paramater indicates whether this is + the first or last call to the crypt method for each message. That added + a lot of bookkeeping overhead, and wasn't compatible with the chacha + public domain implementation. + + As far as I could tell, OpenSSH uses the technique of decrypting the + entire message in one go, and doesn't have anything like firstlast. + However, I could not get out aes128gcm implementation to work that way, + nor could I get the chacha implementation to work with firstlast, so I + split it down the middle and let each implementation work differently. + It's kind of a mess, and probably should be cleaned up, but I don't have + the time to spend on it anymore, and it's probably better to have + everything upstream. + + Fixes #584 + Closes #1426 + +- tidy-up: do/while formatting + + Also fix an indentation and delete empty lines. + + Closes #1440 + +- wolfssl: drop header path hack + + The wolfSSL OpenSSL headers reside in `wolfssl/openssl/*.h`. + + Before this patch the wolfSSL OpenSSL compatibilty header includes were + shared with the native OpenSSL codepath, and used `openssl/*h`. For + wolfSSL builds this required a hack to append the + `/wolfssl` directory to the header search path, to find + the headers. + + This patch changes the source to use the correct header references, + allowing to drop the header path hack. + + Also fix to use the correct variable to set up the header path in CMake: + `WOLFSSL_INCLUDE_DIRS` (was: `WOLFSSL_INCLUDE_DIR`, without the `S`) + + Closes #1439 + +- cmake: mbedTLS detection tidy-ups + + - set and use `MBEDTLS_INCLUDE_DIRS`. + - stop marking `MBEDTLS_LIBRARIES` as advanced. + + Closes #1438 + +- cmake: add quotes, delete ending dirseps + + Follow-up to 3fa5282d6284efba62dc591697e6a687152bdcb1 #1166 + Closes #1437 + +- CI/appveyor: increase wait for SSH server on GHA [ci skip] + + Blind attempt to make AppVeyor CI tests work again. + +- disable DSA by default + + Also: + - add `LIBSSH2_DSA_ENABLE` to enable it explicitly. + - test the above option in CI. + - say 'deprecated' in docs and public header. + - disable DSA in the CI server config. + (OpenSSH 9.8 no longer builds with it by default) + https://www.openssh.com/txt/release-9.8 + Patch-by: Jose Quaresma + - disable more DSA code when not enabled. + + Fixes #1433 + Closes #1435 + +GitHub (30 Jul 2024) +- [Viktor Szakats brought this change] + + tidy-up: link updates (#1434) + +Marc Hoersken (27 Jul 2024) +- ci/GHA: revert concurrency and improve permissions + + Statuses are per AppVeyor event and commit, not pull-request. + Also align permissions approach with curl, least priviledge. + + Partially reverts b08cfbc99fa4df3459db4e1ccf4263fd260e9b15. + +GitHub (23 Jul 2024) +- [Will Cosgrove brought this change] + + Always init mbedtls_pk_context (#1430) + + In the failure case, mbedtls_pk_context could be free'd without first being initialized. + +- [Viktor Szakats brought this change] + + mbedtls: tidy-up (#1429) + +- [Will Cosgrove brought this change] + + Correctly initialize values (#1428) + + Fix regression with commit from #1421 + +Viktor Szakats (14 Jul 2024) +- RELEASE-NOTES: sync [ci skip] + +- [Seo Suchan brought this change] + + mbedtls: expose `mbedtls_pk_load_file()` for our use + + While it's moved to pk_internal, it won't removed in mbedTLS 3.6 LTS + so it's safe to redeclare it on our side to find it. + + This is implementing emergency fix suggested from + https://github.com/libssh2/libssh2/commit/2e4c5ec4627b3ecf4b6da16f365c011dec9a31b4#commitcomment-141379351 + + Follow-up to e973493f992313b3be73f51d3f7ca6d52e288558 #1393 + Follow-up to 2e4c5ec4627b3ecf4b6da16f365c011dec9a31b4 #1349 + Closes #1421 + +GitHub (13 Jul 2024) +- [Viktor Szakats brought this change] + + ci/GHA: simplify mbedTLS build hack for autotools (#1425) + + Follow-up to e973493f992313b3be73f51d3f7ca6d52e288558 #1393 + +- [Michael Buckley brought this change] + + Always check for null pointers before calling _libssh2_bn_set_word (#1423) + +- [Viktor Szakats brought this change] + + ci/GHA: FreeBSD 14.1, actions bump (#1424) + +- [Michael Buckley brought this change] + + Increase SFTP_HANDLE_MAXLEN back to 4092 (#1422) + + Match OpenSSH for compatibility. + +Viktor Szakats (10 Jul 2024) +- ci/GHA: tidy up casing [ci skip] + +- REUSE: fix typo in comment + +- REUSE: shorten and improve + + Follow-up to 70b8bf314cf4566a7529c5d6eae63097a926abb0 #1419 + +- REUSE: upgrade to `REUSE.toml` + + Closes #1419 + +- build: stop detecting `sys/param.h` header + + This header is no longer used. + + Follow-up to 12427f4fb8e789adcee4a6e30974932883915e88 #1415 + Closes #1418 + +- [Nicolas Mora brought this change] + + tests: avoid using `MAXPATHLEN`, for portability + + `MAXPATHLEN` is not present in some systems, e.g. GNU Hurd. + + Co-authored-by: Viktor Szakats + Ref: 54bef4c5dad868a9d45fdbfca9729b191c0abab5 #198 + Fixes #1414 + Closes #1415 + +- cmake: sync formatting in `cmake/Find*` modules + +- [Michael Buckley brought this change] + + sftp: implement posix-rename@openssh.com + + Add a new function `libssh2_sftp_posix_rename_ex()` and + `libssh2_sftp_posix_rename()`, which implement + the posix-rename@openssh.com extension. + + If the server does not support this extension, the function returns + `LIBSSH2_FX_OP_UNSUPPORTED` and it's up to the user to recover, possibly + by calling `libssh2_sftp_rename()`. + + Co-authored-by: Viktor Szakats (bump to size_t) + Closes #1386 + +- src: use `UINT32_MAX` + + Needs to be defined for platforms missing it, e.g. VS2008. + + Closes #1413 + +GitHub (25 Jun 2024) +- [Michael Buckley brought this change] + + Fix a memory leak in key exchange. (#1412) + + Original fix submitted as a patch by Trzik. + + Co-authored-by: Michael Buckley + +Viktor Szakats (25 Jun 2024) +- RELEASE-NOTES: sync [ci skip] + +- wolfssl: fix `EVP_Cipher()` use with v5.6.0 and older + + Add workaround for the wolfSSL `EVP_Cipher(*p, NULL, NULL, 0)` bug to + make libssh2 work with wolfSSL v5.6.0 and older. + + wolfSSL fixed this issue in v5.7.0: + https://github.com/wolfSSL/wolfssl/pull/7143 + https://github.com/wolfSSL/wolfssl/commit/b0de0a1c95119786cf5651dd76dd7d7bdfac5a04 + + Without our local workaround: + + - v5.3.0 and older fail most tests: + Ref: https://github.com/libssh2/libssh2/actions/runs/9646827522/job/26604211476#step:17:1263 + + - v5.4.0, v5.5.x, v5.6.0 fail these: + ``` + 29 - test_read-aes128-cbc (Failed) + 30 - test_read-aes128-ctr (Failed) + 32 - test_read-aes192-cbc (Failed) + 33 - test_read-aes192-ctr (Failed) + 34 - test_read-aes256-cbc (Failed) + 35 - test_read-aes256-ctr (Failed) + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/9646827522/job/26604233819#step:17:978 + + Oddly enough the workaround breaks OpenSSL tests, so only enable it for + the affected wolfSSL versions. + + Also add new build-from-source wolfSSL CI job to test the new codepath. + + wolfSSL has a build bug where `wolfssl/options.h` and + `wolfssl/version.h` are not copied to the `install` destination with + autotools. With CMake it has a different bug where `wolfcrypt/sp_int.h` + is not copied (with v5.4.0). And another with CMake where `FIPS_mode()` + remains missing (with v5.6.0 and earlier.) + + Therefore use CMake with v5.5.4 and a workaround for `FIPS_mode()`. + Another option is autotools with v5.4.0 and a workaround for `install`, + but CMake builds quicker. + + Regression-from 3c953c05d67eb1ebcfd3316f279f12c4b1d600b4 #797 + Fixes #1020 + Fixes #1299 + Assisted-by: Michael Buckley via #1394 + Closes #1394 (another attempt to fix the mentioned wolfSSL bug) + Closes #1407 + +- wolfssl: bump version in upstream issue comment [ci skip] + +- wolfssl: require v5.4.0 for AES-GCM + + Earlier versions crash while running tests. + + This patch is part of a series of fixes to make wolfSSL AES-GCM support + work together with libssh2. + + Possibly related is this wolfSSL bugfix patch, released in v5.4.0: + https://github.com/wolfSSL/wolfssl/pull/5205 + https://github.com/wolfSSL/wolfssl/commit/fb3c611275dfe454c331baa0818445a0406c208a + "Fix another AES-GCM EVP control command issue" + + Ref: #1020 + Ref: #1299 + Cherry-picked from #1407 + Closes #1411 + +- tests: fix excluding AES-GCM tests + + Replace hard-coded crypto backends and rely on `LIBSSH2_GCM` macro + to decide whether to run AES-GCM tests. + + Without this, build attempted to run AES-GCM tests (and failed) + for crypto backends that have conditional support for this feature, e.g. + wolfSSL without the necessary features built-in + (as in before Homewbrew wolfssl 5.7.0_1, or OpenSSL v1.1.0 and older). + + This patch is part of a series of fixes to make wolfSSL AES-GCM support + work together with libssh2. + + Cherry-picked from #1407 + Closes #1410 + +- ci/GHA: fix wolfSSL-from-source AES-GCM tests + + Turns out these tests: + ``` + 31 - test_read-aes128-gcm@openssh.com (Failed) + 36 - test_read-aes256-gcm@openssh.com (Failed) + ``` + were failing because AES-GCM wasn't enabled in libssh2. This in turn + happened because the `WOLFSSL_AESGCM_STREAM` macro wasn't enabled while + building wolfSSL. Which happened because this macro isn't enabled by + any CMake-level wolfSSL option. Passing it as `CPPFLAGS` fixes it. + + This allows enabling tests with wolfSSL 5.7.0. + + Follow-up to d4cea53f53c78febad14b4caa600e25d1aaf92fd #1408 + Closes #1409 + +- ci/GHA: add Linux job with latest wolfSSL built from source + + After this patch it's possible to run tests with wolfSSL 5.7.0. + + wolfSSL 5.7.0 fixes this bug that affects open issues #1020 and #1299: + https://github.com/wolfSSL/wolfssl/pull/7143 + + `-DWOLFSSL_OPENSSLALL=ON` is necessary for `wolfSSL_FIPS_mode()` + + Closes #1408 + +- ci/GHA: tidy up build-from-source steps [ci skip] + + - make curl downloads less verbose. + + - fix cmake warning: + ``` + CMake Warning: + No source or binary directory provided. Both will be assumed to be the + same as the current working directory, but note that this warning will + become a fatal error in future CMake releases. + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/9509866494/job/26213472410#step:5:32 + +- [Adam brought this change] + + src: fix type warning in `libssh2_sftp_unlink` macro + + The `libssh2_sftp_unlink` macro was implicitly casting the `size_t` + returned by `strlen` to the `unsigned int` type expected by + `libssh2_sftp_unlink_ex`. + + This fix adds an explicit cast to match similar macro definitions in + the same file (e.g. `libssh2_sftp_rename`, `libssh2_sftp_mkdir`). + + Closes #1406 + +- libssh2.pc: reference mbedcrypto pkgconfig + + mbedtls 3.6.0 got pkgconfig support: + https://github.com/Mbed-TLS/mbedtls/commit/a4d17b34f354557838e05d2cb47200e8dcaaf59b + + Reference it from `libssh2.pc`. + + Closes #1405 + +- tidy-up: typo in comment [ci skip] + +- RELEASE-NOTES: sync [ci skip] + + Also bump planned deprecation dates. + +- ci/GHA: show configure logs on failure and other tidy-ups + + - dump cmake error log on configure failure. (for cmake 3.26 and newer) + - dump `config.log` on autotools configure failure. + - convert specs filename to Windows format before passing to CMake. + - add missing quotes. + + Closes #1403 + +- ci/GHA: bump parallel jobs to nproc+1 + + Ref: https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories + + Closes #1402 + +- ci/GHA: show test logs on failure + + Closes #1401 + +- ci/GHA: fix `Dockerfile` failing after Ubuntu package update + + Likely due an upstream Ubuntu package update (requiring an apt-get + install call beforehand), tests run via autotools started failing with + no change in the libssh2 repo: + ``` + FAIL: test_aa_warmup + ==================== + + Error running command 'docker build --quiet -t libssh2/openssh_server %s' (exit 256): Dockerfile:10 + -------------------- + 8 | && apt-get clean \ + 9 | && rm -rf /var/lib/apt/lists/* + 10 | >>> RUN mkdir /var/run/sshd + 11 | + 12 | # Chmodding because, when building on Windows, files are copied in with + -------------------- + ERROR: failed to solve: process "/bin/sh -c mkdir /var/run/sshd" did not complete successfully: exit code: 1 + + Failed to build docker image + Cannot stop session - none started + Cannot stop container - none started + Command: docker build --quiet -t libssh2/openssh_server ../../tests/openssh_server + FAIL test_aa_warmup (exit status: 1) + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/9322194756/job/25662748095#step:11:390 + + Fix it by skipping `mkdir` if `/var/run/sshd` already exists. + + (Why cmake-based jobs aren't affected, I don't know.) + + Ref: https://github.com/libssh2/libssh2/commit/50143d5867d35df76a6cf589ca8a13b22105aa64#commitcomment-142560875 + Closes #1400 + +- ci/GHA: use ubuntu-latest with OmniOS job + + It's the same as ubuntu-22.04. + + Also update OmniOS package search link. + +- ci: disable dependency tracking in autotools builds + + For better build performance. Dependency tracking causes a build + overhead while compiling to help a subsequent build, but in CI there is + never one and the extra work is discarded. + + Closes #1396 + +- mbedtls: fail to compile with v3.6.0 outside CI + + A compile-time failure is preferred over an unexpected one at + runtime. + + The problem is silenced with a macro in CI and this macro will have + to be added to more platforms when mbedTLS v3.6.0 reaches them. + + Follow-up to 2e4c5ec4627b3ecf4b6da16f365c011dec9a31b4 #1349 + Closes #1393 + +- tests: drop default cygpath option `-u` + +- tidy-up: fix typo found by codespell + + Ref: https://github.com/libssh2/libssh2/actions/runs/9224795055/job/25380857082?pr=1393#step:4:5 + +- ci/GHA: shell syntax tidy-up + + Closes #1390 + +- RELEASE-NOTES: sync [ci skip] + +- ci/GHA: bump NetBSD/OpenBSD, add NetBSD arm64 job + + OpenBSD arm64 jobs were very slow, so skipped that. + + Closes #1388 + +- autotools: fix to update `LDFLAGS` for each detected dependency + + autotools lib detection routine failed to extend LDFLAGS for each + detection. This could cause successful detection of a dependency, but + later failing to use it. This did not cause an issue as long as all + dependencies lived under the same prefix, but started breaking on macOS + ARM + Homebrew where this was no longer true for mbedTLS and zlib in + particular. + + Follow-up to 844115393bffb4e92c6569204cbe4cd8e553480d #1381 + Follow-up to ae2770de25949bc7c74e60b4cc6a011bbe1d3d7c #1377 + Closes #1384 + +GitHub (8 May 2024) +- [Michael Buckley brought this change] + + OpenSSL 3: Fix calculating DSA public key (#1380) + +Viktor Szakats (8 May 2024) +- ci/GHA: tidy-up wolfSSL autotools config on macOS + + Closes #1383 + +- ci/GHA: shorter mbedTLS autotools workaround + + Follow-up to 844115393bffb4e92c6569204cbe4cd8e553480d #1381 + Closes #1382 + +GitHub (8 May 2024) +- [Michael Buckley brought this change] + + ci: fix mbedtls runners on macOS (#1381) + + Sets LDFLAGS while configuring the autoconf mbedTLS build for macOS. + +Viktor Szakats (29 Apr 2024) +- RELEASE-NOTES: sync [ci skip] + +- [binary1248 brought this change] + + wincng: fix `DH_GEX_MAXGROUP` set higher than supported + + In 1c3a03ebc3166cf69735111aba2b8cee57cdba51 #493, + `LIBSSH2_DH_GEX_MAXGROUP` was introduced to specify + crypto-backend-specific modulus sizes. Unfortunately, the max size for + the wincng DH modulus was defined to 8192, probably because this is the + value most other backends support. + + According to Microsoft documentation [1], `BCryptGenerateKeyPair` + currently only supports up to 4096-bit keys when the selected algorithm + is `BCRYPT_DH_ALGORITHM`. Requesting larger keys when calling + `BCryptGenerateKeyPair` in `_libssh2_dh_key_pair` always results in + `STATUS_INVALID_PARAMETER` being returned and ultimately key exchange + failing. + + When attempting to connect to any server that offers 8192 bit DH, this + causes key exchange to always fail when using the wincng backend. + Reducing `LIBSSH2_DH_GEX_MAXGROUP` to 4096 fixes the issue. + + [1] https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgeneratekeypair + + Closes #1372 + +- build: silence warnings inside `FD_SET()`/`FD_ISSET()` macros + + Use an ugly workaround to silence `-Wsign-conversion` warnings triggered + by the internals of `FD_SET()`/`FD_ISSET()` macros. They've been showing + up in OmniOS CI builds when compiling `example` programs. They also have + been seen with older Cygwin and other envs and configurations. + + Also scope two related variables in examples. + + E.g.: + ``` + ../../example/direct_tcpip.c:251:9: warning: conversion to 'long unsigned int' from 'libssh2_socket_t' {aka 'int'} may change the sign of the result [-Wsign-conversion] + 251 | FD_SET(forwardsock, &fds); + | ^~~~~~ + ../../example/direct_tcpip.c:251:9: warning: conversion to 'long unsigned int' from 'libssh2_socket_t' {aka 'int'} may change the sign of the result [-Wsign-conversion] + ../../example/direct_tcpip.c:251:9: warning: conversion to 'long unsigned int' from 'long int' may change the sign of the result [-Wsign-conversion] + ../../example/direct_tcpip.c:251:9: warning: conversion to 'long int' from 'long unsigned int' may change the sign of the result [-Wsign-conversion] + ../../example/direct_tcpip.c:259:18: warning: conversion to 'long unsigned int' from 'libssh2_socket_t' {aka 'int'} may change the sign of the result [-Wsign-conversion] + 259 | if(rc && FD_ISSET(forwardsock, &fds)) { + | ^~~~~~~~ + ../../example/direct_tcpip.c:259:18: warning: conversion to 'long unsigned int' from 'libssh2_socket_t' {aka 'int'} may change the sign of the result [-Wsign-conversion] + ../../example/direct_tcpip.c:259:18: warning: conversion to 'long unsigned int' from 'long int' may change the sign of the result [-Wsign-conversion] + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/8854199687/job/24316762831#step:3:2020 + + Closes #1379 + +- autotools: use `AM_CFLAGS` + + Use `AM_CFLAGS` to pass custom, per-target C flags. This replaces using + `CFLAGS` which triggered this warning when running `autoreconf -fi`: + ``` + tests/Makefile.am:8: warning: 'CFLAGS' is a user variable, you should not override it; + tests/Makefile.am:8: use 'AM_CFLAGS' instead + ``` + (Only for `tests`, even though `example` and `src` also used this + method. The warning is also missing from curl, that also uses + `CFLAGS`.) + + Follow-up to 3ec53f3ea26f61cbf2e0fbbeccb852fca7f9b156 #1286 + Closes #1378 + +GitHub (25 Apr 2024) +- [Viktor Szakats brought this change] + + ci/GHA: fix gcrypt with autotools/macOS/Homebrew/ARM64 (#1377) + + mbedtls configure fails to detect anything due to this: + ``` + configure:23101: gcc -o conftest -g -O2 -I/opt/homebrew/include conftest.c -lmbedcrypto -lz >&5 + ld: library 'mbedcrypto' not found + clang: error: linker command failed with exit code 1 (use -v to see invocation) + ``` + +Viktor Szakats (25 Apr 2024) +- autotools: delete bogus square bracket from help text [ci skip] + + Follow-up to 3f98bfb0900b5e68445a339cfebc60b307a24650 #1368 + +GitHub (25 Apr 2024) +- [Viktor Szakats brought this change] + + ci/GHA: fix verbose option for autotools jobs (#1376) + + Also enable verbose for macOS `make` step. + +- [Viktor Szakats brought this change] + + ci/GHA: dump `config.log` on failure for macOS autotools jobs (#1375) + +- [Viktor Szakats brought this change] + + ci/GHA: fix `autoreconf` failure on macOS/Homebrew (#1374) + + By manually installing `libtool`. + + ``` + autoreconf -fi + shell: /bin/bash -e {0} + configure.ac:75: error: possibly undefined macro: AC_LIBTOOL_WIN32_DLL + If this token and others are legitimate, please use m4_pattern_allow. + See the Autoconf documentation. + configure.ac:76: error: possibly undefined macro: AC_PROG_LIBTOOL + autoreconf: error: /opt/homebrew/Cellar/autoconf/2.72/bin/autoconf failed with exit status: 1 + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/8833608758/job/24253334557#step:4:1 + +- [Viktor Szakats brought this change] + + ci/GHA: fixup Homebrew location (for ARM runners) (#1373) + + GHA macOS runners became ARM64 machines. Make the Homebrew prefix + dynamic to adapt to these installations. + +Viktor Szakats (14 Apr 2024) +- RELEASE-NOTES: sync [ci skip] + +- [Patrick Monnerat brought this change] + + os400: Add two recent files to the distribution + + Closes #1364 + +- wincng: add to ci/GHA, add `./configure` option `--enable-ecdsa-wincng` + + - add `./configure` option `--enable-ecdsa-wincng` + + - add WinCNG autotools jobs to GHA. + + - enable WinCNG ECDSA in some GHA jobs (both CMake and autotools). + + Follow-up to 3e72343737e5b17ac98236c03d5591d429b119ae #1315 + Closes #1368 + +GitHub (14 Apr 2024) +- [Johannes Passing brought this change] + + wincng: add ECDSA support for host and user authentication (#1315) + + The WinCNG backend currently only supports DSA and RSA. This PR + adds ECDSA support for host and user authentication. + + * Disable WinCNG ECDSA support by default to maintain backward + compatibility for projects that target versions below Windows 10. + + * Add cmake option `ENABLE_ECDSA_WINCNG` to guard ECDSA support. + + * Update AppVeyor job matrix to only enable ECDSA on Server 2016+ + +Viktor Szakats (14 Apr 2024) +- ci: enable Unity mode for most CMake builds + + Ref: 7129ea9ca8cca86dac80a6bac2d63937987efe9d #1034 + Closes #1367 + +- os400: fix shellcheck warnings in scripts (fixups) + + - Build scripts must be executed by the os/400 shell (sh), not bash which + is a PASE program: The `-ot` non-POSIX test extension works in os/400 as + well. Ref: https://github.com/libssh2/libssh2/pull/1364#issue-2241646754 + + - Drop/fixup mods trying to make some syntax highlighters happier. + + Follow-up to c6625707b94d9093f38f1a0a4d89c11b64f12ba8 #1358 + Assisted-by: Patrick Monnerat + Closes #1364 + Closes #1366 + +- cmake: style tidy-up (more) + + Follow-up to 3fa5282d6284efba62dc591697e6a687152bdcb1 #1166 + Closes #1365 + +- RELEASE-NOTES: sync [ci skip] + +- os400: fix shellcheck warnings in scripts + + - use `$()` instead of backticks, and re-arrange double-quotes inside. + - add missing `|| exit 1` to `cd` calls. (could be dropped by using `set -eu`.) + - add `-n` to a few `if`s. + - shorten redirections by using `{} >` (as shellcheck recommended). + - silence warnings where variables were detected as unused (SC2034). + - a couple misc updates to silence warnings. + - switch to bash shebang for `-ot` feature. + - split two lines to unbreak syntax highlighting in my editor. (`$(expr \`, `$(dirname \`) + + Also enable CI checks for OS/400 shell scripts. + + Ref: d88b9bcdafe9d19aad2fb120d0a0acb3edab64f7 + Closes #1358 + +- RELEASE-NOTES: sync [ci skip] + +- ci: add shellcheck job and script + + Add FIXME for OS/400 scripts. + + Cherry-picked from #1358 + +- tests: fix shellcheck issues in `test_sshd.test` + + Cherry-picked from #1358 + +- RELEASE-NOTES: sync [ci skip] + +GitHub (9 Apr 2024) +- [Viktor Szakats brought this change] + + ci/appveyor: re-enable OpenSSL 3, also bump to 3.2.1 (#1363) + + Ref: 104744f4a523de574ce3767c50948d9b8385be4c #1348 + +Viktor Szakats (9 Apr 2024) +- ci: use a better test timestamp [ci skip] + + Mar 27 2024 08:00:00 GMT+0000 + + Follow-up to 2d765e454d98b794a5e5bbc497b1fcba4a9b8c4b #1360 + +GitHub (9 Apr 2024) +- [Viktor Szakats brought this change] + + ci: verify build and install from tarball (#1362) + + Install verification based on: + https://github.com/curl/curl/blob/28c5ddf13ac311d10bc4e8f9fc4ce0858a19b888/scripts/installcheck.sh + +Viktor Szakats (9 Apr 2024) +- tidy-up: dir names, command-line [ci skip] + + Follow-up to 2d765e454d98b794a5e5bbc497b1fcba4a9b8c4b #1360 + +- cmake: tidy up function name casing in `CopyRuntimeDependencies.cmake` + + Use lowercase to match callers. + +GitHub (9 Apr 2024) +- [Viktor Szakats brought this change] + + ci: add reproducibility test for `maketgz` (#1360) + +Viktor Szakats (9 Apr 2024) +- maketgz: add reproducible dir entries to tarballs + + In the initial implementation of reproducible tarballs, they were + missing directory entries, while .zip archives had them. It meant + that on extracting the tarball, on-disk directory entries got the + current timestamp. + + This patch fixes this by including directory entries in the tarball, + with reproducible timestamps. It also moves sorting inside tar, + to ensure reproducible directory entry timestamps on extract + (without the need of `--delay-directory-restore` option, when + extracting with GNU tar. BSD tar got that right by default.) + + GNU tar 1.28 (2014-07-28) introduced `--sort=`. + + Follow-up to d52fe1b4358fab891037d86b5c73c098079567db #1357 + Closes #1359 + +- ci/GHA: improve version number in `maketgz` test + + Follow-up to cba7f97506c1b8e5ff131bbbc57b5796ac634c56 #1353 + +GitHub (8 Apr 2024) +- [Michael Buckley brought this change] + + src: check the return value from `_libssh2_bn_*()` functions (#1354) + + Found by oss-fuzz. In `diffie_hellman_sha_algo()`, we were calling + `_libssh2_bn_from_bin()` with data recieved by the server without + checking whether that data was zero-length or ridiculously long. + In the OpenSSL backend, this would cause `_libssh2_bn_from_bin()` + to fail an allocation, which would eventually lead to a NULL + dereference when the bignum was used. + + Add the same check for `_libssh2_bn_set_word()` and + `_libssh2_bn_to_bin()`. + +Viktor Szakats (8 Apr 2024) +- maketgz: reproducible tarballs/zip, display tarball hashes + + - support `SOURCE_DATE_EPOCH` for reproducibility. + - make tarballs reproducible. + - make file timestamps in tarball/zip reproducible. + - make directory timestamps in zip reproducible. + - make timestamps of tarballs/zip reproducible. + - make file order in tarball/zip reproducible. + - use POSIX ustar tarball format to avoid supply chain vulnerability: https://seclists.org/oss-sec/2021/q4/0 + - make uid/gid in tarball reproducible. + - omit owner user/group names from tarball for reproducibility and privacy. + - omit current timestamp from .gz header for reproducibility. + - display SHA-256 hashes of produced tarballs/zip. (Requires `sha256sum`) + - re-sync formatting with curl's `maketgz`. + + Closes #1357 + +- maketgz: `set -eu`, reproducibility, improve zip, add CI test + + - set bash `-eu`. + - fix bash `-eu` issues. + - apply `TZ=UTC` and `LC_ALL=C` for reproducibility. + - sort `.zip` entries for reproducibility. + - zip with `--no-extra` for reproducibliity. + - use maximum zip compression. + - add the gpg sign command-line. Copied from curl. + - add CI test for `maketgz`. + + Closes #1353 + +- RELEASE-NOTES: sync and cleanups [ci skip] + +GitHub (3 Apr 2024) +- [Tejaswikandula brought this change] + + Support RSA SHA2 cert-based authentication (rsa-sha2-512_cert and rsa-sha2-256_cert) (#1314) + + Replicating OpenSSH's behavior to handle RSA certificate authentication + differently based on the remote server version. + + 1. For OpenSSH versions >= 7.8, ascertain server's support for RSA Cert + types by checking if the certificate's signature type is present in + the `server-sig-algs`. + + 2. For OpenSSH versions < 7.8, Set the "SSH_BUG_SIGTYPE" flag when the + RSA key in question is a certificate to ignore `server-sig-algs` and + only offer ssh-rsa signature algorithm for RSA certs. + + This arises from the fact that OpenSSH versions up to 7.7 accept + RSA-SHA2 keys but not RSA-SHA2 certificate types. Although OpenSSH <=7.7 + includes RSA-SHA2 keys in the `server-sig-algs`, versions <=7.7 do not + actually support RSA certs. Therefore, server sending RSA-SHA2 keys in + `server-sig-algs` should not be interpreted as indicating support for + RSA-SHA2 certs. So, `server-sig-algs` are ignored when the RSA key in + question is a cert, and the remote server version is 7.7 or below. + + Relevant sections of the OpenSSH source code: + + + + + Assisted-by: Will Cosgrove + Reviewed-by: Viktor Szakats + +Viktor Szakats (3 Apr 2024) +- RELEASE-NOTES: sync [ci skip] + + Also fix to include 3-digit issue/PR references. + +- mbedtls: add workaround + FIXME to build with 3.6.0 + + This is just a stub to make `_libssh2_mbedtls_ecdsa_new_private` + compile. + + mbedtls 3.6.0 silently deleted its public API `mbedtls_pk_load_file`, + which this function relies on. + + Closes #1349 + +GitHub (3 Apr 2024) +- [Viktor Szakats brought this change] + + ci/appveyor: OpenSSL 3 no longer found by CMake, revert to 1.1.1 (#1348) + + Ref: https://github.com/appveyor/build-images/commit/702e8cdca01f28f6a40687783f493c786cebbe2c + Ref: https://github.com/appveyor/build-images/pull/149 + +Viktor Szakats (3 Apr 2024) +- docs: improve `libssh2_userauth_publickey_from*` manpages + + Reported-by: Lyndon Brown + Assisted-by: Ryan Kelley + Fixes #652 + Closes #1308 + Closes #xxxx + +- RELEASE-NOTES: sync [ci skip] + +GitHub (2 Apr 2024) +- [Viktor Szakats brought this change] + + test debian:testing-slim post xz backdoor removal (#1346) + + The unexplained CI fallouts are gone with the latest debian:testing (20240330). + + Ref #1328 #1329 #1338. + Closes #1346 + +Viktor Szakats (30 Mar 2024) +- ci: use Linux runner for BSDs, add arm64 FreeBSD 14 job + + - bump cross-platform-actions to 0.23.0. + Ref: https://github.com/cross-platform-actions/action/releases/tag/v0.23.0 + + - switch to Linux runners (from macOS) for cross-platform-actions. + It's significantly faster. + + - switch back FreeBSD 14 job to cross-platform-actions. + Also switch back to default shell. + + - add FreeBSD 14 arm64 job. + + Closes #1343 + +- ci: use single quotes in yaml [ci skip] + +- ci: tidy-up job order [ci skip] + +- build: drop `-Wformat-nonliteral` warning suppressions + + Also markup a vararg function as such. + + In functions marked up as vararg functions, there is no need to suppress + `-Wformat-nonliteral` warnings. It's done automatically by the compiler. + + Closes #1342 + +- ci: delete flaky FreeBSD 13.2 job + + Keep FreeBSD 14. + +- RELEASE-NOTES: sync [ci skip] + +- example: restore `sys/time.h` for AIX + + In AIX, `time.h` header file doesn't have definitions like + `fd_set`, `struct timeval`, which are found in `sys/time.h`. + + Add `sys/time.h` to files affected when available. + + Regression from e53aae0e16dbf53ddd1a4fcfc50e365a15fcb8b9 #1001. + + Reported-by: shubhamhii on GitHub + Assisted-by: shubhamhii on GitHub + Fixes #1334 + Fixes #1335 + Closes #1340 + +- userauth: avoid oob with huge interactive kbd response + + - If the length of a response is `UINT_MAX - 3` or larger, an unsigned + integer overflow occurs on 64-bit systems. Avoid such truncation to + always allocate enough memory to avoid subsequent out of boundary + writes. + + Patch-by: Tobias Stoeckmann + + - also add FIXME to bump up length field to `size_t` (ABI break) + + Closes #1337 + +GitHub (28 Mar 2024) +- [Josef Cejka brought this change] + + transport: check ETM on remote end when receiving (#1332) + + We should check if encrypt-then-MAC feature is enabled in remote end's + configuration. + + Fixes #1331 + +- [Josef Cejka brought this change] + + kex: always add extension indicators to kex_algorithms (#1327) + + KEX pseudo-methods "ext-info-c" and "kex-strict-c-v00@openssh.com" + are in default kex method list but they were lost after configuring + custom kex method list in libssh2_session_method_pref(). + + Fixes #1326 + +- [Jiwoo Park brought this change] + + cmake: use the imported target of FindOpenSSL module (#1322) + + * Use the imported target of FindOpenSSL module + * Build libssh2 before test runner + * Use find_package() in the CMake config file + * Use find_dependency() rather than find_package() + * Install CMake module files and use them in the config file + * Use elseif() to choose the crypto backend + +- [Andrei Augustin brought this change] + + docs: update INSTALL_AUTOTOOLS (#1316) + + corrected --with-libmbedtls-prefix to current option --with-libmbedcrypto-prefix + +Viktor Szakats (28 Mar 2024) +- ci: don't parallelize `distcheck` job + + A while ago the `distcheck` CI job became flaky. This continued after + switching to Debian stable (from testing). Try stabilzing it by running + it single-threaded. + + Closes #1339 + +- Dockerfile: switch to Debian stable (from testing) + + This fixes flakiness experienced recently with two OpenSSL jobs and one + libgcrypt job, and/or intermittently causing all Docker-based tests to + fail. + + Reported-by: András Fekete + Fixes #1328 + Fixes #1329 + Closes #1338 + +GitHub (22 Feb 2024) +- [Michael Buckley brought this change] + + Supply empty hash functions for mac_method_hmac_aesgcm to avoid a crash when e.g. setting LIBSSH2_METHOD_CRYPT_CS (#1321) + +- [Michael Buckley brought this change] + + gen_publickey_from_dsa: Initialize BIGNUMs to NULL for OpenSSL 3 (#1320) + +Viktor Szakats (23 Jan 2024) +- RELEASE-NOTES: add algo deprecation notices [ci skip] + + Closes #1307 + +- RELEASE-NOTES: sync [ci skip] + +GitHub (22 Jan 2024) +- [Juliusz Sosinowicz brought this change] + + wolfssl: enable debug logging in wolfSSL when compiled in (#1310) + + Co-authored-by: Viktor Szakats + +- [monnerat brought this change] + + os400: maintain up to date (#1309) + + - Handle MD5 conditionals in os400qc3. + - Check for errors in os400qc3 pbkdf1. + - Implement an optional build options override file. + - Sync ILE/RPG copy files with current C header files. + - Allow a null session within a string conversion cache. + - Add an ILE/RPG example. + - Adjust outdated copyrights in changed files. + +Viktor Szakats (18 Jan 2024) +- RELEASE-NOTES: sync + +- src: check hash update/final success + + Also: + - delete unused internal macro `libssh2_md5()` where defined. + - prefix `libssh2_os400qc3_hash*()` function names with underscore. + These are public/visible, but internal. + - add FIXMEs to OS/400 code to verify update/final calls; some OS API, + some internal. + + Ref: https://github.com/libssh2/libssh2/pull/1301#discussion_r1446861650 + Reviewed-by: Michael Buckley + Reviewed-by: Patrick Monnerat + Closes #1303 + +- RELEASE-NOTES: sync [ci skip] + +GitHub (18 Jan 2024) +- [Ryan Kelley brought this change] + + openssl: fix cppcheck found NULL dereferences (#1304) + + * Fix NULL dereference in gen_publickey_from_rsa_evp and + gen_publickey_from_dsa_evp. + * Add checks for en_publickey_from_ec_evp and en_publickey_from_ed_evp + +Viktor Szakats (12 Jan 2024) +- openssl: delete internal `read_openssh_private_key_from_memory()` + + It was wrapping another internal function with no added logic. + + Closes #1306 + +- openssl: formatting/whitespace + + Also use `NULL` instead of `0` for pointers. + + Closes #1305 + +- HACKING-CRYPTO: more fixups [ci skip] + + Follow-up to f64885b6ab9bbdae2da9ebd70f4dd5cea56e838a #1297 + +- HACKING-CRYPTO: fixups [ci skip] + + Follow-up to f64885b6ab9bbdae2da9ebd70f4dd5cea56e838a #1297 + +- RELEASE-NOTES: sync [ci skip] + +- src: check hash init success + + Before this patch, SHA2 and SHA1 init function results were cast to + `void`. This patch makes sure to verify these values. + + Also: + - exclude an `assert(0)` from release builds in `_libssh2_sha_algo_ctx_init()`. + (return error instead) + - fix indentation / whitespace + + Reviewed-by: Michael Buckley + Closes #1301 + +- mac: handle low-level errors + + - update low-level hmac functions from macros to functions. + - libgcrypt: propagate low-level hmac errors. + - libgcrypt: add error checks for hmac calls. + - os400qc3: add error checks, propagate them. + Assisted-by: Patrick Monnerat + - mbedtls: fix propagating low-level hmac errors. + - wincng: fix propagating low-level hmac errors. + - mac: verify success of low-level hmac functions. + - knownhost: verify success of low-level hmac functions. + - transport: verify success of MAC hash call. + - minor type cleanup in wincng. + - delete unused ripemd wrapper in wincng. + - delete unused SHA384 wrapper in mbedtls. + + Reported-by: Paul Howarth + Reviewed-by: Michael Buckley + Closes #1297 + +GitHub (8 Jan 2024) +- [Michael Buckley brought this change] + + Fix an out-of-bounds read in _libssh2_kex_agree_instr when searching for a KEX not in the server list (#1302) + +Viktor Szakats (21 Dec 2023) +- RELEASE-NOTES: sync [ci skip] + +- ci/appveyor: re-enable parallel mode + + The comment cited earlier is no longer true with recent CMake versions. + This options does actually enable parallel builds with MSVC since CMake + v3.26.0: https://gitlab.kitware.com/cmake/cmake/-/issues/20564 + + The effect isn't much for libssh2, because it spends most time in tests, + but let's enable it anyway for efficiency. + + Ref: 0d08974633cfc02641e6593db8d569ddb3644255 #884 + Ref: 7a039d9a7a2945c10b4622f38eeed21ba6b4ec55 #867 + + Closes #1294 + +- ci/gha: review/fixup auto-cancel settings + + - use the group expression from `reuse.yml` (via curl). + - add auto-cancel for `ci` and `cifuzz`. + - add auto-cancel to `appveyor_docker`. I'm just guessing here. + The hope is that it fixes AppVeyor CI runs when re-pushing a PR. + This frequently caused the freshly pushed session to fail waiting for + a connection. + - sync group expression in `appveyor_status` with `reuse`. + + Closes #1292 + +- RELEASE-NOTES: fix casing in GitHub names [ci skip] + +- RELEASE-NOTES: synced [ci skip] + + Closes #1279 + +- [Michael Buckley brought this change] + + src: add 'strict KEX' to fix CVE-2023-48795 "Terrapin Attack" + + Refs: + https://terrapin-attack.com/ + https://seclists.org/oss-sec/2023/q4/292 + https://osv.dev/list?ecosystem=&q=CVE-2023-48795 + https://github.com/advisories/GHSA-45x7-px36-x8w8 + https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-48795 + + Fixes #1290 + Closes #1291 + +- session: add `libssh2_session_callback_set2()` + + Add new `libssh2_session_callback_set2()` API that deprecates + `libssh2_session_callback_set()`. + + The new implementation offers the same functionality, but accepts and + returns a generic function pointer (of type `libssh2_cb_generic *`), as + opposed to the old function that used data pointers (`void *`). The new + solution thus avoids data to function (and vice versa) pointer + conversions, which has undefined behaviour in standard C. + + About the name: It seems the `*2` suffix was used in the past for + replacement functions for deprecated ones. Let's stick with that. + `*_ex` was preferred for new functions that extend existing ones with + new features. + + Closes #1285 + +- build: enable `-pedantic-errors` + + According to the manual, this isn't the same as `-Werror -pedantic`. + Enable it together with `-Werror`. + + https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-pedantic-errors-1 + + This option results in autotools feature detection going into crazies. + To avoid this, we add it to `CFLAGS` late. Idea copied from curl. + + This option has an effect only with gcc 5.0 and newer as of this commit. + Let's enable it for clang and older versions too for simplicity. Ref: + https://github.com/curl/curl/commit/d5c0351055d5709da8f3e16c91348092fdb481aa + https://github.com/curl/curl/pull/2747 + + Closes #1286 + +- build: add mingw-w64 support to `LIBSSH2_PRINTF()` attribute + + And fix the warning it detected. + + Closes #1287 + +- libssh2.h: add deprecated function warnings + + With deprecated-at versions and suggested replacement function. + + It's possible to silence them by defining `LIBSSH2_DISABLE_DEPRECATION`. + + Also add depcreated-at versions to documentation, and unify wording. + + Ref: https://github.com/libssh2/libssh2/pull/1260#issuecomment-1837017987 + Closes #1289 + +- ci/spellcheck: delete redundant option [ci skip] + + `--check-hidden` not necessary when passing filenames explicitly. + + Follow-up to a79218d3a058a333bb9de14079548a3511679a04 + +- tidy-up: add empty line for clarity [ci skip] + +- build: FIXME `-Wsign-conversion` to be errors [ci skip] + +- src: disable `-Wsign-conversion` warnings, add option to re-enable + + To avoid the log noise till we fix those ~360 compiler warnings. + + Also add macro `LIBSSH2_WARN_SIGN_CONVERSION` to re-enable them. + + Follow-up to afa6b865604019ab27ec033294edfe3ded9ae0c0 #1257 + + Closes #1284 + +- cmake: fix indentation [ci skip] + +- example, tests: call `WSACleanup()` for each `WSAStartup()` + + On Windows. + + Closes #1283 + +- RELEASE-NOTES: update credits [ci skip] + + Ref: https://github.com/libssh2/libssh2/pull/1241#issuecomment-1830118584 + +- RELEASE-NOTES: avoid splitting names, fix typo, refine order [ci skip] + +- RELEASE-NOTES: synced [ci skip] + +- add portable `LIBSSH2_SOCKET_CLOSE()` macro + + Add `LIBSSH2_SOCKET_CLOSE()` to the public `libssh2.h` header, for user + code. It translates to `closesocket()` on Windows and `close()` on other + platforms. + + Use it in example code. + + It makes them more readable by reducing the number of `_WIN32` guards. + + Closes #1278 + +- ci: add FreeBSD 14 job, fix issues + + - install bash to fix error when running tests: + ``` + ERROR: test_sshd.test - missing test plan + ERROR: test_sshd.test - exited with status 127 (command not found?) + ===================================== + [...] + # TOTAL: 4 + # PASS: 2 + # SKIP: 0 + # XFAIL: 0 + # FAIL: 0 + # XPASS: 0 + # ERROR: 2 + [...] + env: bash: No such file or directory + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/7133852508/job/19427420687#step:3:3998 + + - fix sshd issue when running tests: + ``` + # sshd log: + # Server listening on :: port 4711. + # Server listening on 0.0.0.0 port 4711. + # Authentication refused: bad ownership or modes for file /home/runner/work/libssh2/libssh2/tests/key_rsa.pub + # Authentication refused: bad ownership or modes for file /home/runner/work/libssh2/libssh2/tests/openssh_server/authorized_keys + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/7134629175/job/19429828342#step:3:4059 + + Cherry-picked from #1277 + Closes #1277 + +- ci: add OmniOS job, fix issues + + - use GNU Make, to avoid errors: + ``` + make: Fatal error in reader: Makefile, line 983: Badly formed macro assignment + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/7134629175/job/19429838379#step:3:1956 + + Caused by `?=` in `Makefile.am`. Fix it just in case. + + ``` + make: Fatal error in reader: Makefile, line 438: Unexpected end of line seen + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/7135524843/job/19432451767#step:3:1966 + + It's around line 43 in `Makefile.am`, reason undiscovered. + + - fix error: + ``` + ../../src/hostkey.c:1227:44: error: pointer targets in passing argument 5 of '_libssh2_ed25519_sign' differ in signedness [-Werror=pointer-sign] + 1227 | datavec[0].iov_base, datavec[0].iov_len); + | ~~~~~~~~~~^~~~~~~~~ + | | + | caddr_t {aka char *} + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/7135102832/job/19431233967#step:3:2225 + + https://docs.oracle.com/cd/E36784_01/html/E36887/iovec-9s.html + + - FIXME: new `-Wsign-conversion` warnings appeared in examples: + ``` + ../../example/direct_tcpip.c:251:9: warning: conversion to 'long unsigned int' from 'libssh2_socket_t' {aka 'int'} may change the sign of the result [-Wsign-conversion] + 251 | FD_SET(forwardsock, &fds); + | ^~~~~~ + ../../example/direct_tcpip.c:251:9: warning: conversion to 'long unsigned int' from 'libssh2_socket_t' {aka 'int'} may change the sign of the result [-Wsign-conversion] + ../../example/direct_tcpip.c:251:9: warning: conversion to 'long unsigned int' from 'long int' may change the sign of the result [-Wsign-conversion] + ../../example/direct_tcpip.c:251:9: warning: conversion to 'long int' from 'long unsigned int' may change the sign of the result [-Wsign-conversion] + ../../example/direct_tcpip.c:259:18: warning: conversion to 'long unsigned int' from 'libssh2_socket_t' {aka 'int'} may change the sign of the result [-Wsign-conversion] + 259 | if(rc && FD_ISSET(forwardsock, &fds)) { + | ^~~~~~~~ + ../../example/direct_tcpip.c:259:18: warning: conversion to 'long unsigned int' from 'libssh2_socket_t' {aka 'int'} may change the sign of the result [-Wsign-conversion] + ../../example/direct_tcpip.c:259:18: warning: conversion to 'long unsigned int' from 'long int' may change the sign of the result [-Wsign-conversion] + [...] + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/7136086865/job/19433997429#step:3:3450 + + Cherry-picked from #1277 + +- example: use `libssh2_socket_t` in X11 example + + Cherry-picked from #1277 + +- [Aaron Stone brought this change] + + Handle EINTR from send/recv/poll/select to try again as the error is not fatal + + Integration-patches-by: Viktor Szakats + Fixes #955 + Closes #1058 + +- appveyor: delete UWP job broken since Visual Studio upgrade + + Few days ago UWP job started permafailing. + + fail: https://ci.appveyor.com/project/libssh2org/libssh2/builds/48678129/job/yb8n2pox8mfjwv6m + good: https://ci.appveyor.com/project/libssh2org/libssh2/builds/48673013 + + Other projects also affected: + https://ci.appveyor.com/project/c-ares/c-ares/builds/48687390/job/l0fo4b0sijvqkw9r + + No related local update. Same CMake version. Same CI image. + + This seems to be the culprit, which could mean that this update broke + CMake detection, needs a different CMake configuration on our end, or + that this MSVC update pulled support for UWP apps: + + fail: -- The C compiler identification is MSVC 19.38.33130.0 (~ Visual Studio 2022 v17.8) + good: -- The C compiler identification is MSVC 19.37.32825.0 (~ Visual Studio 2022 v17.7) + + If this is v17.8, release notes don't readily suggest a feature removal: + https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.8 + + So it might just be UWP accidentally broken in this release. + + Closes #1275 + +- checksrc: sync with curl + + Closes #1272 + +- autotools: delete `--disable-tests` option, fix CI tests + + Originally added to improve build performance by skipping building + tests. But, there seems to be no point in this, because autotools + doesn't build tests by default, unless explicitly invoking + `make check`. + + Delete this option from Cygwin and FreeBSD CI tests, where it caused + `make check` to do nothing. Tests are built now, and runtime tests are + too, where supported. + + Also disable Docker-based tests for these, and add a missing `make -j3` + for FreeBSD. + + Reverts 7483edfada1f7e17cf8f9ac1c87ffa3d814c987e #715 + + Closes #1271 + +GitHub (6 Dec 2023) +- [ren mingshuai brought this change] + + build: add `LIBSSH2_NO_DEPRECATED` option (#1266) + + The following APIs have been deprecated for over 10 years and + use `LIBSSH2_NO_DEPRECATED` to mark them as deprecated: + + libssh2_session_startup() + libssh2_banner_set() + libssh2_channel_receive_window_adjust() + libssh2_channel_handle_extended_data() + libssh2_scp_recv() + + Add these options to disable them: + - autotools: `--disable-deprecated` + - cmake: `-DLIBSSH2_NO_DEPRECATED=ON` + - `CPPFLAGS`: `-DLIBSSH2_NO_DEPRECATED` + + Fixes #1259 + Replaces #1260 + Co-authored-by: Viktor Szakats + Closes #1267 + +Viktor Szakats (5 Dec 2023) +- autotools: show the default for `hidden-symbols` option + + Closes #1269 + +- tidy-up: bump casts from int to long for large C99 types in printfs + + Cast large integer types to avoid dealing with printf masks for + `size_t` and other C99 types. Some of existing code used `int` + for this, bump them to `long`. + + Ref: afa6b865604019ab27ec033294edfe3ded9ae0c0 #1257 + + Closes #1264 + +- build: enable missing OpenSSF-recommended warnings, with fixes + + Ref: + https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html + (2023-11-29) + + Enable new warnings: + + - replace `-Wno-sign-conversion` with `-Wsign-conversion`. + + Fix them in example, tests and wincng. There remain about 360 of these + warnings in `src`. Add a TODO item for those and disable `-Werror` for + this particular warning. + + - enable `-Wformat=2` for clang (in both cmake and autotools). + + - enable `__attribute__((format))` for `_libssh2_debug()`, + `_libssh2_snprintf()` and in tests for `run_command()`. + + `LIBSSH2_PRINTF()` copied from `CURL_TEMP_PRINTF()` in curl. + + - enable `-Wimplicit-fallthrough`. + + - enable `-Wtrampolines`. + + Fix them: + + - src: replace obsolete fall-through-comments with + `__attribute__((fallthrough))`. + + - wincng: fix `-Wsign-conversion` warnings. + + - tests: fix `-Wsign-conversion` warnings. + + - example: fix `-Wsign-conversion` warnings. + + - src: fix `-Wformat` issues in trace calls. + + Also, where necessary fix `int` and `unsigned char` casts to + `unsigned int` and adjust printf format strings. These were not + causing compiler warnings. + + Cast large types to `long` to avoid dealing with printf masks for + `size_t` and other C99 types. Existing code often used `int` for this. + I'll update them to `long` in an upcoming commit. + + - tests: fix `-Wformat` warning. + + - silence `-Wformat-nonliteral` warnings. + + - mbedtls: silence `-Wsign-conversion`/`-Warith-conversion` + in external header. + + Closes #1257 + +- packet: whitespace fix + + Tested via #1257 + +- tidy-up: unsigned -> unsigned int + + In the `interval` argument of public `libssh2_keepalive_config()`. + + Tested via #1257 + +- tests: sync port number type with the rest of codebase + + Tested via #1257 + +- autotools: enable `-Wunused-macros` with gcc + + It works with gcc without the libtool warnings seen with clang + on Windows in 96682bd5e14c20828e18bf10ed5b4b5c7543924a #1227. + + Sync usage of of this macro with CMake and + autotools + clang + non-Windows. Making it enabled everywhere except + autotools + clang + Windows due to the libtool stub issue. + + Follow-up to 7ecc309cd10454c54814b478c4f85d0041da6721 #1224 + + Closes #1262 + +- TODO: disable or drop weak algos [ci skip] + + Closes #1261 + +- example, tests: fix/silence `-Wformat-truncation=2` gcc warnings + + Then sync this warning option with curl. + + Seems like a false positive and/or couldn't figure how to fix it, so silence: + ``` + example/ssh2.c:227:38: error: '%s' directive output may be truncated writing likely 1 or more bytes into a region of size 0 [-Werror=format-truncation=] + 227 | snprintf(fn1, fn1sz, "%s/%s", h, pubkey); + | ^~ + example/ssh2.c:227:34: note: assuming directive output of 1 byte + 227 | snprintf(fn1, fn1sz, "%s/%s", h, pubkey); + | ^~~~~~~ + example/ssh2.c:227:13: note: 'snprintf' output 3 or more bytes (assuming 4) into a destination of size 2 + 227 | snprintf(fn1, fn1sz, "%s/%s", h, pubkey); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + example/ssh2.c:228:38: error: '%s' directive output may be truncated writing likely 1 or more bytes into a region of size 0 [-Werror=format-truncation=] + 228 | snprintf(fn2, fn2sz, "%s/%s", h, privkey); + | ^~ + example/ssh2.c:228:34: note: assuming directive output of 1 byte + 228 | snprintf(fn2, fn2sz, "%s/%s", h, privkey); + | ^~~~~~~ + example/ssh2.c:228:13: note: 'snprintf' output 3 or more bytes (assuming 4) into a destination of size 2 + 228 | snprintf(fn2, fn2sz, "%s/%s", h, privkey); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/7055480458/job/19205970397#step:10:98 + + Fix: + ``` + tests/openssh_fixture.c:116:38: error: ' 2>&1' directive output may be truncated writing 5 bytes into a region of size between 1 and 1024 [-Werror=format-truncation=] + tests/openssh_fixture.c:116:11: note: 'snprintf' output between 6 and 1029 bytes into a destination of size 1024 + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/7055480458/job/19205969221#step:10:51 + + Tested via #1257 + +- example: fix indentation follow-up + + Fix long line and fix more indentations. + + Follow-up to 9e896e1b80911a53d6aabb322e034e6ca51b6898 + +- example: fix indentation + + Tested via #1257 + +- autotools: fix missed `-pedantic` and `-Wall` options for gcc + + Follow-up to 5996fefe2bad80cfba85b2569ce6ab6ef575142c #1223 + + Tested via #1257 + +- ci: show compiler in cross/cygwin job names + + Tested via #1257 + +- mbedtls: further improve disabling `-Wredundant-decls` + + Move warning option suppression to `src/mbedtls.h` to surround the actual + external header #includes that need it. + + Follow-up to ecec68a2c13a9c63fe8c2dc457ae785a513e157c #1226 + Follow-up to 7ecc309cd10454c54814b478c4f85d0041da6721 #1224 + + Tested via #1257 + +GitHub (1 Dec 2023) +- [ren mingshuai brought this change] + + example: replace remaining libssh2_scp_recv with libssh2_scp_recv2 in output messages (#1258) + + libssh2_scp_recv is deprecated and has been replaced by libssh2_scp_recv2 + in prior commit. + + Follow-up to 6c84a426beb494980579e5c1d244ea54d3fc1a3f + +Viktor Szakats (27 Nov 2023) +- openssl: use OpenSSL 3 HMAC API, add `no-deprecated` CI job + + - use OpenSSL 3 API when available for HMAC. + This fixes building with OpenSSL 3 `no-deprecated` builds. + + - ensure we support pure OpenSSL 3 API by adding a CI job using + OpenSSL 3 custom-built with `no-deprecated`. + + Follow-up to b0ab005fe79260e6e9fe08f8d73b58dd4856943d #1207 + + Fixes #1235 + Closes #1243 + +- ci: restore lost comment for FreeBSD [ci skip] + + Follow-up to eee4e8055ab375c9f9061d4feb39086737f41a9c + +- ci: add OpenBSD (v7.4) job + fix build error in example + + - Use CMake, LibreSSL and clang from the base install. + + - This uncovered a build error in `example/subsystem_netconf.c`, caused + by using the `%n` printf mask. This is a security risk and some + systems (notably OpenBSD) disable this feature. + + Fix it by applying this patch from OpenBSD ports (from 2021-09-11): + https://cvsweb.openbsd.org/ports/security/libssh2/patches/patch-example_subsystem_netconf_c?rev=1.1&content-type=text/x-cvsweb-markup + https://github.com/openbsd/ports/commit/2c5b2f3e94381914a3e8ade960ce8c997ca9d6d7 + "The old code is also broken, as it passes a pointer to a variable + of a different size (on LP64). There is no check for truncation, + but buf[] is 1MB in size." + Patch-by: naddy + + ``` + /home/runner/work/libssh2/libssh2/example/subsystem_netconf.c:252:17: error: '%n' format specifier support is deactivated and will call abort(3) [-Werror] + "]]>]]>\n%n", (int *)&len); + ~^ + /home/runner/work/libssh2/libssh2/example/subsystem_netconf.c:270:17: error: '%n' format specifier support is deactivated and will call abort(3) [-Werror] + "]]>]]>\n%n", (int *)&len); + ~^ + 2 errors generated. + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/6991449778/job/19022024280#step:3:420 + + Also made tests with arm64, but it takes consistently almost 14m to + finish the job, vs. 2-3m for the native amd64: + https://github.com/libssh2/libssh2/actions/runs/6991648984/job/19022440525 + https://github.com/libssh2/libssh2/actions/runs/6991551220/job/19022233651 + + Cherry-picked from #1250 + Closes #1250 + +- ci: add NetBSD (v9.3) job + + Use CMake, OpenSSL (v1.1) and clang from the base install. + + Cherry-picked from #1250 + +- ci: update and speed up FreeBSD job + + - switch to an alternate GitHub action. This one seems (more) actively + maintained, and runs faster: + https://github.com/cross-platform-actions/action + + - use clang instead of gcc. clang is already present in the base + install, saving install time and bandwidth. + + - stop installing `openssl-quictls` and use the OpenSSL (v1.1) from + the base system. + (I'm suspecting that quictls before this patch wasn't detected by + the build.) + https://wiki.freebsd.org/OpenSSL + + Cherry-picked from #1250 + +- stop using leading underscores in macro names + + Underscored macros are reserved for the compiler / standard lib / etc. + Stop using them in user code. + + We used them as header guards in `src` and in `__FILESIZE` in `example`. + + Closes #1248 + +- ci: use absolute path in `CMAKE_INSTALL_PREFIX` + + To make the installed locations unambiguous in the build logs. + + Closes #1247 + +- openssl: make a function static, add `#ifdef` comments + + Follow-up to 03092292597ac601c3f9f0c267ecb145dda75e4e #248 + where the function was added. + + Also add comments to make `#ifdef` branches easier to follow in + `openssl.h`. + + Closes #1246 + +- ci: boost mbedTLS build speed + + Build times down to 4 seconds (from 18-20). + + Closes #1245 + +- openssl: fix DSA code to use OpenSSL 3 API + + - fix missing `DSA` type when building for OpenSSL 3 `no-deprecated`. + - fix fallouts after fixing the above by switching away from `DSA` + with OpenSSL 3. + + Follow-up to b0ab005fe79260e6e9fe08f8d73b58dd4856943d #1207 + + Closes #1244 + +- openssl: formatting (delete empty lines) [ci skip] + +- tests: fall back to `$LOGNAME` for username + + If the `$USER` variable is empty, fall back to using `$LOGNAME` to + retrieve the logged-in username. + + In POSIX, `$LOGNAME` is a mandatory variable, while `$USER` isn't, and + on some systems it may not be set. Without this value, tests were unable + to provide the correct username when logging into the SSH server running + under the active user's session. + + Reported-by: Nicolas Mora + Suggested-by: Nicolas Mora + Ref: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1056348 + Fixes #1240 + Closes #1241 + +- libssh2.h: use `_WIN32` for Windows detection instead of rolling our own + + Sync up `libssh2.h` Windows detection with the libssh2 source code. + + `libssh2.h` was using `WIN32` and `LIBSSH2_WIN32` for Windows detection, + next to the official `_WIN32`. After this patch it only uses `_WIN32` + for this. Also, make it stop defining `LIBSSH2_WIN32`. + + There is a slight chance these break compatibility with Windows + compilers that fail to define `_WIN32`. I'm not aware of any obsolete + or modern compiler affected, but in case there is one, one possible + solution is to define this macro manually. + + Closes #1238 + +- openssl: fix `EC_KEY` reference with OpenSSL 3 `no-deprecated` build + + Fixes: + ``` + src/openssl.c:650:5: error: use of undeclared identifier 'EC_KEY' + EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve); + ^ + src/openssl.c:650:13: error: use of undeclared identifier 'ec_key' + EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve); + ^ + src/openssl.c:650:22: error: implicit declaration of function 'EC_KEY_new_by_curve_name' is invalid in C99 [-Werror,-Wimplicit-function-declaration] + EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve); + ^ + src/openssl.c:650:22: note: did you mean 'EC_GROUP_new_by_curve_name'? + ./quictls/_a64-mac-sys/usr/include/openssl/ec.h:483:11: note: 'EC_GROUP_new_by_curve_name' declared here + EC_GROUP *EC_GROUP_new_by_curve_name(int nid); + ^ + In file included from ./_a64-mac-sys-bld/src/CMakeFiles/libssh2_static.dir/Unity/unity_0_c.c:19: + In file included from src/crypto.c:10: + src/openssl.c:652:8: error: use of undeclared identifier 'ec_key' + if(ec_key) { + ^ + ``` + Ref: https://github.com/curl/curl-for-win/actions/runs/6950001225/job/18909297867#step:3:4341 + + Follow-up to b0ab005fe79260e6e9fe08f8d73b58dd4856943d #1207 + + Bug #1235 + Closes #1236 + +- openssl: formatting + + Sync up these lines with the other two similar occurrences in the code. + + Cherry-picked from #1236 + +GitHub (21 Nov 2023) +- [Michael Buckley brought this change] + + openssl: use non-deprecated APIs with OpenSSL 3.x (#1207) + + Assisted-by: Viktor Szakats + +Viktor Szakats (21 Nov 2023) +- ci: add BoringSSL job (cmake, gcc, amd64) + + Closes #1233 + +- autotools: fix dotless gcc and Apple clang version detections + + - fix parsing dotless (major-only) gcc versions. + Follow-up to 00a3b88c51cdb407fbbb347a2e38c5c7d89875ad #1187 + + - sync gcc detection variable names with curl. + + - fix Apple clang version detection for releases between + 'Apple LLVM version 7.3.0' and 'Apple LLVM version 10.0.1' where the + version was under-detected as 3.7 llvm/clang equivalent. + + - fix Apple clang version detection for 'Apple clang version 11.0.0' + and newer where the Apple clang version was detected, instead of its + llvm/clang equivalent. + + - revert to show `clang` instead of `Apple clang`, because we follow it + with an llvm/clang version number. (Apple-ness still visible in raw + version.) + + Used this collection for Apple clang / llvm/clang translation and test + inputs: https://gist.github.com/yamaya/2924292 + + Closes #1232 + +- acinclude.m4: revert accidental edit [ci skip] + + Follow-up to 8c320a93a48775b74f40415e46f84bf68b4d5ae8 + +- autotools: show more clang/gcc version details + + Also: + - show if we detected Apple clang. + - delete duplicate version detection for clang. + + Closes #1230 + +- acinclude.m4: re-sync with curl [ci skip] + +- autotools: avoid warnings in libtool stub code + + Seen on Windows with clang64, in libtool-generated stub code for + examples and tests. + + The error didn't break the CI job for some reason. + + msys2 (autotools, clang64, clang-x86_64: + ``` + [...] + 2023-11-17T20:14:17.8639574Z ./.libs/lt-test_read.c:91:10: error: macro is not used [-Werror,-Wunused-macros] + [...] + 2023-11-17T20:14:39.8729255Z ./.libs/lt-sftp_write_nonblock.c:91:10: error: macro is not used [-Werror,-Wunused-macros] + [...] + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/6908585056/job/18798193405?pr=1226#step:8:474 + + Follow-up to 7ecc309cd10454c54814b478c4f85d0041da6721 #1224 + + Closes #1227 + +- mbedtls: improve disabling `-Wredundant-decls` + + Disable these warnings specifically for the mbedTLS public headers + and leave it on for the the rest of the code. This also fixes this + issue for autotools. Previous solution was globally disabling this + warning for the whole code when using mbedTLS and only with CMake. + + Follow-up to 7ecc309cd10454c54814b478c4f85d0041da6721 #1224 + + Closes #1226 + +- cmake: rename picky warnings script + + To match the camel-case style used in other CMake scripts and also + to match the name used in curl. + + Closes #1225 + +- build: enable more compiler warnings and fix them + + Enable more picky compiler warnings. I've found these options in the + nghttp3 project when implementing the CMake quick picky warning + functionality for it. + + Fix issues found along the way: + + - wincng, mbedtls: delete duplicate function declarations. + Most of this was due to re-#defining crypto functions to + crypto-backend specific implementations These redefines also remapped + the declarations in `crypto.h`, making the backend-specific + declarations duplicates. + This patch deletes the backend-specific declarations. + + - wincng mapped two crypto functions to the same local function. + Also causing double declarations. + Fix this by adding two disctinct wrappers and moving + the common function to a static one. + + - delete unreachable `break;` statements. + + - kex: disable macros when unused. + + - agent: disable unused constants. + + - mbedtls: disable double declaration warnings because public mbedTLS + headers trigger it. (with function `psa_set_key_domain_parameters`) + + - crypto.h: formatting. + + Ref: https://github.com/ngtcp2/nghttp3/blob/a70edb08e954d690e8fb2c1df999b5a056f8bf9f/cmake/PickyWarningsC.cmake + + Closes #1224 + +- autotools: sync warning enabler code with curl + + Tiny changes and minor updates to bring this code closer + to curl's `m4/curl-compilers.m4`. + + Closes #1223 + +- acinclude.m4: fix indentation [ci skip] + + Also match indentation of curl's `m4/curl-compilers.m4` for + easier syncing. + +- autotool: rename variable + + `WARN` -> `tmp_CFLAGS` + + To match curl and make syncing this code easier. + + Ref: https://github.com/curl/curl/blob/d1820768cce0e797d1f072343868ce1902170e93/m4/curl-compilers.m4#L479 + + Closes #1222 + +- autotools: picky warning options tidy-up + + - sync clang warning version limits with CMake. + - make `WARN=` vs. `CURL_ADD_COMPILER_WARNINGS()` consistent with curl + and between clang and gcc (`WARN=` is for `no-` options in general). + + Closes #1221 + +- build: picky warning updates + + - cmake, autotools: sync picky gcc warnings with curl. + - cmake, autotools: add `-Wold-style-definition` for clang too. + - cmake, autotools: add comment for `-Wformat-truncation=1`. + - cmake: more precise version info for old clang options. + + Closes #1219 + +- ci: fixup FreeBSD version, bump mbedtls + + We haven't been using the FreeBSD version. Also it turns out, + the single version supported is 13.2 at the moment: + https://github.com/vmactions/freebsd-vm/tree/main/conf + + Stop trying to set the version and instead rely on the action + providing the latest supported one automatically. + + Follow-up to a7d2a573be26238cc2b55e5ff6649bbe620cb8d9 + + Also: + - add more details to the FreeBSD job description. + - bump mbedtls version while here. + + Closes #1217 + +- cmake: fix multiple include of libssh2 package + + Also extend our integration test double inclusion. It will still not + catch this case, because that requires + `cmake_minimum_required(VERSION 3.18)` or higher. + + Fixes: + ``` + CMake Error at .../lib/cmake/libssh2/libssh2-config.cmake:8 (add_library): + add_library cannot create ALIAS target "libssh2::libssh2" because another + target with the same name already exists. + Call Stack (most recent call first): + CMakeLists.txt:24 (find_package) + + CMake Error at .../lib/cmake/libssh2/libssh2-config.cmake:13 (add_library): + add_library cannot create ALIAS target "Libssh2::libssh2" because another + target with the same name already exists. + Call Stack (most recent call first): + CMakeLists.txt:24 (find_package) + ``` + + Test to reproduce: + ```cmake + cmake_minimum_required(VERSION 3.18) # must be 3.18 or higher + + project(test) + + find_package(libssh2 CONFIG) + find_package(libssh2 CONFIG) # fails + + add_executable(test main.c) + target_link_libraries(test libssh2::libssh2) + ``` + + Ref: https://cmake.org/cmake/help/latest/release/3.18.html#other-changes + Ref: https://cmake.org/cmake/help/v3.18/policy/CMP0107.html + + Assisted-by: Kai Pastor + Assisted-by: Harry Mallon + Ref: https://github.com/curl/curl/pull/11913 + + Closes #1216 + +- ci: add FreeBSD 13.2 job + + It runs over Linux via qemu. First two runs were (very) slow, then it + became (much) more performant at just 2x slower than a native Linux + build. Then got slow again, then fast again. Still seems acceptable + for the value this adds. + + The build uses autotools and quictls. + + Successful builds: + 1. https://github.com/libssh2/libssh2/actions/runs/6802676786/job/18496286419 (13m59s, -j3) + 2. https://github.com/libssh2/libssh2/actions/runs/6802976375/job/18497243225 (11m5s, -j2) + 3. https://github.com/libssh2/libssh2/actions/runs/6803142201/job/18497785049 (3m6s, -j1) + 4. https://github.com/libssh2/libssh2/actions/runs/6803194839/job/18497962766 (3m10s, -j2) + 5. https://github.com/libssh2/libssh2/actions/runs/6803267201/job/18498208501 (3m13s) + 6. https://github.com/libssh2/libssh2/actions/runs/6803510333/job/18498993698 (15m25s) + 7. https://github.com/libssh2/libssh2/actions/runs/6813602863/job/18528571057 (3m13s) + + Similar solution exists for Solaris (over macOS via VirtualBox), but it + hangs forever at `Waiting for text: solaris console login`: + https://github.com/libssh2/libssh2/actions/runs/6802388128/job/18495391869#step:4:185 + + Idea taken from LibreSSL. + + FIXME: Unrelated, the `distcheck` job became flaky in recent days: + https://github.com/libssh2/libssh2/actions/runs/6802976375/job/18497256437#step:10:536 + ``` + FAIL: test_auth_pubkey_ok_rsa_aes256gcm + ``` + https://github.com/libssh2/libssh2/actions/runs/6813602863/job/18528588933#step:10:533 + ``` + FAIL: test_read + ``` + + Closes #1215 + +- reuse: fix duplicate copyright warning + + ``` + PendingDeprecationWarning: + Copyright and licensing information for 'tests/openssh_server/Dockerfile' + has been found in both 'tests/openssh_server/Dockerfile' and in the DEP5 + file located at '.reuse/dep5'. The information for these two sources has + been aggregated. In the future this behaviour will change, and you will + need to explicitly enable aggregation. [...] + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/6789274955/job/18456085964#step:4:4 + +- Makefile.mk: delete Windows-focused raw GNU Make build + + We recommend using CMake instead. Especially in unity mode, it's faster + and probably more familiar for most. It's also easily portable. + + (`Makefile.mk` was also portable, but in practice only usable for + Windows. Other platforms required a manual config header.) + + Also: + - migrate `LIBSSH2_NO_*` option CI tests to CMake. + - make MSYS2 CMake builds verbose to show compilation options. + + Closes #1204 + +- tidy-up: around `stdint.h` + + - os400: delete unused `HAVE_STDINT_H`. + + - fuzz: delete redundant `stdint.h` use. + `inttypes.h` is already included via `testinput.h`. + + - docs/TODO: adjust type in planned function. + + Closes #1212 + +- cmake: show crypto backend in feature summary + + This was visible as an enabled package before this patch, but it missed + to show WinCNG. + + Closes #1211 + +- man: fix double spaces and dash escaping + + - `- ` -> `- ` + - `. ` -> `. ` + - `\- ` -> `- ` + - `-1` -> `\-1` + - fold long lines along the way + + This makes the minus sign come out as a Unicode minus sign + (0x2212), and title separator dashes as Unicode hyphen (0x2010), + with `groff -Tutf8` v1.23.0. + + Ref: https://lwn.net/Articles/947941/ + + Closes #1210 + +- src: fix gcc 13 `-Wconversion` warning on Darwin + + ``` + src/session.c: In function 'libssh2_poll': + src/session.c:1776:22: warning: conversion from 'long int' to '__darwin_suseconds_t' {aka 'int'} may change value [-Wconversion] + 1776 | tv.tv_usec = (timeout_remaining % 1000) * 1000; + | ^ + ``` + Ref: https://github.com/curl/curl-for-win/actions/runs/6711735060/job/18239768548#step:3:4368 + + Follow-up to 08354e0abbe86d4cc5088d210d53531be6d8981a + + Closes #1209 + +- openssl: silence `-Wunused-value` warnings + + Seen with gcc 12. + + Manual: https://www.openssl.org/docs/man3.1/man3/BIO_reset.html + + ``` + ./quictls/linux-a64-musl/usr/include/openssl/bio.h:555:34: warning: value computed is not used [-Wunused-value] + 555 | # define BIO_reset(b) (int)BIO_ctrl(b,BIO_CTRL_RESET,0,NULL) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ./libssh2/src/openssl.c:3518:5: note: in expansion of macro 'BIO_reset' + ./libssh2/src/openssl.c:3884:5: note: in expansion of macro 'BIO_reset' + ./libssh2/src/openssl.c:3995:5: note: in expansion of macro 'BIO_reset' + ``` + Ref: https://github.com/curl/curl-for-win/actions/runs/6696392318/job/18194032712#step:3:5060 + + Closes #1205 + +- Makefile.am: fix `cp` to preserve attributes and timestamp + +- cmake: simplify showing CMake version + + Move it to `CMakeLists.txt`. Drop `cmake --version` commands. + + Credit to the `zlib-ng` project for the idea: + https://github.com/zlib-ng/zlib-ng/blob/61e181c8ae93dbf56040336179c9954078bd1399/CMakeLists.txt#L7 + + Closes #1203 + +- ci: mbedtls 3.5.0 + + v3.5.0 needs extra compiler option for i386 to avoid: + ``` + #error "Must use `-mpclmul -msse2 -maes` for MBEDTLS_AESNI_C" + ``` + + Closes #1202 + +- tests: show cmake version used in integration tests + + Closes #1201 + +- readme.vms: fix typo [ci skip] + + Detected by codespell 2.2.6 + +- appveyor: YAML/PowerShell formatting, shorten variable name + + - use single-quotes in yaml and PowerShell. + + - shorten a variable name. + + - use indentation 2 for scripts. + + - use C else-style in PowerShell. + + Closes #1200 + +- ci: update actions, use shallow clones with appveyor + + - update GitHub Actions to their latest versions. + + - use shallow git clones in AppVeyor CI to save data over the wire. + + Closes #1199 + +- appveyor: move to pure PowerShell + + - replace batch commands with PowerShell. + + - merge separate command entries into single PowerShell blocks. + + Closes #1197 + +- windows: use built-in `_WIN32` macro to detect Windows + + Instead of `WIN32`. + + The compiler defines `_WIN32`. Windows SDK headers or build env defines + `WIN32`, or we have to take care of it. The agreement seems to be that + `_WIN32` is the preferred practice here. + + Minor downside is that CMake uses `WIN32` and we also adopted it in + `Makefile.mk`. + + In public libssh2 headers we stick with accepting either `_WIN32` or + `WIN32` and define our own namespaced `LIBSSH2_WIN32` based on them. + + grepping for `WIN32` remains useful to detect Windows-specific code. + + Closes #1195 + +- cmake: cleanup mbedTLS version detection more + + - lowercase, underscored local variables. + - fix `find_library()` to use the multiple names passed. + - rely more on `find_package_handle_standard_args()`. + Logic based on our `Findwolfssl.cmake`. + - delete ignored/unused `MBEDTLS_LIBRARY_DIR`. + - revert CI configuration to use `MBEDCRTYPO_LIBRARY`. + - clarify inputs/outputs in comment header. + - use variable for regex. + - formatting. + + Follow-up to 41594675072c578294674230d4cf5f47fa828778 #1192 + + Closes #1196 + +- cmake: delete duplicate `include()` + +- cmake: improve/fix mbedTLS detection + + - libssh2 needs the crypto lib only, stop dealing with the rest. + + - simplify logic. + + - drop hard-wired toolchain specific options that broke with e.g. MSVC. + + Reported by: AR Visions + Fixes #1191 + + - add mbedTLS version detection for recent releases. + + - merge custom detection results display into a single line. + + - shorten mbedTLS configuration in macOS CI job. + + Used the curl mbedTLS detection logic for ideas: + https://github.com/curl/curl/blob/a8c773845f4fdbfb09b08a6ec4b656c812568995/CMake/FindMbedTLS.cmake + + Closes #1192 + +GitHub (24 Sep 2023) +- [concussious brought this change] + + libssh2_session_get_blocking.3: Add description (#1185) + +Viktor Szakats (21 Sep 2023) +- autotools: fix selecting wincng in cross-builds (and more) + + - Fix explicitly selecting WinCNG in autotools cross-builds by moving + `windows.h` header check before the WinCNG availability check. + Follow-up to d43b8d9b0b9cd62668459fe5d582ed83aabf77e7 + + Reported-by: Jack L + Fixes #1186 + + - Add Linux -> mingw-w64 cross-builds for autotools and CMake. This + doesn't detect #1186, because that happened when explicitly specifying + WinCNG via `--with-crypto=wincng`, but not when falling back to WinCNG + by default. + + - autotools: fix to strip suffix from gcc version + + Before this patch we expected `n.n` `-dumpversion` output, but Ubuntu + may return `n-win32` (also with `-dumpfullversion`). Causing these + errors and failing to enable picky warnings: + ``` + ../configure: line 23845: test: : integer expression expected + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/6263453828/job/17007893718#step:5:143 + + Fix that by stripping any dash-suffix. + + gcc version detection is still half broken because we translate '10' + to '10.10' because `cut -d. -f2` returns the first word if the + delimiter missing. + + More possible `-dumpversion` output: `10-posix`, `10-win32`, + `9.3-posix`, `9.3-win32`, `6`, `9.3.0`, `11`, `11.2`, `11.2.0` + Ref: https://github.com/mamedev/mame/pull/9767 + + Closes #1187 + +GitHub (28 Aug 2023) +- [Michael Buckley brought this change] + + Properly bounds check packet_authagent_open() (#1179) + + * Properly bounds check packet_authagent_open + * packet.c: use strlen instead of sizeof for strings + * Make LIBSSH_CHANNEL's channel_type_len a size_t + * packet_authagent_open: use size_t for offset + + Credit: + Michael Buckley, signed off by Will Cosgrove + +Viktor Szakats (28 Aug 2023) +- os400qc3: move FIXME comment [ci skip] + + Follow-up to eb9f9de2c19ec67d12a444cce34bdd059fd26ddc + +- md5: allow disabling old-style encrypted private keys at build-time + + Before this patch, this happened at runtime when using an old (pre-3.0), + FIPS-enabled OpenSSL backend. + + This patch makes it possible to disable this via the build-time option + `LIBSSH2_NO_MD5_PEM`. + + Also: + - make sure to exclude all MD5 internal APIs when both the above and + `LIBSSH2_NO_MD5` are enabled. + - fix tests to support build with`LIBSSH2_NO_MD5`, `LIBSSH2_NO_MD5_PEM` + and `LIBSSH2_NO_3DES`. + - add FIXME to apply this change to `os400qc3.*`. + + Old-style encrypted private keys require MD5 and they look like this: + ``` + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: AES-128-CBC, + + + -----END RSA PRIVATE KEY----- + ``` + + E.g.: `tests/key_rsa_encrypted` + + Ref: https://github.com/libssh2/www/issues/20 + Closes #1181 + +- cmake: tidy-up `foreach()` syntax + + Use `IN LISTS` and `IN ITEMS`. This appears to be the preferred way + within CMake's own source code and possibly improves readability. + + Fixup a side-effect of `IN LISTS`, where it retains empty values at + the end of the list, as opposed to the syntax used before, which + dropped it. In our case this happened with lines read from a text + file via `file(READ)`. + + https://cmake.org/cmake/help/v3.7/command/foreach.html + + Closes #1180 + +- ci: replace `mv` + `chmod` with `install` in `Dockerfile` + + Cherry-picked from #1175 + Closes #1175 + +- ci: set file mode early in `appveyor_docker.yml` + + Also: + - replace tab with spaces in generated config file + - formatting + + Cherry-picked from #1175 + +- ci: add spellcheck (codespell) + + Also rename a variable in `src/os400qc3.c` to avoid a false positive. + + Cherry-picked from #1175 + +- cmake: also test for `libssh2_VERSION` + + Cherry-picked from #1175 + +- cmake: show cmake versions in ci + + Cherry-picked from #1175 + +- tests: formatting and tidy-ups + + - Dockerfile: use standard sep with `sed` + - Dockerfile: use single quotes in shell command + - appveyor.yml: use long-form option with `choco` + - tests/cmake: add language to test project + - reuse.yml: fix indentation + ``` + $ yamllint reuse.yml + reuse.yml + [...] + 11:5 error wrong indentation: expected 6 but found 4 (indentation) + 15:5 error wrong indentation: expected 6 but found 4 (indentation) + [...] + 27:5 error wrong indentation: expected 6 but found 4 (indentation) + ``` + + Cherry-picked from #1175 + +- openssl.c: whitespace fixes + + Cherry-picked from #1175 + +- checksrc: fix spelling in comment [ci skip] + +- cmake: quote more strings + + Follow-up to 3fa5282d6284efba62dc591697e6a687152bdcb1 + + Closes #1173 + +- drop `www.` from `www.libssh2.org` + + is now a 301 permanent redirect to + . + + Update all references to point directly to the new destination. + + Ref: https://github.com/libssh2/www/commit/ccf4a7de7f702a8ee17e2c697bcbef47fcf485ed + + Closes #1172 + +- cmake: add `ExternalProject` integration test + + - via `ExternalProject_Add()`: + https://cmake.org/cmake/help/latest/module/ExternalProject.html + (as documented in `docs/INSTALL_CMAKE.md`) + + - also make `FetchContent` fetch from local repo instead of live master. + + Closes #1171 + +- cmake: add integration tests + + Add a small project to test dependent/downstream CMake build using + libssh2. Also added to the GHA CI, and you can also run it locally with + `tests/cmake/test.sh`. + + Test three methods of integrating libssh2 into a project: + - via `find_package()`: + https://cmake.org/cmake/help/latest/command/find_package.html + - via `add_subdirectory()`: + https://cmake.org/cmake/help/latest/command/add_subdirectory.html + - via `FetchContent`: + https://cmake.org/cmake/help/latest/module/FetchContent.html + + Closes #1170 + +- cmake: (re-)add aliases for `add_subdirectory()` builds + + Add internal libssh2 library aliases to make these available for + downstream/dependent projects building libssh2 via `add_subdirectory()`: + + - `libssh2:libssh2_static` + - `libssh2:libssh2_shared` + - `libssh2:libssh2` (shared, or static when not building shared) + - `libssh2` (shared, or static when not building shared) + + Of these, `libssh2` was present in v1.10.0 and earlier releases, but + missing from v1.11.0. + + Closes #1169 + +- cmake: delete empty line [ci skip] + + Follow-up to 3fa5282d6284efba62dc591697e6a687152bdcb1 + +- cmake: reflect minimum version in docs [ci skip] + + Follow-up to 9cd18f4578baa41dfca197f60557063cad12cd59 + +- cmake: style tidy up + + - quote text literals to improve readability. + (exceptions: `FILES` items, `add_subdirectory` names, `find_package` + names, literal target names, version numbers, 0/1, built-in CMake + values and CMake keywords, list items in `cmake/max_warnings.cmake`) + - quote standalone variables that could break syntax on empty values. + - replace `libssh2_SOURCE_DIR` with `PROJECT_SOURCE_DIR`. + - add missing mode to `message()` call. + - `TRUE`/`FALSE` → `ON`/`OFF`. + - add missing default value `OFF` to `option()` for clarity. + - unfold some lines. + - `INSTALL_CMAKE.md` fixes and updates. Show defaults. + + Closes #1166 + +- wincng: prefer `ULONG`/`DWORD` over `unsigned long` + + To match with the types used by the `Crypt*()` (uses `DWORD`) and + `BCrypt*()` (uses `ULONG`) Windows APIs. + + This patch doesn't change data width or signedness. + + Closes #1165 + +- wincng: tidy-ups + + - make `_libssh2_wincng_key_sha_verify` static. + + - prefer `unsigned long` over `size_t` in two static functions. + + - prefer `ULONG` over `DWORD` to match `BCryptImportKeyPair()` + and `BCryptGenerateKeyPair()`. + + - add a newline. + + Closes #1164 + +- ci: add MSYS builds (autotools and cmake) + + Use existing MSYS2 section and extend it with builds for the MSYS + environment with both autotools and cmake. + + MSYS builds resemble Cygwin ones: The env is Unixy, where Windows + headers are all available but we don't use them. + + Also: + + - extend existing autotools logic for Cygwin to skip detecting + `windows.h` for MSYS targets too. + + - require `windows.h` for the WinCNG backend in autotools. Before this + patch, autotools allowed selecting WinCNG on the Cygwin and MSYS + platforms, but the builds then fell apart due to the resulting mixed + Unixy + Windowsy environment. The general expectation for Cygwin/MSYS + builds is not to use the Windows API directly in them. + + - stop manually selecting the `MSYS Makefiles` CMake generator for + MSYS2-based GHA CI builds. mingw-w64 builds work fine without it, but + it broke MSYS build which use `Unix Makefiles`. Deleting this setting + fixes all build flavours. + + Closes #1162 + +- ci: cygwin job tidy-ups + + `CMAKE_C_COMPILER=gcc` not necessary, delete it. + + Follow-up to f1e96e733fefb495bc31b07f5c2a5845ff877c9c + + Cherry-picked from #1163 + Closes #1163 + +- ci: add Cygwin builds (autotools and cmake) + + To avoid builds picking up non-Cygwin components coming by default with + the CI machine, I used the solution recommended by Cygwin [1] and set + `PATH` manually. To avoid repeating this for each step, I merged steps + into a single one. Let us know if there is a more elegant way. + + Cygwin's Github Action uses cleartext HTTP. We upgrade this to HTTPS. + + autotools build seemed to take slightly longer than other jobs. To save + turnaround time I disabled building tests. + + Cygwin package search: https://cygwin.com/cgi-bin2/package-grep.cgi + + [1] https://github.com/cygwin/cygwin-install-action/tree/v4#path + + Closes #1161 + +- cmake: add `LIB_NAME` variable + + It holds the name `libssh2`. Mainly to document its uses, and also + syncing up with the same variable in libcurl. + + Closes #1159 + +- cmake: add one missed `PROJECT_NAME` variable + + Follow-up to 72fd25958a7dc6f8e68f2b2d5d72839a2da98f9c + + Closes #1158 + +- cmake: tidy-up concatenation in `CMAKE_MODULE_PATH` + + Former solution was appending an empty element to the array if + `CMAKE_MODULE_PATH` was originally empty. The new syntax doesn't have + this side-effect. + + There is no known issue caused by this. Fixing it for good measure. + + Closes #1157 + +- ci: add mingw-w64 UWP build + + Add a CI test for Windows UWP builds using mingw-w64. Before this patch + we had UWP builds tested with MSVC only. + + Alike existing UWP jobs, it's not possible to run the binaries due to + the missing UWP runtime DLL: + https://github.com/libssh2/libssh2/actions/runs/5821297010/job/15783475118#step:11:42 + + We could install `winstorecompat-git` in the setup-msys2 step, but opted + to do it manually to avoid the overhead for every matrix job. + + All this would work smoother with llvm-mingw, which features an UWP + toolchain prefix and provides all necessary implibs by default. + + This also hit a CMake bug (with v3.26.4), where CMake gets confused and + sets up `windres.exe` to use the MSVC rc.exe-style command-line: + https://github.com/libssh2/libssh2/actions/runs/5819232677/job/15777236773#step:9:126 + + Notice that MS "sunset" UWP in 2021: + https://github.com/microsoft/WindowsAppSDK/discussions/1615 + + If this particular CI job turns out to be not worth the maintenance + burden or CPU time, or too much of a hack, feel free to delete it. + + Ref: https://github.com/libssh2/libssh2/pull/1147#issuecomment-1670850890 + Closes #1155 + +- cmake: replace `libssh2` literals with `PROJECT_NAME` variable + + Where applicable. + + This also makes it more obvious which `libssh2` uses were referring + to the project itself. + + Closes #1152 + +- cmake: fix `STREQUAL` check in error branch + + This caused a CMake error instead of our custom error when manually + selecting the `WinCNG` crypto-backend for a non-Windows target. + + Also cleanup `STREQUAL` checks to use variable name without `${}` on + the left side and quoted string literals on the right. + + Closes #1151 + +- misc: flatten `_libssh2_explicit_zero` if tree + + Closes #1149 + +- src: drop a redundant `#include` + + We include `misc.h` via `libssh2_priv.h` already. + + Closes #1153 + +- openssl: use automatic initialization with LibreSSL 2.7.0+ + + Stop calling `OpenSSL_add_all_*()` for LibreSSL 2.7.0 and later. + + LibreSSL 2.7.0 (2018-03-21) introduced automatic initialization and + deprecated these functions. Stop calling these functions manually for + LibreSSL version that no longer need them. + + Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.7.0-relnotes.txt + Ref: https://github.com/libressl/openbsd/commit/46f29f11977800547519ee65e2d1850f2483720b + Ref: https://github.com/libssh2/libssh2/issues/302 + + Also stop calling `ENGINE_*()` functions when initialization is + automatic with LibreSSL 2.7.0+ and OpenSSL 1.1.0+. Engines are also + initializated automatically with these. + + Closes #1146 + +- gha: restore curly braces in `if` + + Without curly braces it was less obvious which string is a GHA expression. + + Also fix an `if` expression that always missed its curly braces. + + Reverts cab3db588769d6deed97ba89ca9221fd7503405e + + Closes #1145 + +- ci: bump mbedtls + +- [renmingshuai brought this change] + + Add a new structure to separate memory read and file read. + We use different APIs when we read one private key from memory, + so it is improper to store the private key information in the + structure that stores the private key file information. + + Fixes https://github.com/libssh2/libssh2/issues/773 + Reported-by: mike-jumper + +- tests: replace FIXME with comments + + `key_dsa_wrong` is the same kind of (valid) key as `key_dsa`, both with + an empty passphrase. Named "wrong" because it's intentionally not added + to our `openssh_server/authorized_keys` file. + +- tidy-up: delete duplicate word from comment + +- cmake: cache more config values on Windows + + Set two cases of non-detection to save the time dynamically detecting + these on each build init. Affects old MSVC versions. + + Before: + https://ci.appveyor.com/project/libssh2org/libssh2/builds/47668870/job/i17e0e9yx8rgpv4i + + After: + https://ci.appveyor.com/project/libssh2org/libssh2/builds/47674950/job/ysa1jq0pxtyhui3f + + Closes #1142 + +- revert: build: respect autotools `DLL_EXPORT` in `libssh2.h` + + Revert fb1195cf88268a11e2709b9912ab9dca8c23739c #917 + + On a second look this change did not improve anything with autotools + builds. autotools seems to handle the dll export matter without it. + + This patch also broke (e.g.) curl-for-win autotools builds, where the + curl build defines `DLL_EXPORT` while building libcurl DLL. `libssh2.h` + picks it up, resulting in unresolved symbols while trying to link a + static libssh2 on Windows. The best fix seems to be to revert this, + instead of adding extra tweaks to dependents. + + Fixes: + https://ci.appveyor.com/project/curlorg/curl-for-win/builds/47667412#L11035 + ``` + ld.lld-15: error: undefined symbol: __declspec(dllimport) libssh2_session_block_directions + >>> referenced by vssh/.libs/libcurl_la-libssh2.o:(ssh_do) + >>> referenced by vssh/.libs/libcurl_la-libssh2.o:(ssh_connect) + >>> referenced by vssh/.libs/libcurl_la-libssh2.o:(ssh_multi_statemach) + >>> referenced 8 more times + + ld.lld-15: error: undefined symbol: __declspec(dllimport) libssh2_session_init_ex + >>> referenced by vssh/.libs/libcurl_la-libssh2.o:(ssh_connect) + + ld.lld-15: error: undefined symbol: __declspec(dllimport) libssh2_session_set_read_timeout + [...] + ``` + + Closes #1141 + +- gha: simplify `if` strings + + Closes #1140 + +- test_read: make it run without Docker + + Apply an existing fix to `test_read`, so that it falls back to use + the current username instead of the hardcoded `libssh2` when run + outside Docker. + + This allows to run algo tests with this command: + ```shell + cd tests + ./test_sshd.test ./test_read_algos.test + ``` + + Closes #1139 + +- cmake: streamline invocation + + Stop specifiying the current directory. + Simplify build instructions. + + Closes #1138 + +- NMakefile: delete + + This make file was for long time unmaintained (last updated in 2014). + Despite best efforts to keep it working in the recent round of major + overhauls, it appears to be broken now. There is also no way to test it + without an actual MSVC env and it's also missing from our CI. Based on + our Issue tracker, it's also not widely used. + + Since its addition in 2005, libssh2 got support for CMake in 2014. + CMake should be able to generate NMake makefiles with the option + `-G "NMake Makefiles"`. (I haven't tested this.) + + Ref: https://github.com/libssh2/libssh2/discussions/1129 + Closes #1134 + +- tests: add aes256-gcm encrypted key test + + Follow-up to #1133 + + Also update `tests/gen_keys.sh` to set `aes256-ctr` encryption method + for `key_ed25519_encrypted' explicitly. + + Closes #1135 + +GitHub (26 Jul 2023) +- [Jakob Egger brought this change] + + Fix private keys encrypted with aes-gcm methods (#1133) + + libssh2 1.11.0 fails to decrypt private keys encrypted with + aes128-gcm@openssh.com and aes256-gcm@openssh.com ciphers. + + To reproduce the issue, you can create a test key with a command like + the following: + + ```bash + ssh-keygen -Z aes256-gcm@openssh.com -f id_aes256-gcm + ``` + + If you attempt to use this key for authentication, libssh2 returns the + not-so-helpful error message "Wrong passphrase or invalid/unrecognized + private key file format". + + The problem is that OpenSSH encrypts keys differently than packets. It + does not include the length as AAD, and the 16 byte authentication tag + is appended after the encrypted key. The length of the authentication + tag is not included in the encrypted key length. + + I have not found any documentation for this behaviour -- I discovered it + by looking at the OpenSSH source. See the `private2_decrypt` function in + . + + This patch fixes the code for reading OpenSSH private keys encrypted + with AES-GCM methods. + +Viktor Szakats (26 Jul 2023) +- ci: add missing timeout to 'autotools distcheck' step + +- cmake: merge `set_target_properties()` calls + + Also rename variable `LIBSSH2_VERSION` to `LIBSSH2_LIBVERSION` in + context of lib versioning to avoid collision with another use. + + Closes #1132 + +- cmake: formatting [ci skip] + +- cmake: (re-)add zlib to `Libs.private` in `libssh2.pc` + + We mistakently added transitive zlib to `Requires.private` before, then + removed it. This patch re-adds zlib, but this time to `Libs.private`, + which is listing raw libs and should include transitive libs as well. + + Also add zlib when used as a direct dependency when zlib compression + support is enabled. + + Follow-up to ef538069a661a43134fe7b848b1fe66b2b43bdac + + Closes #1131 + +- cmake: formatting [ci skip] + +- cmake: use `wolfssl/options.h` for detection, like autotools + + Closes #1130 + +- build: stop requiring libssl from openssl + + libssh2 does not use or need the TLS/SSL library of OpenSSL. + It only needs libcrypto. + + Closes #1128 + +- cmake: add openssl libs to `Libs.private` in `libssh2.pc` + + Also to sync up with autotools-generated `libssh2.pc`, that + already added them. + + Closes #1127 + +- Makefile.mk: stop linking unused mbedtls libs + + Stop linking libmbedtls and libmbedx509 (similarly to autotools). + Only libmbedcrypto is necessary for libssh2. + +- cmake: bump minimum CMake version to v3.7.0 + + Fixes the warning below, which appeared in CMake v3.27.0: + ``` + CMake Deprecation Warning at CMakeLists.txt:39 (cmake_minimum_required): + Compatibility with CMake < 3.5 will be removed from a future version of + CMake. + + Update the VERSION argument value or use a ... suffix to tell + CMake that the project does not need compatibility with older versions. + ``` + + Bump straight up to v3.7.0 to sync up with the curl project: + https://github.com/curl/curl/blob/2900c29218d2d24ab519853589da84caa850e8c7/CMakeLists.txt#L64 + + CMake release dates: + v3.7.0 2016-11-11 + v3.5.0 2016-03-08 + v3.1.0 2014-12-17 + + Closes #1126 + +- build: tidy-up `libssh2.pc.in` variable names + + - prefix with `LIBSSH2_PC_` + + - match with the names of `pkg-config` values. + + - use the same names in autotools and CMake scripts. + + - use `LIBSSH2_VERSION` for the version number in autotools scripts, + to match the name used in CMake. + + Closes #1125 + +- libssh2.pc: re-add & extend support for static-only libssh2 builds + + Adapted for libssh2 from the curl commit message by James Le Cuirot: + + "A project built entirely statically will call `pkg-config` with + `--static`, which utilises the `Libs.private:` field. Conversely it will + not use `--static` when not being built entirely statically, even if + there is only a static build of libssh2 available. This will most + likely cause the build to fail due to underlinking unless we merge the + `Libs:` fields. + + Consider that this is what the Meson build system does when it generates + `pkg-config` files." + + This patch extends the above to `Requires:`, to mirror `Libs:` with + `pkg-config` package names. + + Follow-up to 1209c16d93cba3c5e0f68c12fa4a5049f49c00d8 #1114 + + Ref: https://github.com/libssh2/libssh2/pull/1114#issuecomment-1634334809 + Ref: https://github.com/curl/curl/commit/98e5904165859679cd78825bcccb52306ee3bb66 + Ref: https://github.com/curl/curl/pull/5373 + Closes #1119 + +GitHub (14 Jul 2023) +- [Nursan Valeyev brought this change] + + cmake: CMAKE_SOURCE_DIR -> PROJECT_SOURCE_DIR (#1121) + + Fixes compiling as dependency with FetchContent + + Co-authored-by: Viktor Szakats + +Viktor Szakats (14 Jul 2023) +- autotools: use comma separator in `Requires.private` of `libssh2.pc` + + In `Requires*:`, the documented name separator is comma. We already used + it in the CMake-generated `libssh2.pc`. Adjust the autotools-generated + one to use it too, instead of spaces. + + Ref: https://linux.die.net/man/1/pkg-config + Ref: https://gitlab.freedesktop.org/pkg-config/pkg-config/-/blob/d97db4fae4c1cd099b506970b285dc2afd818ea2/pkg-config.1 + + Closes #1124 + +- build: add/fix `Requires.private` packages in `libssh2.pc` + + - autotools was using `libwolfssl`. CMake left it empty. wolfSSL + provides `wolfssl.pc`. This patch sets `Requires.private: wolfssl` + with both build tools. + + - add `libgcrypt` to `Requires.private` with both autotools and CMake. + Ref: + https://github.com/gpg/libgcrypt/blob/e76e88eef7811ada4c6e1d57520ba8c439139782/src/libgcrypt.pc.in + Present since 2005-04-22: + https://github.com/gpg/libgcrypt/commit/32bf3f13e8b45497322177645bebf0b5d0c9cb8e + Released in v1.3.0 2007-05-04: + https://github.com/gpg/libgcrypt/releases/tag/libgcrypt-1.3.0 + + - also stop adding transitive `zlib` deps to `Requires.private`. + The referenced crypto package is adding it as nedded. + This makes deduplication of the list redundant, so stop doing it. + Follow-up to 2fc367900701e6149efc42bd674c4b69127756dd + + (`libssh2.pc` not tested as a project dependency.) + + Closes #1123 + +- cmake: tidy-ups + + - dedupe `Requires.private` in `libssh2.pc`. + `zlib` could appear on the list twice: + ``` + Requires.private: libssl,libcrypto,zlib,zlib + ``` + According to CMake docs `list(REMOVE_DUPLICATES ...)`, is supported by + our minimum required CMake version (and by earlier ones even): + https://cmake.org/cmake/help/v3.1/command/list.html#remove-duplicates + + - move `cmake_minimum_required()` to the top. + + - move `set(CMAKE_MODULE_PATH)` to the top. + + - delete duplicate `set(CMAKE_MODULE_PATH)`. + + - replace `CMAKE_CURRENT_SOURCE_DIR` with `PROJECT_SOURCE_DIR` in root + `CMakeLists.txt` for robustness. + + - replace `gcovr` option with long-form for readability/consistency. + + - rename `GCOV_OPTIONS` to `GCOV_CFLAGS`. These are C options we enable + when using gcov, not gcov tooling options. + + Closes #1122 + +- openssl: add missing check for `LIBRESSL_VERSION_NUMBER` before use + + Fixes: + ``` + openssl.h:101:5: warning: "LIBRESSL_VERSION_NUMBER" is not defined [-Wundef] + LIBRESSL_VERSION_NUMBER >= 0x3050000fL + ^ + ``` + + Ref: https://github.com/libssh2/libssh2/issues/1115#issuecomment-1631845640 + Closes #1117 + +- [Harmen Stoppels brought this change] + + Don't put `@LIBS@` in pc file + +- misc: delete redundant NULL check and assignment + + Follow-up to 724effcb47ebb713d3ef1776684b8f6407b4b6a5 #1109 + + Ref: https://github.com/libssh2/libssh2/pull/1109#discussion_r1246613274 + Closes #1111 + +- [renmingshuai brought this change] + + We should check whether *key_method is a NULL pointer instead of key_method + + Signed-off-by: renmingshuai + +GitHub (30 Jun 2023) +- [ren mingshuai brought this change] + + Add NULL pointer check for outlen before use (#1109) + + Before assigning a value to the outlen, we need to check whether it is NULL. + + Credit: Ren Mingshuai + +Viktor Szakats (25 Jun 2023) +- cmake: re-add `Libssh2:libssh2` for compatibiliy + lowercase namespace + + - add `libssh2:libssh2` target that selects the shared lib if built, + otherwise the static one. + + - re-add `Libssh2:libssh2` target for compatibility with v1.10.0 and + earlier. This is an alias for `libssh2:libssh2`. + + - keep `libssh2:libssh2_shared` and `libssh2_libssh2_static` targets. + + - allow using `find_package(libssh2)` in dependents as an alternative + to `find_package(Libssh2)`. + + Co-authored-by: Radek Brich + Suggested-by: Haowei Hsu + + Fixes #1103 + Fixes #731 + Closes #1104 + +- example: fix regression in `ssh2_exec.c` + + Regression from b13936bd6a89993cd3bf4a18317ca5bd84bb08d7 #861 #846. + Update a variable name missed above. + + Reported-by: PewPewPew + Fixes #1105 + Closes #1106 + +- docs: replace SHA1 with SHA256 in CMake example + +- checksrc: modernise perl file open + + Use regular variables and separate file open modes from filenames. + + Suggested by perlcritic + + Copied from https://github.com/curl/curl/commit/7f669aa0f1d40ef5d64543981f22bdc5af1272f5 + Copied from https://github.com/curl/trurl/commit/f2784a9240f47ee28a845 + +- reuse: comply with 3.1 spec and 2.0.0 checker + + The checker tool was upgraded upstream to 2.0.0 and the REUSE + Specification to version 3.1 (from 3.0), causing these new errors: + ``` + reuse.project - WARNING - Copyright and licensing information for 'docs/INSTALL_AUTOTOOLS' have been found in 'docs/INSTALL_AUTOTOOLS' and the DEP5 file located at '.reuse/dep5'. The information in the DEP5 file has been overridden. Please ensure that this is correct. + reuse.project - WARNING - Copyright and licensing information for 'tests/openssh_server/Dockerfile' have been found in 'tests/openssh_server/Dockerfile' and the DEP5 file located at '.reuse/dep5'. The information in the DEP5 file has been overridden. Please ensure that this is correct. + + The following files have no licensing information: + * docs/INSTALL_AUTOTOOLS + * tests/openssh_server/Dockerfile + ``` + Via: https://github.com/libssh2/libssh2/actions/runs/5333572682/jobs/9664211341?pr=1098#step:4:4 + + Ref: https://github.com/fsfe/reuse-tool/releases/tag/v2.0.0 + Ref: https://git.fsfe.org/reuse/docs/src/branch/stable/CHANGELOG.md#3-1-2023-06-21 + + Original discovery: https://github.com/libssh2/libssh2/pull/1098#issuecomment-1600719575 + + Fixes #1101 + Closes #1102 + +- tests: trap signals in scripts + + Closes #1098 + +- test_sshd.test: fixup to distcheck failure + + Fixes: + ``` + ERROR: test_sshd.test - missing test plan + ERROR: test_sshd.test - exited with status 1 + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/5322354271/jobs/9638694218#step:10:532 + + Caused by trying to create the log file in a read-only directory. + + Follow-up to 299c2040625830d06ad757d687807a166b57d6de + Closes #1099 + +GitHub (21 Jun 2023) +- [Viktor Szakats brought this change] + + test_sshd.test: show sshd and test connect logs on harness failure (#1097) + +- [Joel Depooter brought this change] + + Fix incorrect byte offset in debug message (#1096) + + Fixes debug log message + + Credit: + Joel Depooter + +Viktor Szakats (16 Jun 2023) +- tidy-up: delete whitespace at EOL [ci skip] + +- mbedtls: include `version.h` for `MBEDTLS_VERSION_NUMBER` + + Older (2021 or earlier?) mbedTLS releases require this. + + Reported-by: rahmanih on Github + Fixes #1094 + Closes #1095 + +- hostkey: do not advertise ssh-rsa when SHA1 is disabled + + Before this patch OpenSSL, mbedTLS, WinCNG and OS/400 advertised both + SHA2 and SHA1 host key algos, even when SHA1 was not supported by the + crypto backend or when forcefully disabled via `LIBSSH2_NO_RSA_SHA1`. + + Reported-by: João M. S. Silva + Fixes #1092 + Closes #1093 + +- openssl.h: whitespace tidy-up [ci skip] + +GitHub (14 Jun 2023) +- [Dan Fandrich brought this change] + + test_sshd.test: set a safe PID directory (#1089) + + The compiled in default to sshd can be a non-writable location since it + expects to be run as root. + +Viktor Szakats (13 Jun 2023) +- mingw: fix printf mask for 64-bit integers + + Before 02f2700a61157ce5a264319bdb80754c92a40a24 #846 #876, we used + `%I64d'. That patch changed this to `%lld`. This patch uses `PRId64` + (defined in `inttypes.h`). + + Fixes #1090 + Closes #1091 + +- test_sshd.test: minor cleanups + +Daniel Stenberg (7 Jun 2023) +- provide SPDX identifiers + + - All files have prominent copyright and SPDX identifier + - If not embedded in the file, in the .reuse/dep5 file + - All used licenses are in LICENSES/ (not shipped in tarballs) + - A new REUSE CI job verify that all files are OK + + Assisted-by: Viktor Szakats + + Closes #1084 + +Viktor Szakats (6 Jun 2023) +- src: improve MSVC C4701 warning fix + + Simplify the code to avoid this warning. This might also help avoiding + it with other compilers (e.g. gcc?). + + Improves 02f2700a61157ce5a264319bdb80754c92a40a24 #876 + Might fix #1083 + Closes #1086 + +Daniel Stenberg (5 Jun 2023) +- configure.ac: remove AB_INIT + + Not used. Remove m4/autobuild.m4 as well + +Viktor Szakats (4 Jun 2023) +- copyright: remove years from copyright headers + + Also: + - uppercase `(C)`. + - add missing 'All rights reserved.' lines. + - drop duplicate 'Author' lines. + - add copyright headers where missing. + - enable copyright header check in checksrc. + + Reasons for deleting years (copied as-is from curl): + - they are mostly pointless in all major jurisdictions + - many big corporations and projects already don't use them + - saves us from pointless churn + - git keeps history for us + - the year range is kept in COPYING + + Closes #1082 + +- tests: cast to avoid `-Wchar-subscripts` with Cygwin + + ``` + In file included from $HOME/src/cygwin/libssh2/libssh2-1.11.0-1.x86_64/src/libssh2-1.11.0/tests/openssh_fixture.c:57: + $HOME/src/cygwin/libssh2/libssh2-1.11.0-1.x86_64/src/libssh2-1.11.0/tests/openssh_fixture.c: In function 'run_command_varg': + $HOME/src/cygwin/libssh2/libssh2-1.11.0-1.x86_64/src/libssh2-1.11.0/tests/openssh_fixture.c:136:37: warning: array subscript has type 'char' [-Wchar-subscripts] + 136 | while(end > 0 && isspace(buf[end - 1])) { + | ~~~^~~~~~~~~ + ``` + Ref: https://github.com/libssh2/libssh2/files/11644340/cygwin-x86_64-libssh2-1.11.0-1-check.log + + Reported-by: Brian Inglis + Fixes #1080 + Closes #1081 + +- tidy-up: avoid exclamations, prefer single quotes, in outputs + + Closes #1079 + +- autotools: improve libz position + + We repositioned crypto libs in 4f0f4bff5a92dce6a6cd7a5600a8ee5660402c3f + via #941 and subsequently in d4f58f03438e326b8696edd31acadd6f3e028763 + from d93ccf4901ef26443707d341553994715414e207 via #1013. + + This patch moves libz accordingly, to unbreak certain build scenarios. + + Reported-by: Kenneth Davidson + Regression from 4f0f4bff5a92dce6a6cd7a5600a8ee5660402c3f #941 + Fixes #1075 + Closes #1077 + +- src: bump `hash_len` to `size_t` in `LIBSSH2_HOSTKEY_METHOD` + + Follow-up to 7b8e02257f01a6dac5f65305b18bb74a157fb5c4 + Closes #1076 + +- ci: add non-static autotools i386 build, ignore GHA updates on AppVeyor + + Add a non-static autotools build to GitHub Actions. Make this build + target i386 and libgcrypt, to test a new build combination if we are at + it. + + Also: + - GHA: add necessary generic bits for i386 autotools builds. + - AppVeyor CI: teach it to ignore commits updating our GHA config. + + Follow-up to 572c57c9d8d4e89cfce19dde40125d55481256d1 #1072 + Closes #1074 + +GitHub (31 May 2023) +- [Xi Ruoyao brought this change] + + autotools: skip tests requiring static lib if `--disable-static` (#1072) + + Co-authored-by: Viktor Szakats + Regression from 83853f8aea0e2f739cacd491632eb7fd3d03ad2d #663 + Fixes #1056 + +Viktor Szakats (31 May 2023) +- ci: prefer `=` operator in shell snippets + + Closes #1073 + +- src: bump DSA and ECDSA sign `hash_len` to `size_t` + + Closes #1055 + +- scp: fix missing cast for targets without large file support + + E.g. on 32-bit Linux. Issue revealed after adding i386 Linux CI build + in abdf40c741c575f94bdea1c67a9d1182ff813ccb #1057. + + ``` + /home/runner/work/libssh2/libssh2/src/scp.c: In function 'scp_recv': + /home/runner/work/libssh2/libssh2/src/scp.c:765:23: error: conversion from 'libssh2_int64_t' {aka 'long long int'} to '__off_t' {aka 'long int'} may change value [-Werror=conversion] + 765 | sb->st_size = session->scpRecv_size; + | ^~~~~~~ + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/5126803482/jobs/9221746299?pr=1054#step:12:51 + + Regression from 5db836b2a829c6fff1e8c7acaa4b21b246ae1757 #1002 + Closes #1060 + +- mbedtls.h: formatting [ci skip] + + For consistency with `mbedtls.c`. + + Follow-up to 1153ebdeba563ac657b525edd6bf6da68b1fe5e2 + +- libssh2.h: bump to 1.11.1_DEV [ci skip] + +- mbedtls: use more `size_t` to sync up with `crypto.h` + + Ref: 5a96f494ee0b00282afb2db2e091246fc5e1774a #846 #879 + + Fixes #1053 + Closes #1054 + +- ci: drop redundant/unused vars, sync var names + + Closes #1059 + +- ci: add i386 Linux build (with mbedTLS) + + Also: + - reorder Linux build matrix to make build tool more visible. + - hide apt-get progress bar. + - prepare package install step for i386 builds. + + Detects bug #1053 + Closes #1057 + +- checksrc: switch to dot file + + Closes #1052 + +Version 1.11.0 (30 May 2023) + +Daniel Stenberg (30 May 2023) +- libssh2.h: bump to 1.11.0 for release + +GitHub (30 May 2023) +- [Will Cosgrove brought this change] + + Libssh2 1.11 release notes, copyright (#1048) + + * Libssh2 1.11 release notes, copyright + +Viktor Szakats (29 May 2023) +- add copyright/credits + + Closes #1050 + +- ci: add LIBSSH2_NO_AES_CBC to GNU Make build + + Closes #1049 + +- ci: add wolfSSL Linux builds + + Exclude wolfSSL builds from tests. All fail: + + ``` + 2/43 Test #2: test_aa_warmup ............................***Failed 5.59 sec + libssh2_session_handshake failed (-44): Unable to ask for ssh-userauth service + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/5085775952/jobs/9139583212#step:12:942 (with logging) + Ref: https://github.com/libssh2/libssh2/actions/runs/5085586301/jobs/9139192562#step:12:225 + + wolfSSL version: + ``` + Get:1 http://azure.archive.ubuntu.com/ubuntu jammy/universe amd64 libwolfssl32 amd64 5.2.0-2 [818 kB] + Get:2 http://azure.archive.ubuntu.com/ubuntu jammy/universe amd64 libwolfssl-dev amd64 5.2.0-2 [1194 kB] + ``` + + Cherry-picked from #1046 + Closes #1046 + +- ci: mbedTLS build config tidy-up + + Cherry-picked from #1046 + +- wolfssl: fix detection of AES-GCM feature + + Follow-up to df513c0128e1a811ad863d153892618e728845f0 + + Ref: https://github.com/libssh2/libssh2/issues/1020#issuecomment-1562069241 + Closes #1045 + +- build: fix 'unused' compiler warnings with all `NO` options set + + - add `LIBSSH2_NO_ED25519` build-time option to force-disable ED25519 + support. Useful to replicate crypto-backend builds without ED25519, + such as wolfSSL. + + - openssl: fix unused variable and function warnings with all supported + `LIBSSH2_NO_*` options enabled. + + - mbedtls: fix misplaced `#endif` leaving out the required internal + public function `libssh2_supported_key_sign_algorithms()`. + + - mbedtls: add missing prototype for two internal public functions. + + - delete a redundant block. + + All `NO` options: + ```shell + CPPFLAGS=' + -DLIBSSH2_NO_MD5 -DLIBSSH2_NO_HMAC_RIPEMD -DLIBSSH2_NO_DSA + -DLIBSSH2_NO_RSA -DLIBSSH2_NO_RSA_SHA1 + -DLIBSSH2_NO_ECDSA -DLIBSSH2_NO_ED25519 -DLIBSSH2_NO_AES_CTR + -DLIBSSH2_NO_BLOWFISH -DLIBSSH2_NO_RC4 -DLIBSSH2_NO_CAST + -DLIBSSH2_NO_3DES' + ``` + + Closes #1044 + +- cmake: avoid `list(PREPEND)` for compatibility + + `list(PREPEND)` requires CMake v3.15, our minimum is v3.1. `APPEND` + should work fine for headers anyway. + + Also fix a wrongly placed comment. + + Ref: https://cmake.org/cmake/help/latest/command/list.html#prepend + + Regression from 1e3319a167d2f32d295603167486e9e88af9bb4e + + Closes #1043 + +- checksrc: verify label indent, fix fallouts + + Also update two labels to match the rest of the source. + + checksrc update credit: Emanuele Torre @emanuele6 + + Ref: https://github.com/curl/curl/pull/11134 + + Closes #1042 + +- tidy-up: minor nits + +- ci: drop default shared/static configuration options + + Both autotools and cmake build both shared and static lib by default. + + Ref: 896154bc17f000c0a1bb89b74bc879692ac0d47c + + Delete configuration enabling these explicitly in CI jobs. + + Cherry-picked from #1036 + Closes #1036 + +- cmake: enable shared libssh2 library by default + + This brings default behaviour in sync with autotools, which builds both + lib flavours by default. + + (Notice that on Windows, autotools includes the Windows Resource in the + static library, when building both at the same time. CMake doesn't have + this issue.) + + Enabling both lib flavours has a side-effect when using non-MinGW + toolchains (e.g. MSVC): to resolve the filename conflict between import + and static libraries, we add a suffix to the static lib, naming it + `libssh2_static.lib`. This can break dependent builds relying on + `libssh2.lib` for linking the static libssh2. + + Workarounds: + + - disable either shared or static libssh2 via + `-DBUILD_STATIC_LIBS=OFF` or + `-DBUILD_SHARED_LIBS=OFF`. This results in a libssh2 library (either + static or shared) without a prefix: `libssh2.lib`. + + - set a custom static library suffix via: + `-DSTATIC_LIB_SUFFIX=_my_static`. Resulting in + `libssh2_my_static.lib`, and import library + `libssh2.lib`. + + - set a custom import library suffix via: + `-DIMPORT_LIB_SUFFIX=_my_implib`. Resulting in + `libssh2_my_implib.lib` import library, and static library + `libssh2.lib`. + + - customize the default static/import library suffix (incl. extension) + via + `-DCMAKE_STATIC_LIBRARY_SUFFIX=_my_static_suffix.lib` or + `-DCMAKE_IMPORT_LIBRARY_SUFFIX=_my_import_suffix.lib`. + + Cherry-picked from #1036 + +- cmake: tweak static/import lib name collision avoidance logic + + The collision issue affects (typically) MSVC, when building both shared + and static libssh2 in one go. + + Ref: https://stackoverflow.com/questions/2140129/what-is-proper-naming-convention-for-msvc-dlls-static-libraries-and-import-libr + + Initially we handled this by appending the `_imp` suffix to the import + library filename. This is how curl tackles this, but on a second look, + this solution seem to be accidental and has no widespread use. + + It seems more widely accepted to use the '_static' suffix for the static + library. This patch implements this. + + (MinGW, Cygwin and unixy platforms are not affected by this issue.) + + Follow-up to 4e2580628dd1f8dc51ac65ac747ebcf0e93fa3d1 + + Cherry-picked from #1036 + +- cmake: add `IMPORT_LIB_SUFFIX` (like `STATIC_LIB_SUFFIX`) + + Allow resolving the import/static library name collision also by setting + a custom _import_ library name suffix. + + Follow-up to 4e2580628dd1f8dc51ac65ac747ebcf0e93fa3d1 + + Cherry-picked from #1036 + +- ci: do not disable shared lib with msys2/autotools in GHA + + Cherry-picked from #1036 + +- Makefile.mk: fix `DYN=1 test` by skipping tests needing static lib + + `DYN=1` means to build examples/tests against the shared libssh2. + + Before this patch this was broken for building tests. This patch skips + building tests that require the static libssh2 library, so the build now + succeeds. + + Also move the list of tests that require static lib from + `CMakeLists.txt` to `Makefile.inc`, so that we can reuse it in + `Makefile.mk`. + + Couldn't find a way to also reuse it in `Makefile.am`. Move the + `Makefile.am` specific definitions close to the shared list, to make it + easier to keep them synced. + + Cherry-picked from #1036 + +- ci: make one of the AppVeyor CMake jobs shared-only + + This build combination did not have a CI test before. + + Cherry-picked from #1036 + +- cmake: allow tests with `BUILD_STATIC_LIBS=OFF` + + Before this patch, the CMake build did not allow to disable static + libssh2 library while also building tests. + + This patch removes this constraint, and makes this combination possible. + In this case the 3 (at the moment) tests that require a static libssh2 + library, are skipped from the build and test runs. + + Cherry-picked from #1036 + +- build: fix to set `-DLIBSSH2DEBUG` for tests + + Required for tests using libssh2 internals. These are the ones + requiring the libssh2 _static_ lib. + + Before this patch, `src` and `tests` declared the `session` structure + differently, due to extra struct members added with the `LIBSSH2DEBUG` + macro set. But, the macro was only set for `src` when using CMake. At + runtime this caused struct members to be at different offsets between + lib and test code, resulting in the test failures below. + + Due to another bug in the affected test, these failures did not reflect + in the exit code, which always returned success, so this went unnoticed + for a good while. Fixed in: 84d31d0ca7b647ad4c2aa92bf8f4a94b233f5d3b + + ``` + Start 5: test_auth_keyboard_info_request + [...] + 5: Test case 1 passed + 5: Test case 2 passed + 5: Test case 3: expected return code to be 0 got -1 + 5: Test case 4: expected last error code to be "-6" got "-38" + 5: Test case 5: expected last error code to be "-6" got "-38" + 5: Test case 6: expected last error code to be "-6" got "-38" + 5: Test case 7: expected last error message to be "Unable to decode keyboard-interactive number of keyboard prompts" got "userauth keyboard data buffer too small to get l + 5: Test case 8: expected last error code to be "-41" got "-38" + 5: Test case 9: expected return code to be 0 got -1 + 5: Test case 10: expected return code to be 0 got -1 + 5: Test case 11: expected last error code to be "-6" got "-38" + 5: Test case 12: expected last error message to be "Unable to decode user auth keyboard prompt echo" got "userauth keyboard data buffer too small to get length" + 5: Test case 13: expected return code to be 0 got -1 + 5: Test case 14: expected return code to be 0 got -1 + 5: Test case 15: expected last error code to be "-6" got "-38" + 5: Test case 16: expected last error code to be "-6" got "-38" + 5: Test case 17: expected last error code to be "-6" got "-38" + 5: Test case 18: expected last error code to be "-6" got "-38" + ``` + Ref: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46925869/job/i9uasceu3coss0i2#L440 + Ref: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46983040/job/c3vag25c26a77lyr#L485 + + Cherry-picked from #1037 + Closes #1037 + +- test_auth_keyboard_info_request: fix to return failure + + Before this patch, this test returned success even when one of its tests + failed. Fix it by returning 1 in case any of the tests fails. + + This issue masked a CMake build bug with logging enabled. Subject to an + upcoming patch. + + Cherry-picked from #1037 + +- test_auth_keyboard_info_request: fix indentation + + Cherry-picked from #1037 + +- tidy-up: move comment off from copyright header + + Cherry-picked from #1037 + +- ci: enable shared libs in msys2/macOS cmake builds + + Shared libs improve example/tests build times. For "unity" + builds the overhead of building shared lib is negligible, so + this even reduced the overall build-time. + + Follow-up to 3d64a3f5100f7f4cf52202396eb4f1c3f3567771 + Follow-up to d93ccf4901ef26443707d341553994715414e207 + + Tests: + https://github.com/libssh2/libssh2/actions/runs/4906586658: unity builds enabled + https://github.com/libssh2/libssh2/actions/runs/4906925743: unity builds enabled + parallel msys2 builds + https://github.com/libssh2/libssh2/actions/runs/4906777629: unity + shared lib (this commit) + https://github.com/libssh2/libssh2/actions/runs/4906927190: unity + shared lib (this commit) + parallel msys2 builds + + Consider making shared libs enabled by default also in CMake, to sync it with autotools? + + Closes #1035 + +- ci: add missed --parallel 3 from msys2 cmake builds + + Follow-up to 3d64a3f5100f7f4cf52202396eb4f1c3f3567771 + +- cmake: add and test "unity" builds + + "Unity" (aka "jumbo", aka "amalgamation" builds concatenate source files + before compiling. It has these benefits for example: faster builds, + improved code optimization, cleaner code. Let's support and test this. + + - enable unity builds for some existing CI builds to test this build + scenario. + - tune `UNITY_BUILD_BATCH_SIZE` size. + - disable unity build for example and test programs (they use one source + each already). + + You can enable it by passing `-DCMAKE_UNITY_BUILD=ON` to cmake. + Supported by CMake 3.16 and newer. + + Ref: https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html + + Closes #1034 + +- tests: simplify passing `srcdir` to tests + + Before this patch libssh2 used a variety of solutions to pass the source + directory to tests: `FIXTURE_WORKDIR` build-time macro (cmake), + `FIXTURE_WORKDIR` envvar (unused), setting `srcdir` manually + (autotools), setting current directory (cmake), and also `builddir` + envvar (autotools) for passing current working dir to `mansyntax.sh`. + + This patch reduces this to using existing `srcdir` with autotools and + setting it ourselves in CMake. This was mostly enabled by this recent + patch: 4c9ed51f962f542b98789b15bedaaa427f4029a2 + + Details: + + - cmake: replace baked-in `FIXTURE_WORKDIR` macro with env. + + Added in 54bef4c5dad868a9d45fdbfca9729b191c0abab5 #198 (2018-03-21) + + - rename `FIXTURE_WORKDIR` to `srcdir`, to match autotools. + + - cmake: add missing `srcdir` for algo and sshd tests. + + - session_fixture: stop `chdir()`-ing, rely on prefixing with `srcdir`. + + Changing current directory should be unnecessary after + 4c9ed51f962f542b98789b15bedaaa427f4029a2 #801 (2023-02-24), + that prefixes referenced input filenames with the `srcdir` envvar. + + The `srcdir` envvar was already exported by autotools, and now we're + also setting it from CMake. + + - cmake: stop setting `WORKING_DIRECTORY`, rely on `srcdir` env. + + `WORKING_DIRECTORY` is no longer necessary, after passing `srcdir` to + all tests, so they can find our source tree and keys/etc in it + regardless of the current directory. + + Also this past commit hints that `WORKING_DIRECTORY` wasn't always + working for this purpose as expected: + "tests: Xcode doesn't obey CMake's test working directory" + Ref: https://github.com/libssh2/libssh2/pull/198/commits/10a5cbf945abcc60153ee3d59284d09fc64ea152 + + - autotools: delete explicit `srcdir` for test env. + + Added in 13f8addd1bc17e6c55d52491cc6304319ac38c6d (2015-07-02) + + automake documents `srcdir` as exported to the test environment: + https://github.com/autotools-mirror/automake/blob/c04c4e8856e3c933239959ce18e16599fcc04a8b/doc/automake.texi#L9302-L9304 + https://www.gnu.org/software/automake/manual/html_node/Scripts_002dbased-Testsuites.html + It's mentioned in the docs back in 1997 and got a regression test in + 2012. We can safely assume it to be available without setting it + ourselves. + + - autotools: delete explicit `builddir`. + + Added in 13f8addd1bc17e6c55d52491cc6304319ac38c6d (2015-07-02) + + It seems this wasn't necessary to make the above fix work, and + `mansyntax.sh` is able to figure out the build workdir by reading + `$PWD`. Our out-of-tree and `make distcheck` CI builds also work + without it. + + Let us know if there is a scenario we're missing and needs this. + + Closes #1032 + +- src: fix `libssh2_store_*()` for >u32 inputs + + `_libssh2_store_str()` and `_libssh2_store_bignum2_bytes()` accept + inputs of `size_t` max, store the size as 32-bit unsigned integer, then + store the complete input buffer. + + With inputs larger than `UINT_MAX` this means the stored size is smaller + than the data that follows it. + + This patch truncates the stored data to the stored size, and now returns + a boolean with false if the stored length differs from the requested + one. Also add `assert()`s for this condition. + + This is still not a correct fix, as we now dump consistent, but still + truncated data which is not what the caller wants. In future steps we'll + need to update all callers that might pass large data to this function + to check the return value and handle an error, or make sure to not call + this function with more than UINT_MAX bytes of data. + + Ref: c3bcdd88a44c4636818407aeb894fabc90bb0ecd (2010-04-17) + Ref: ed439a29bb0b4d1c3f681f87ccfcd3e5a66c3ba0 (2022-09-29) + + Closes #1025 + +- cmake: limit WinCNG to Windows + + After deleting the `bcrypt.h` check, no check remained. Restore + a `WIN32` check here to ensure WinCNG is not enabled outside Windows. + + Follow-up to 1289033598546ee5089ff0fc4369d24e1e2be81f + + Tested-in #1032 + +- cmake: move `CMAKE_VS_GLOBALS` setting to CI configs + + To not force this setting for local builds where they might serve + a good purpose. + + It makes our CI runs slightly faster and we don't need to track + file changes in unattended, single, CI runs. + + Cherry-picked from #1031 + +- cmake: prefill for faster config phase on Windows + + Prefill known detection results on Windows with MinGW and MSVC, to + avoid spending time on detecting these on every cmake configuration + run. + + With MinGW + clang and MSVC, this elminates all detections. + With MinGW + gcc, it reduces them to 3. + + Cherry-picked from #1031 + +- libssh2_setup.h: set `HAVE_INTTYPES_H` for MSVC + + To sync up the hand-crafted config with actual detection results + by CMake and autotools. Sources compiled fine without it anyway. + + Cherry-picked from #1031 + +- cmake: re-add `select()` detection (regression) + + `select()` detection suffered two regressions: First I accidentally + deleted it for non-Windows [1]. Then the Windows-specific setting got + missed from the generated `libssh2_config.h` after a rearrangement in + `CMakeLists.txt` files. + + [1] 31fb8860dbaae3e0b7d38f2a647ee527b4b2a95f (2023-03-07) + [2] 803f19f004eb6a5b525c48fff6f46a493d25775c (2023-04-18) + + This patch restores detection. For Windows, enable it unconditionally, + not only for speed reasons, but because detection needs `ws2_32`, and + even that is broken on the x86 platform. According to the original + `cmake/SocketLibraries.cmake`, caused by a calling convention mismatch. + FWIW autotools detects it correctly. + + Cherry-picked from #1031 + +- ci: merge make job into msys2 section, enable zlib + openssl + + Follow up to dd625766271a0ba13f5ac661bdc2fa40bbfa580a + + Cherry-picked from #1030 + +- ci: add missing timeouts for autotools tests + + Cherry-picked from #1030 + +- ci: add mingw-w64 clang and gcc CMake jobs + + Cherry-picked from #1030 + +- cmake: assume `bcrypt.h` with WinCNG + + autotools already didn't check for `bcrypt.h`, and such check is only + required for old/legacy mingw without obsolete/incomplete Windows + headers. + + curl deprecated old-mingw support just recently and will delete support + in September 2023. + + This patch saves some complexity and detection time by dropping this + check for CMake. Meaning that mingw-w64 is now required to compile + libssh2 when using the WinCNG backend for 32-bit builds. Other backends + and CPU platforms are not affected. + + Ref: https://github.com/curl/curl/commit/e4d5685cb5d6eb07e1b43156fd7e3ba3563afba5 + + Closes #1026 + +- cmake: do not check for `poll()` on Windows + + While it seems to exist on mingw in theory, it's not detected as of this + writing. It also has issues, and not ready for production use: + https://stackoverflow.com/questions/1671827/poll-c-function-on-windows + + On MSVC it's even less supported. + + Skip checking this to save CMake detection time. + + Closes #1027 + +- agent_win: make a struct static and other build improvements + + Also: + - merge back `agent.h` into `agent.c` where it was earlier. + Ref: c998f79384116e9f6633cb69c2731c60d3a442bb + - introduce `HAVE_WIN32_AGENT` internal macro. + - fix two guards to exclude more code unused in UWP builds. + + Follow-up to 1c1317cb768688eee0e5496c72683190aaf63b29 + + Closes #1028 + +- tidy-up: formatting nits + + Whitespace and redundant parenthesis in `return`s. + + Closes #1029 + +GitHub (3 May 2023) +- [Nick Woodruff brought this change] + + sftp: parse attribute extensions, if present, to avoid stream parsing errors (#1019) + + Prevents directory listing errors when attribute extensions are present + by advancing stream parsing past extensions. + +Viktor Szakats (3 May 2023) +- tests: merge `sshd_fixture.sh` into `test_sshd.test` + + Merge the loop executing multiple tests and the script that actually + launches the tests into a single script. This same script is now called + from both autotools and CMake. autotools loads the list of tests from + `Makefile.inc`, CMake passes it via the command-line. It's also possible + to call the script manually with a custom list of tests or individual + ones. + + With this setup we're now launching a single sshd session for all tests, + instead of launching and killing it for each test. This did not improve + reliability of these test on CI machines, and it's easy to go back to + the previous behaviour if necessary. + + Also: + + - allow passing custom sshd options via `SSHD_FLAGS`. + + - add `SSHD_TESTS_LIMIT_TO` to limit the number of tests to its value. + E.g. `SSHD_TESTS_LIMIT_TO=1` executes the first test only. Meant for + debugging. + + - use `ssh` to test the connection (if available) instead of fixed + amount of wait. Made to also work on Windows. + + - set `PermitRootLogin yes` in `sshd`, to allow running tests as root. + + - show `sshd` path and version. + + Cherry-picked from #1017 (the last one) + Closes #1024 + +- ci: make sure to run tests after all builds in GHA + + Whenever possible. Due to flakiness/hangs/timeouts, keep sshd + tests disabled on Windows and macOS. + + Also keep Docker tests disabled on these platforms, they do not work: + + GHA Windows: + ``` + no matching manifest for windows/amd64 in the manifest list entries + ``` + + GHA macOS: + ``` + sh: docker: command not found + ``` + + It's not possible to run UWP and ARM64 binaries: + UWP: + ``` + Test #2: test_simple ......................Exit code 0xc0000135 + ``` + Needs but doesn't find: `VCRUNTIME140_APP.dll`. + + ARM64 + ``` + D:/a/libssh2/libssh2/bld/tests/Release/test_ssh2.exe: cannot execute binary file: Exec format error + ``` + + Cherry-picked from #1017 + +- tests: disable sshd tests on Windows via new options + + Instead of using hacks inside the build systems. + + `SSHD` variable added to GitHub Actions is not currently used. + Added there to make it easy to experiment with these tests and + the path is non-trivial to discover. Using the Windows built-in + sshd server is another option (haven't discovered its path yet). + + Cherry-picked from #1017 + +- tests: add cmake/autotools options to disable running tests + + autotools: + - `--disable-docker-tests` + - `--disable-sshd-tests` + + cmake: + - `RUN_DOCKER_TESTS` + - `RUN_SSHD_TESTS` + + Update automake and ci to use this new flag and delete former logic + of relying on Windows detection and `HOST_WINDOWS`. Also fix honoring + this when running `test_read_algos.test`. + + This allows to disable these individually and on per-CI/local-job basis. + To run as much tests as the env allows. + + Cherry-picked from #1017 + +- ci: add `make distcheck` job + + Cherry-picked from #1017 + +- ci: switch to out-of-tree autotools builds + + Cherry-picked from #1017 + +- ci: restore parallel builds with cmake + + Also add missing -j3 for macOS builds. + + Partial revert of 0d08974633cfc02641e6593db8d569ddb3644255 + + Cherry-picked from #1017 + +- ci: sync names, steps, syntax, build dirname between jobs + + Also: + + - delete an unused 64-bit option for Linux (all jobs are 64-bit). + + - fix to not install libgcrypt and openssl when doing mbedTLS builds. + + [ Empty lines after multiline run commands are solely to unbreak + my editor's syntax highlighting. They can be deleted in the future ] + + Cherry-picked from #1017 + +- ci: add `Makefile.mk` test, with `LIBSSH2_NO_*` options + + Cherry-picked from #1017 + +- Makefile.mk: use Makefile.inc from example and tests + + Instead of assembling the list using `$(wildcard ...)`. + + Also split off a `tests/Makefile.inc` from `tests/Makefile.am`. With its + simpler syntax, this also allows to delete some complexity from the + CMake loader. + + Cherry-picked from #1017 + +- example, tests: fix ssh2 to correctly return failure + + Before this patch ssh2 and test_ssh2 returned success even if the session + failed at `libssh2_session_handshake()` or after. + + This patch depends on cda41f7cb87c3af5258ba48ccef19d3efdbd3d3b, that fixed + running test_ssh2 on Windows via sshd_fixture. + + Cherry-picked from #1017 + +- tests: set -e -u in shell scripts + + Cherry-picked from #1017 + +- cmake: use shared libs again in example and tests + + Re-sync with autotools and v1.10.0 behavior. + + This improves build times. It also allows to stop building our special + shared test target to test shared builds. + + Follow-up to 4e2580628dd1f8dc51ac65ac747ebcf0e93fa3d1 + + Cherry-picked from #1017 + Closes #1022 + +- tests: retry KEX failures when using the WinCNG backend + + Twice. This tests are flaky and we haven't figured out why. In the + meantime use this workaround to test and log these issues, but also + ensure that CI run aren't flagged red because of it. + + Also: + - kex: add debug message when hostkey `sig_verify` fails, + to help tracking WinCNG KEX failures. + - test_ssh2: also add retry logic. + I'm not quite sure this is correct. Please let me know. + - session_fixture: bump up `src_path` slots to fit retries and show + message when hitting the limit. + - session_fixture: clear `kbd_password` static variable after use. + - session_fixture: close and deinit socket after use. + - session_fixture: deinit libssh2 after use. + + Ref: #804 #846 #979 #1012 #1015 + + Cherry-picked from #1017 + Closes #1023 + +- example, test_ssh2: shutdown socket before close + + Syncing them with `tests/session_fixture.c`. + + Cherry-picked from #1017 + +- ci.yml: fix indentation [ci skip] + + Cherry-picked from #1017 + +- Makefile.mk: make tests depend on runner lib + + Cherry-picked from #1017 + +- build: compile agent_win.c via agent.c + + Silences these warnings on non-Windows: + ``` + ranlib: file: libssh2.a(agent_win.c.o) has no symbols + ``` + + Cherry-picked from #1017 + +- cmake: delete obsolete comment + + Follow-up to 80175921638fa0a345237d23206a2ad1644cdd9b + + Cherry-picked from #1017 + +- checksrc.sh: fix it to run from any current directory + + Also silence a shellcheck warning. + + Cherry-picked from #1017 + +- ISSUE_TEMPLATE: ask for crypto backend version + + Also fix casing in backend names. + + Cherry-picked from #1017 + +- tests: fix newlines in test keys for sshd on Windows + + Make sure these files get LF newlines on checkout. Before this patch + a checked out libssh2 Git repository may have used CRLF newlines in text + files, include test keys. Private keys with CRLF newlines could confuse + sshd on Windows: + + ``` + # sshd version: 'OpenSSH_9.2, OpenSSL 1.1.1t 7 Feb 2023' + Unable to load host key "/d/a/libssh2/libssh2/tests/openssh_server/ssh_host_ed25519_key": invalid format + Unable to load host key: /d/a/libssh2/libssh2/tests/openssh_server/ssh_host_ed25519_key + ``` + Ref: https://github.com/libssh2/libssh2/actions/runs/4846188677/jobs/8635575847#step:6:39 + + Cherry-picked from #1017 + +- cmake: move option descriptions next to definition + + Cherry-picked from #1017 + +- checksrc: sync with curl + + There were no new issues detected. + + Cherry-picked from #1017 + +- openssl: enable AES-GCM with wolfSSL + + Follow-up to 3c953c05d67eb1ebcfd3316f279f12c4b1d600b4 #797 + + There is pending issue with wolfSSL, where encryption/decryption is not + working (both with and without this patch). Ref: #1020 + + Cherry-picked from #1017 + +- appveyor: add a UWP OpenSSL 3 build + + Cherry-picked from #1017 + +- appveyor: skip `before_test` when not doing tests + + Also merge `before_test` section into `test_script`. + + Cherry-picked from #1017 + +- docs: delete two stray characters + + Cherry-picked from #1017 + +- tidy-up: avoid expression 'of course' + + Cherry-picked from #1017 + +- tidy-up: avoid word 'just' + + Cherry-picked from #1017 + +- tidy-up: avoid word 'simply' + + Cherry-picked from #1017 + +- tests: teach to use the `USERNAME` envvar on Windows + + Necessary to pick the correct local username when run on Windows. + + Cherry-picked from #1017 + +- test_ssh2: support `FIXTURE_TRACE_ALL*` envvars + + Cherry-picked from #1017 + +- tidy-up: add missing newline to error msg, formatting + + Also: + - fix indent + - lowercase variables names + - fix formatting in `src/global.c` + + Cherry-picked from #1017 + +- appveyor: wait more for SSH connection from GHA + + Cherry-picked from #1017 + +- ci: restrict permissions in GitHub Actions + + Cherry-picked from #1017 + +- build: fix autoreconf warnings + + - update `AC_HELP_STRING' to 'AS_HELP_STRING`: + ``` + configure.ac:[...]: warning: The macro `AC_HELP_STRING' is obsolete. + ``` + "AC_HELP_STRING is deprecated in 2.70+ and I believe AS_HELP_STRING works + already since 2.59 so bump the minimum required version to that." + + Ref: https://github.com/curl/curl/commit/a59f04611629f0db9ad8e768b9def73b9b4d9423 + + - simplify to avoid: + ``` + src/Makefile.inc:48: warning: variable 'EXTRA_DIST_SOURCES' is defined but no program or + src/Makefile.inc:48: library has 'DIST' as canonical name (possible typo) + ``` + Regression from 2c18b6fc8df060c770fa7e5da704c32cf40a5757 + + - `AC_TRY_LINK`/`AC_TRY_COMPILE`: + ``` + configure.ac:335: warning: The macro `AC_TRY_COMPILE' is obsolete. + configure.ac:335: warning: The macro `AC_TRY_LINK' is obsolete. + ``` + + - `libtool`-related ones: + ``` + configure.ac:70: warning: The macro `AC_LIBTOOL_WIN32_DLL' is obsolete. + configure.ac:70: warning: AC_LIBTOOL_WIN32_DLL: Remove this warning and the call to _LT_SET_OPTION when you + configure.ac:70: put the 'win32-dll' option into LT_INIT's first parameter. + configure.ac:71: warning: The macro `AC_PROG_LIBTOOL' is obsolete. + ``` + Using code copied from curl: + https://github.com/curl/curl/blob/9ce7eee07042605045dcfd02a6f5b38ad5c8a05d/m4/xc-lt-iface.m4#L157-L163 + + - delete commented and obsolete `AC_HEADER_STDC`. + + - formatting. + + Most cherry-picked from `autoupdate` updates. + + Cherry-picked from #1017 + Closes #1021 + +- docker-bridge.ps1: use native newlines + + Also add a shebang and exec flag to ease testing/handling on *nix. + PowerShell accepts both LF and CRLF. + + Cherry-picked from #1017 + +GitHub (1 May 2023) +- [Zenju brought this change] + + sftp: remove packet limit for directory reading (#791) + + Currently libssh2 cannot read huge directory listings when the package + size of `LIBSSH2_SFTP_PACKET_MAXLEN` (256KB) is hit. For example AWS + always sends a single package with all files of a directory, no matter + how big it is: https://freefilesync.org/forum/viewtopic.php?t=10020 + Package size is probably around 7MB in this case! + + `LIBSSH2_SFTP_PACKET_MAXLEN` is a good idea in general, but there + doesn't seem to be a one size fits all. While almost all(?) SFTP + responses come in very small packages, I believe the `SSH_FXP_READDIR` + request should be exempted. + + The proposed patch, enhances the package size reading to include parsing + the full SFTP packet header. And in case a package is of type + `SSH_FXP_NAME` and matches an expected `readdir_request_id`, it does not + fail if `LIBSSH2_SFTP_PACKET_MAXLEN` is hit. The chances of accidentally + hiding data-corruption are pretty non-existent, because both SFTP + `request_id` and packet type must match. No change in behavior + otherwise. + + Best, Zenju + + Previous discussion: #268 #269 + + With the above changes, the `LIBSSH2_SFTP_PACKET_MAXLEN` value could + (and should?) probably be set back to a small number again. + + Integration-patches-by: Viktor Szakats + +Viktor Szakats (28 Apr 2023) +- checksrc: update and apply fixes + + Update to latest revision and fix new issues detected. + + Closes #1014 + +- ci: add macOS CI jobs + fix issues revealed + + Add macOS CI jobs, both cmake and autotools for all supported crypto + backends (except BoringSSL), with debug, zlib enabled. Without running + tests. It also introduces OpenSSL 1.1 into the CI with a non-MSVC + compiler. + + Credits to curl's `macos.yml`, that I used as a base. + + Fix these issues uncovered by the new tests: + + - openssl: fix warning when built with wolfSSL, or OpenSSL 1.1 and + earlier. CI missed it because apparently the only OpenSSL 1.1 test + we had used MSVC, which did not complain. + + ``` + ../src/openssl.c:3852:19: error: variable 'sslError' set but not used [-Werror,-Wunused-but-set-variable] + unsigned long sslError; + ^ + ``` + + Regression from 097c8f0dae558643d43051947a1c35b65e1c5761 + + - pem: add hack to build without MD5 crypto-backend support. + + The Homebrew wolfSSL build comes with MD5 support disabled. We can + expect this becoming the norm. FIPS also requires MD5 disabled. + + We deleted the same hack from `hostkey.c` a month ago: + ad6aae302aaec84afbfacf0c1dfdc446d46eaf21 + + A better fix would be to guard the MD5 logic with our `LIBSSH2_MD5` + macro. + + ``` + pem.c:214:32: error: use of undeclared identifier 'MD5_DIGEST_LENGTH'; did you mean 'SHA_DIGEST_LENGTH'? + unsigned char secret[2*MD5_DIGEST_LENGTH]; + ^~~~~~~~~~~~~~~~~ + SHA_DIGEST_LENGTH + ``` + + Regression from 386e012292a96fcf0dc6861588397845df0aba2c + + - `configure.ac`: add crypto libs late. + + Fix it by adding crypto libs to `LIBS` at the end of the configuration + process. + + Otherwise `configure` links crypto libs while doing feature tests, + which can cause unwanted detections. For example LibreSSL publishes + the function `explicit_bzero()`, which masks the system alternative, + e.g. `memset_s()` on macOS. Then when trying to compile libssh2, its + declaration is missing: + + ``` + bcrypt_pbkdf.c:93:5: error: implicit declaration of function 'explicit_bzero' is invalid in C99 [-Werror,-Wimplicit-function-declaration] + _libssh2_explicit_zero(ciphertext, sizeof(ciphertext)); + ^ + ../src/misc.h:50:43: note: expanded from macro '_libssh2_explicit_zero' + ^ + ``` + + Regression from 4f0f4bff5a92dce6a6cd7a5600a8ee5660402c3f + + - cmake: fix to list our own include directory before the crypto libs', + when building tests. + + Otherwise a global crypto header path, such as `/usr/local/include`, + containing an external `libssh2.h` of a different version, could cause + weird errors: + + ``` + cc -DHAVE_CONFIG_H -DLIBSSH2_LIBGCRYPT \ + -I../src -I../../src -I/usr/local/include -I[...]/libssh2/include \ + -g -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.1.sdk \ + -mmacosx-version-min=12.6 -MD -MT \ + tests/CMakeFiles/test_aa_warmup.dir/test_aa_warmup.c.o \ + -MF CMakeFiles/test_aa_warmup.dir/test_aa_warmup.c.o.d \ + -o CMakeFiles/test_aa_warmup.dir/test_aa_warmup.c.o -c \ + [...]/libssh2/tests/test_aa_warmup.c + ``` + + ``` + [ 62%] Building C object tests/CMakeFiles/test_aa_warmup.dir/test_aa_warmup.c.o + In file included from /Users/runner/work/libssh2/libssh2/tests/test_aa_warmup.c:4: + In file included from /Users/runner/work/libssh2/libssh2/tests/runner.h:42: + In file included from /Users/runner/work/libssh2/libssh2/tests/session_fixture.h:43: + /Users/runner/work/libssh2/libssh2/tests/../src/libssh2_priv.h:649:5: error: type name requires a specifier or qualifier + LIBSSH2_AUTHAGENT_FUNC((*authagent)); + ^ + /Users/runner/work/libssh2/libssh2/tests/../src/libssh2_priv.h:649:30: error: type specifier missing, defaults to 'int' [-Werror,-Wimplicit-int] + LIBSSH2_AUTHAGENT_FUNC((*authagent)); + ^ + /Users/runner/work/libssh2/libssh2/tests/../src/libssh2_priv.h:650:5: error: type name requires a specifier or qualifier + LIBSSH2_ADD_IDENTITIES_FUNC((*addLocalIdentities)); + ^ + /Users/runner/work/libssh2/libssh2/tests/../src/libssh2_priv.h:650:35: error: type specifier missing, defaults to 'int' [-Werror,-Wimplicit-int] + LIBSSH2_ADD_IDENTITIES_FUNC((*addLocalIdentities)); + ^ + /Users/runner/work/libssh2/libssh2/tests/../src/libssh2_priv.h:651:5: error: type name requires a specifier or qualifier + LIBSSH2_AUTHAGENT_SIGN_FUNC((*agentSignCallback)); + ^ + /Users/runner/work/libssh2/libssh2/tests/../src/libssh2_priv.h:651:35: error: type specifier missing, defaults to 'int' [-Werror,-Wimplicit-int] + LIBSSH2_AUTHAGENT_SIGN_FUNC((*agentSignCallback)); + ^ + 6 errors generated. + ``` + + - `tests/session_fixture.h`: delete duplicate `libssh2.h`, + `libssh2_priv.h` already includes it. + + Follow-up to a683133dfe96de126194f58f183131a84c7d36a2 + + CI logs with these errors: + https://github.com/libssh2/libssh2/actions/runs/4824079094 + https://github.com/libssh2/libssh2/actions/runs/4824270819 + + curl's `macos.yml`: https://github.com/curl/curl/blob/da2470de96e94e1c8d276b9ae6e4c97c2cf54239/.github/workflows/macos.yml + + Tidying-up while here: + + - tests/session_fixture.h: delete duplicate `libssh2.h`. + `libssh2_priv.h` includes it already. + + Follow-up to a683133dfe96de126194f58f183131a84c7d36a2 + + - ci.yml: yamllint warnings and formatting. + + - ci.yml: msvc section formatting and step-naming sync with macOS. + + Follow-up to f4a4c05dc3bcd62ecaa1b0cac5997faefe16c83f + + - ci.yml: enable `--enable-werror` for msys2 jobs. + + Follow-up to 71cae949d577fdd632a271da0bec89f977dc5dd2 + + - appveyor.yml: show OpenSSL versions, link to image content. + + Closes #1013 + +- ci: convert `docker-bridge.bat` to shell script + + Convert `ci/appveyor/docker-bridge.bat` to a POSIX shell script. + + Also bump the tunnel to use ed25519 (was RSA-2048). + + Closes #997 + +- kex: use distinctive error strings + + Use unique error strings to help localize errors. + + Closes #1011 + +- tidy-up: C header use + + - drop unused or duplicate C headers. + - add missing ones (that worked by chance). + (`string.h`, `stdlib.h`) + - mention the functions that need certain headers. + - move some headers from crypto header to crypto C source. + - reorder headers in some places. + - simplify the #if tree for `sys/select.h` in `libssh2_priv.h`. + - move scp-specific macros next to their header to `scp.c` + Follow-up to 5db836b2a829c6fff1e8c7acaa4b21b246ae1757 + + Closes #999 + +- tidy-up: text nits, English contractions [ci skip] + + In input/output text and docs mostly. + +- ci: add MSVC and UWP builds to GitHub Actions + + - add MSVC jobs to GitHub Actions. They are similar to the 'Build-only' + jobs we have on AppVeyor CI, though only the ARM64 Windows one is + identical. Major disadvantage is that we don't run tests here. Major + advantage is they only take a few minutes to complete, compared to + an hour on AppVeyor, so WinCNG build results now appear quicker. + + Docker tests might be possible, but my light attempts failed. + Finding ZLIB also failed, so we still miss an MSVC test with it. + + Tool versions as of now: Server 2022, VS2022, OpenSSL 1.1.1 + + - add UWP builds for both ARM64 and x64. This hasn't been CI tested + before. + + (We could probably enable UWP on AppVeyor CI as well. + I haven't tried.) + + - fix two uncovered UWP issues in tests. + + - rename internal macro `LIBSSH2_WINDOWS_APP` to `LIBSSH2_WINDOWS_UWP`. + + Follow-up to 2addafb77b662e64248d156c71c69b91ba7b926e + + - fold long lines and quote truthy values in `.github/workflows/ci.yml`. + + Closes #1010 + +- session_fixture: avoid no-op `chdir(getcwd())` + + If no `FIXTURE_WORKDIR` macro or envvar is present to set the cwd, + avoid querying the cwd and then calling chdir with the result. + + Ref: 54bef4c5dad868a9d45fdbfca9729b191c0abab5 (patch) + Ref: 10a5cbf945abcc60153ee3d59284d09fc64ea152 (individual commit) + + Closes #1009 + +- tests/sshd_fixture.sh: convert back to POSIX + + There was no strong reason to require bash. Let's use POSIX shell + like before the recent overhaul. + + Follow-up to a459a25302a31f6e2aba3c4e15b1472b83b596fc + + Closes #1008 + +GitHub (26 Apr 2023) +- [Miguel de Icaza brought this change] + + If SFTP fails to initialize, do not busy loop waiting for IO to happen (#720) + + Currently SFTP's init will busy loop waiting for the channel to close, + even if the underlying transport returns EAGAIN. While this works for + sockets, it might not work out if you have a different transport that + needs to do some additional processing on the side. + + Integration-patches-by: Viktor Szakats + +Viktor Szakats (26 Apr 2023) +- docs: simplify `.TH` header & other cleanups [ci skip] + + - simplify `.TH` headers. + - delete empty lines before sections. + - update template with an `AVAILABILITY` section. + + Left libssh2 version number in the `.TH` header for entries without an + `AVAILABILITY` section, or where there was a different version number + there. + +- tidy-up: formatting nits [ci skip] + +- vms: fix to include `sys/socket.h` + + Due to a typo in the `HAVE_*` macro, this header was never included. + + A comment suggests that `socklen_t` is not defined on VMS and defines it + manually. This symbol is usually in `sys/socket.h`, so the typo may have + been the reason for it to be missing. + + Closes #1007 + +- build: fix `make distcheck` regressions + + - add #included C files to `EXTRA_DIST`. + + Regression from 4f0f4bff5a92dce6a6cd7a5600a8ee5660402c3f + + - fix `tests/sshd_fixture.sh` to not write into the test dir, by using + a pre-assembled `TrustedUserCAKeys` file. Update `Dockerfile` too to + use this. + + Regression from a459a25302a31f6e2aba3c4e15b1472b83b596fc + + Also update `tests/sshd_fixture.sh` to use + `openssh_server/authorized_keys` like `Dockerfile` does. And a few more + cosmetic updates. + + Closes #1006 + +- libssh2_priv.h: assume `HAVE_LONGLONG` + + Unless I'm missing something, it looks like `libssh2.h` has been using + `libssh2_int64_t` unconditionally since at least 2010-04-17 when + `libssh2_scp_send64()` landed via commit + be9ee7095e2d5021985f57d88f5f889d3c2b9d8f. + + This makes it redundant to detect `HAVE_LONGLONG` to fallback to a + 32-bit `scpRecv_size` in `libssh2_priv.h`. Then deal with possible + combinations of this flag and `strtoll()` options, which was + error-prone. + + Instead, assume in `libssh2_priv.h` that we have `libssh2_int64_t`, and + use it always. + + For MSVC, this means `_MSC_VER` `1310` (from year 2003) is now + required. Based on the above, this was already so before this patch. + + If there happens to be no 64-bit `strtoll()` detected, fall back to the + 32-bit `strtol()` (this should never happen with MSVC, and probably + neither with any other reasonably modern toolchain.) + + Also make sure to set `HAVE_STRTOI64` for older, non-CMake, MSVC builds + (e.g. `Makefile.mk` or `NMakefile` ones). + + Closes #1002 + +GitHub (26 Apr 2023) +- [Miguel de Icaza brought this change] + + fix a couple of small regressions (#1004) + + - openssl: fix potentially missing `ERR_*` constants by including + `openssl/err.h`. This could happen with recent version of Xcode + or when building against OpenSSL built with the `OPENSSL_NO_ENGINE` + option. + + Regression from 097c8f0dae558643d43051947a1c35b65e1c5761 (#789) + + - channel: fix an issue that would corrupt the data stream when + attempting to initialize the agent in non-blocking mode, as it is + necessary to propagate the `EAGAIN` signal upstream when the transport + returns `EAGAIN`. + + Regression from bc4e619e76071393e466c29220fc4ef5764c2820 (#752) + + - packet: the current code does not set the state machine upon reaching + this point which means that if the code is suspended due to the + transport returning an `EAGAIN`, this will re-initialize the structure + every time. + + The issue is that this keeps assigning a new channel-id downstream, + which does not match the initial channel-id that is initially + generated, causing a lookup later to fail as there is no matching + channel. + + Regression from bc4e619e76071393e466c29220fc4ef5764c2820 (#752) + +Viktor Szakats (26 Apr 2023) +- tidy-up: `gettimeofday()` fallback and use + + Simplify the way we handle `gettimeofday()` fallback for platforms + without native support or without any support. Make it similar to + how we handle `snprintf()`. + + In case of no native `gettimeofday()` support and a non-Windows + platform, our local fallback returns zero in `tv_usec` and `tv_sec`, + ending up with a zero `timeout_remaining` in `session.c`, same as + before this patch. + + Also: + - drop unused `sys/time.h` headers. + - fix our fallback code to compile with any Windows compilers + (not just MSVC) + - delete unnecessary casts. + + Closes #1001 + +- libssh2_priv.h: fix checksrc warning [ci skip] + + Regression from 9ef75298fae0728305d9d38ba1e3c838ad0513f7 + +- libssh2_priv.h: whitespace fixes cont. [ci skip] + +- libssh2_priv.h: whitespace fixes [ci skip] + +- cmake: use portable mkdir for tests/coverage target [ci skip] + + Makes `make coverage` work without a POSIX mkdir. + + Tested locally. + + Ref: https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake-E-arg-make_directory + +- kex: fix overlapping memcpy() to memmove() + + Noticed this when libasan started kicking out errors when sending in + MACs preferences that were not supported yet. + + Reported-by: fourierules on github + Fixes #611 + Closes #1000 + +- test/CMakeLists.txt: reuse `Makefile.am` librunner source list + + Follow-up to a459a25302a31f6e2aba3c4e15b1472b83b596fc + + Closes #998 + +GitHub (25 Apr 2023) +- [Zenju brought this change] + + openssl: fix misleading error message if wrong passphrase (#789) + + Fixes #608 + +Viktor Szakats (25 Apr 2023) +- tidy-up: tiny nits [ci skip] + +- tests: improve running tests + + TL;DR: Sync test builds between autotools and CMake. Sync sshd + configuration between Docker and non-Docker fixtures. Bump up + sshd_config for recent OpenSSH releases. + + This also opens up the path to have non-Docker tests that use a + local sshd process. Though sshd is practically unusable on Windows + CI machines out of the box, so this will need further efforts. + + Details: + + - cmake: run sshd fixture test just like autotool did already. + + - sync tests and their order between autotools and CMake. + + It makes `test_aa_warmup` the first test with both. + + - cmake: load test lists from `Makefile.am`. + + Needed to update the loader to throw away certain lines to keep the + converted output conform CMake syntax. Using regexp might be an + alternative way of doing this, but couldn't make it work. + + - cmake: use the official way to configure test environment variables. + Switch to syntax that's extendable. + + - cmake: allow to run the same test both under Docker and sshd fixture. + + Useful for testing the sshd fixture runner, or how the same test + behaves in each fixture. + + - update test fixture to read the username from `USER` envvar instead of + using the Dockfile-specific hardwired one, when running outside Docker. + + - rework `ssh2.sh` into `sshd_fixture.sh`, to: + + - allow running any tests (not just `test_ssh2`). + - configure Docker tests for running outside Docker. + - fixup `SSHD` path when running on Windows (e.g. in AppVeyor CI). + Fixes: `sshd re-exec requires execution with an absolute path` + - allow overriding `PUBKEY` and `PRIVKEY` envvars. + - allow overriding `ssh_config` via `SSHD_FIXTURE_CONFIG`. + + - prepare support for running multiple tests via sshd_fixture. + + Add a TAP runner for autotools and extend CMake logic. The TAP runner + loads the test list from `Makefile.am`. + + Notice however that on Windows, `sshd_fixture.sh` is very flaky with + GitHub Actions. And consistently broken for subsequent tests in + AppVeyor CI: + 'libssh2_session_handshake failed (-43): Failed getting banner' + + Another way to try is a single sshd instance serving all tests. + For CMake this would probably mean using an external script. + + - ed25519 test keys were identical for auth and host. Regenerate the + auth keypair to make them distinct. + + - sync the sshd environment between Docker and sshd_fixture. + + - use common via `openssh_server/sshd_config`. + - accept same auth keys. + - offer the same host keys. + - sync TrustedUserCAKeys. + - delete now unused keypairs: `etc/host*`, `etc/user*`. + - bump up startup delay for Windows (randomly, to 5 secs, from 3). + - delete `UsePrivilegeSeparation no` to avoid deprecation warnings. + `command-line line 0: Deprecated option UsePrivilegeSeparation` + - delete `Protocol 2` to avoid deprecation warnings. + It has been the default since OpenSSH 3.0 (2001-11-06). + - delete `StrictModes no` (CI tests work without it, Docker tests + never used it). + + - bump `Dockerfile` base image to `testing-slim` (from `bullseye-slim`). + + It needed `sshd_config` updates to keep things working with + OpenSSH 9.2 (compared to bullseye's 8.4). + + - replace `ChallengeResponseAuthentication` alias with + `KbdInteractiveAuthentication`. + The former is no longer present in default `sshd_config` since + OpenSSH 8.7 (2021-08-20). This broke the `Dockerfile` script. + The new name is documented since OpenSSH 4.9 (2008-03-31) + + - add `PubkeyAcceptedKeyTypes +ssh-rsa,ssh-dss,ssh-rsa-cert-v01@openssh.com` + and `HostKeyAlgorithms +ssh-rsa`. + + Original-patch-by: Eric van Gyzen (@vangyzen on github) + Fixes #691 + + There is a new name for `PubkeyAcceptedKeyTypes`: + `PubkeyAcceptedAlgorithms`. + It requires OpenSSH 8.5 (2021-03-03) and breaks some envs so we're + not using it just yet. + + - drop `rijndael-cbc@lysator.liu.se` tests and references from config. + + This is a draft alias for `aes256-cbc`. No need to test it twice. + Also this alias is no longer recognized by OpenSSH 8.5 (2021-03-03). + + - update `mansyntax.sh` and `sshd_fixture.sh` to not rely on `srcdir`. + + Hopefully this works with out-of-tree builds. + + - fix `test_read_algos.test` to honor CRLF EOLs in their inputs + (necessary when running on Windows.) + + - fix `test_read_algos.test` to honor `EXEEXT`. Might be useful when + running tests under cross-builds? + + - `test_ssh2.c`: + + - use libssh2 API to set blocking mode. This makes it support all + platforms. + - adapt socket open timeout logic from `openssh_fixture.c`. + Sadly this did not help fix flakiness on GHA Windows. + + - tests: delete unused C headers and variable initialization. + + - delete unused test files: `sshd_fixture.sh.in`, `sshdwrap`, + `etc/sshd_config`. + + Ref: cf80f2f4b5255cc85a04ee43b27a29c678c1edb1 + + - autotools: delete stray `.c` test sources from `EXTRA_DIST` in tests. + + - `tests/.gitignore`: drop two stray tests. + + - autotools: fix passing `SSHD` containing space (Windows needs this). + + - autotools: sort `EXTRA_DIST` in tests. + + - cmake: fix to add `test_ssh2` to `TEST_TARGETS`. + + - fix `authorized_key` order in `tests/gen_keys.sh`. + + - silence shellcheck warning in `ci/checksrc.sh`. + + - set `SSHD` for autotools on GitHub Actions Windows. [skipped] + + Auto-detection doesn't work (maybe because sshd is installed via + Git for Windows and we're using MSYS2's shell.) + + It enables running sshd fixture (non-Docker) tests in these jobs. + + I did not include this in the final patch due to flakiness: + ``` + Connection to 127.0.0.1:4711 attempt #0 failed: retrying... + Connection to 127.0.0.1:4711 attempt #1 failed: retrying... + Connection to 127.0.0.1:4711 attempt #2 failed: retrying... + Failure establishing SSH session: -43 + ``` + + Can be enabled with: + `export SSHD='C:/Program Files/Git/usr/bin/sshd.exe'` + + Closes #996 + +- ci: reduce algo test runtime on AppVeyor + + Make the block count customizable in `test_read` via environment + `FIXTURE_XFER_COUNT`. + + Set the custom count lower than the default when running on AppVeyor. + + The goal is to reduce CI roundtrip times. + + Closes #995 + +GitHub (22 Apr 2023) +- [Michael Buckley brought this change] + + Agent forwarding implementation (#752) + + This PR contains a series of patches that date back many years and I + believe were discussed on the mailing list, but never merged. We have + been using these in our local copy of libssh2 without issue since 2015, + if not earlier. I believe this is the full set of changes, as we tried + to use comments to mark where our copy of libssh2 differs from the + canonical version. + + This also contains changes I made earlier this year, but which were not + discussed on the mailing list, to support certificates and FIDO2 keys + with agent forwarding. + + Note that this is not a complete implementation of agent forwarding, as + that is outside the scope of libssh2. Clients still need to provide + their own implementation that parses ssh-agent methods after calling + libssh2_channel_read() and calls the appropriate callback messages in + libssh2. See the man page changes in this PR for more details. + + Integration-patches-by: Viktor Szakats + + * prefer size_t + * prefer unsigned int over u_int in public function + * add const + * docs, indent, checksrc, debug call, compiler warning fixes + +Viktor Szakats (21 Apr 2023) +- ci: add Windows Server 2016 into the test mix + + We had Windows Server 2012 R2 (8.1) and Windows Server 2019 (10) before + this patch. After, we also have Windows Server 2016 (10). + + The WinCNG flakey tests should have a better chance when running on the + newer OS. + + This update does not change the compiler mix. + + Also change the test fixture to not use the `--quiet` option with the + `docker pull` commant. This option requires docker v19.03, and + AppVeyor's Visual Studio 2017 image doesn't support it. Log output did + not change without `--quiet`, so it seems safe to delete it. In case + we'd need it, another solution is to retry without `--quiet` if the + command fails. docker's exit status is 125 in that case. + + Ref: https://github.com/libssh2/libssh2/issues/804#issuecomment-1515232799 + Ref: https://www.appveyor.com/docs/windows-images-software/ + + Closes #994 + +- build: add autotools test_read support and more + + Keep a single list for mac and crypt algos that we use in both CMake + and autotools. Use the same test names across build tools. + + Use the TAP protocol to track individual tests run from a single shell + script. + + Also: + + - enable the rest of our tests with autotools. + + - set `make check` verbose to see errors in case they happen. + + - silence stray 'command not found' error when running `mansyntax.sh` + on Windows. + + GitHub Actions Windows docker tests disabled due to: + ``` + Command: docker build --quiet -t libssh2/openssh_server ../tests/openssh_server + Error running command 'docker build --quiet -t libssh2/openssh_server ../tests/openssh_server' (exit 1): Sending build context to Docker daemon 22.02kB + Step 1/42 : FROM debian:bullseye-slim + bullseye-slim: Pulling from library/debian + no matching manifest for windows/amd64 10.0.20348 in the manifest list entries + Failed to build docker image + ``` + + Closes #993 + +- cmake: restore a dash char in comment [ci skip] + + It's a CMake comment header convention. + +GitHub (21 Apr 2023) +- [Dan Fandrich brought this change] + + tests: add AES-GCM protocol read tests (#992) + + Closes #992 + +- [Viktor Szakats brought this change] + + support encrypt-then-mac (etm) MACs (#987) + + Support for calculating MAC (message authentication code) on encrypted + data instead of plain text data. + + This adds support for the following MACs: + - `hmac-sha1-etm@openssh.com` + - `hmac-sha2-256-etm@openssh.com` + - `hmac-sha2-512-etm@openssh.com` + + Integration-patches-by: Viktor Szakats + + * rebase on master + * fix checksec warnings + * fix compiler warning + * fix indent/whitespace/eol + * rebase/manual merge onto AES-GCM patch #797 + * more manual merge of `libssh2_transport_send()` based + on dfandrich/shellfish + + Fixes #582 + Closes #655 + Closes #987 + +Viktor Szakats (20 Apr 2023) +- docs: fix typo in argument name [ci skip] + +- [Keith Dart brought this change] + + channel: add support for "signal" message + + Can send specific signals to remote process. Allows for slightly + improved remote process management, if the server supports it. + + Integration-patches-by: Viktor Szakats + + * doc updates + * change `signame_len` to `size_t` + * variable scopes + * fix checksrc warnings + + Closes #672 + Closes #991 + +- crypto: add `LIBSSH2_NO_AES_CBC` option + + Also rename internal `LIBSSH2_AES` to `LIBSSH2_AES_CBC`. + + Follow-up to 857e431648df6edcb3e17138d877f2e65d2d769d + + Closes #990 + +- tidy-up: indentation fixes [ci skip] + +GitHub (20 Apr 2023) +- [Dan Fandrich brought this change] + + Add support for AES-GCM crypto protocols (#797) + + Add support for aes256-gcm@openssh.com and aes128-gcm@openssh.com + ciphers, which are the OpenSSH implementations of AES-GCM cryptography. + It is similar to RFC5647 but has changes to the MAC protocol + negotiation. These are implemented for recent versions of OpenSSL only. + + The ciphers work differently than most previous ones in two big areas: + the cipher includes its own integrated MAC, and the packet length field + in the SSH frame is left unencrypted. The code changes necessary are + gated by flags in the LIBSSH2_CRYPT_METHOD configuration structure. + + These differences mean that both the first and last parts of a block + require special handling during encryption. The first part is where the + packet length field is, which must be kept out of the encryption path + but in the authenticated part (as AAD). The last part is where the + Authentication Tag is found, which is calculated and appended during + encryption or removed and validated on decryption. As encryption/ + decryption is performed on each packet in a loop, one block at a time, + flags indicating when the first and last blocks are being processed are + passed down to the encryption layers. + + The strict block-by-block encryption that occurs with other protocols is + inappropriate for AES-GCM, since the packet length shifts the first + encrypted byte 4 bytes into the block. Additionally, the final part of + the block must contain the AES-GCM's Authentication Tag, so it must be + presented to the lower encryption layer whole. These requirements mean + added code to consolidate blocks as they are passed down. + + When AES-GCM is negotiated as the cipher, its built-in MAC is + automatically used as the SSH MAC so further MAC negotiation is not + necessary. The SSH negotiation is skipped when _libssh2_mac_override() + indicates that such a cipher is in use. The virtual MAC configuration + block mac_method_hmac_aesgcm is then used as the MAC placeholder. + + This work was sponsored by Anders Borum. + + Integration-patches-by: Viktor Szakats + + * fix checksrc errors + * fix openssl.c warning + * fix transport.c warnings + * switch to `LIBSSH2_MIN/MAX()` from `MIN()`/`MAX()` + * fix indent + * fix libgcrypt unused warning + * fix mbedtls unused warning + * fix wincng unused warning + * fix old openssl unused variable warnings + * delete blank lines + * updates to help merging with the ETM patch + +Viktor Szakats (20 Apr 2023) +- tidy-up: align comments [ci skip] + +- tidy-up: whitespace nits [ci skip] + +- crypto: add/fix algo guards and extend `NO` options + + Add new guard `LIBSSH2_RSA_SHA1`. Add missing guards for `LIBSSH2_RSA`, + `LIBSSH2_DSA`. + + Fix warnings when all options are disabled. + + This is still not complete and it's possible to break a build with + certain crypto backends (e.g. mbedTLS) and/or combination of options. + It's not guaranteed that all bits everywhere get disabled by these + settings. Consider this a "best effort". + + Add these new options to disable certain crypto elements: + - `LIBSSH2_NO_3DES` + - `LIBSSH2_NO_AES_CTR` + - `LIBSSH2_NO_BLOWFISH` + - `LIBSSH2_NO_CAST` + - `LIBSSH2_NO_ECDSA` + - `LIBSSH2_NO_RC4` + - `LIBSSH2_NO_RSA_SHA1` + - `LIBSSH2_NO_RSA` + + The goal is to offer a way to disable legacy/obsolete/insecure ones. + + See also: 146a25a06dd2365a4330dad34fefcdcee1a206aa `LIBSSH2_NO_HMAC_RIPEMD` + See also: 38015f4e46d8dbeea522dc7ee664522d4f47fc75 `LIBSSH2_NO_DSA` + See also: be31457f3071686b555a0f0b19e5dcf63d67fc27 `LIBSSH2_NO_MD5` + + Closes #986 + +- scp: fix typo in comments [ci skip] + + Follow-up to 0a500b3554c29451708353279eefce750f4bca6c + +- base64: do not use `snprintf()` on encoding + + This also significantly (by 7-8x in my limited tests with a short + string) speeds up this function. The impact is still minor as this + function is only used in `knownhost.c` in release builds. + + Closes #985 + +- wincng: constify data arg of `libssh2_wincng_hash()` + + Tested in #979 + +- wincng: fix unused variables with `LIBSSH2_RSA_SHA2` disabled + + Tested in #979 + +- ci: delete config elements for unused 32-bit Linux builds + + They have been disabled since d9b4222ef1c5ab9b9e499fe6234556e5cca7c4fe + + Tested in #979 + +- ci: enable FIXTURE_TRACE_ALL_CONNECT for WinCNG tests + + To hopefully help finding the WinCNG hostkey verification + intermittent failure #804. + + Tested in #979 + +- tests: add `FIXTURE_TRACE_ALL_CONNECT` option + + Works like the `FIXTURE_TRACE_ALL` envvar, but enables full trace for + the connection phase only. + + Also fix a possible NULL deref with `FIXTURE_TRACE_ALL` and a failed + `libssh2_session_init_ex()`. + + Tested in #979 + +- ci: really enable logging in AppVeyor CMake builds + + `CONFIGURATION` was never passed to the cmake command, so it had + never enabled logging when set to `Debug`. + + Also `CONFIGURATION` is ambiguous depending on the "generator" used + by CMake. In case of Visual Studio, this is a build/ctest-time + setting, not a cmake-config parameter. + + So set this permanently to `Release` and enable logging via our + dedicated CMake option `ENABLE_DEBUG_LOGGING`. + + Tested in #979 + +- HACKING-CRYPTO: fix stray whitespace + +- tidy-up: fix more nits + + - fix indentation errors. + - reformat `cmake/FindmbedTLS.cmake` + - replace a macro with a variable in `example/sftp_RW_nonblock.c`. + - delete macOS macro `_DARWIN_USE_64_BIT_INODE` from the + OS/400 config header, `os400/libssh2_config.h`. + - fix other minor nits. + + Closes #983 + +- mansyntax: make it work on macOS, check reqs locally + + - use `gman` alias if present. This makes it work when the correct `man` + command is provided via `brew` on macOS. + + - move CMake attempts to detect tools necessary to run `mansyntax.sh` + into the script itself. + + - delete CMake TODO to move more test logic into CMake. This would make + it CMake-specific and require maintaining it separately for each build + tool. Just use our external script when a POSIX shell is available. + + Closes #982 + +- cmake: dedupe setting `-DHAVE_CONFIG_H` + + Move `libssh2_config.h` generation and setting `-DHAVE_CONFIG_H` to + the root `CMakeFile.txt`. + + Also move symbol hiding setup there. It needs to be done before + generating the config file for `LIBSSH2_API` value to be set in it. + + After this change the `HIDE_SYMBOLS` setting is accepted without an + annoying CMake warning when not actually building a shared libssh2 lib. + + Closes #981 + +- build: assume non-blocking I/O on Windows + + Drop checks from Windows builds and enable it based on `WIN32`. + + This saves detection time and also makes 3rd party builds simpler. + + Also: + + - delete `HAVE_DISABLED_NONBLOCKING`, that we used in build tools to + explicitly disable an explicit `#error` in `session.c`. + + - replace existing `WSAEWOULDBLOCK` check for Windows support with + `WIN32`. Cleaner with the same result. + + Follow-up to f1e80d8d8ce9570d81836da96ba02f4d4552a7b3 + Follow-up to 5644eea2161b17f7c16e18f3a10465ebb217ca1f + + Closes #980 + +- ci: rename Logging to Debug in AppVeyor + +- switch to internal base64 decode that uses size_t + + Make the public `libssh2_base64_decode()` a wrapper for that. + Bump up length sizes in callers. + + Also fix output size calculation to first divide then multiply. + + Closes #978 + +- tests: switch to debian:bullseye-slim in Dockerfile + + 'slim' provides all we need, with less bloat. + + Tested in #976 + + Follow-up to 78cb64a85955f2cd9700c4fbad3f02d589dd7169 + +- tests: build improvements and more + + - rename tests to have more succint names and a more useful natural + order. + + - rename `simple` and `ssh2` in tests to have the `test_` prefix. + + This avoids a name collisions with `ssh2` in examples. + + - cmake: drop the `example-` prefix for generated examples. + + Bringing their names in sync with other build tools, like autotools. + + - move common auth test code into the fixture and simplify tests by + using that. + + - move feature guards from CMake to preprocessor for auth tests. + + Now it works with all build tools and it's easier to keep it in sync + with the lib itself. + + For this we need to include `libssh2_priv.h` in tests, which in turn + needs tweaking on the trick we use to suppress extra MSVS warnings + when building tests and examples. + + - move mbedTLS blocklist for crypto tests from CMake to the test + fixture. + + - add ed25519 hostkey tests to `test_hostkey` and `test_hostkey_hash`. + + - add shell script to regenerate all test keys used for our tests. + + - alpha-sort tests. + + - rename `signed_*` keys to begin with `key` like the rest of the keys + do. + + - whitespace fixes. + + Closes #969 + +- autotools: rename a variable + + To match its counterpart we use for clang and to better match + the original code in curl. + + Follow-up to ec0feae7920d695ce234a5aba13014bf29824c09 + + Closes #977 + +- ssh2.sh: revert likely wrong quoting [ci skip] + + Follow-up to 50124428509ffc2f5d08d8d3c152fa36546c9a75 + +- build: add `-Wbad-function-cast` picky warning + + Also adjust minimum gcc versions in comment. + + Closes #975 + +- tests: restore debian:bullseye in Dockerfile + + Follow-up to 78cb64a85955f2cd9700c4fbad3f02d589dd7169 + +- session: simplify preprocessor logic + + - by using #elif + - by merging two blocks + + Closes #972 + +- tests: try debian:testing for Dockerfile + + Follow-up to 78cb64a85955f2cd9700c4fbad3f02d589dd7169 + +- src: add and use `LIBSSH2_MIN/MAX` macros + + Also for #797 + + Closes #974 + +- tests: switch Dockerfile to debian:testing-slim + + From debian:bullseye + + - doesn't need manual bumps. + - is ahead of stable and should be stable enough for our purpose. + - slim is saving resources. + + Closes #971 + +- cmake: optimize non-blocking tests on WIN32/non-WIN32 + + Skip testing unixy methods on Windows and vice versa. + + I continue to assume that CMake doesn't define `WIN32` with Cygwin + (as Cygwin doesn't define `_WIN32`/`WIN32` for C), though I haven't + tested this. + + Closes #970 + +GitHub (15 Apr 2023) +- [Jörgen Sigvardsson brought this change] + + scp: option to not quote paths (#803) + + A new flag named `LIBSSH2_FLAG_QUOTE_PATHS` has been added, to make + libssh2 not quote file paths sent to the remote's scp subsystem. Some + custom ssh daemons cannot handle quoted paths, and this makes this flag + useful. + + Authored-by: Jörgen Sigvardsson + +Viktor Szakats (15 Apr 2023) +- cmake: make Windows builds initialize faster + + By skipping unixy header checks that always fail with + the MSVC toolchain or all Windows toolchains. + + Closes #968 + +- cmake: use a single build rule for all tests + + - use the complete filename of test sources in the input list. + + - build all tests with the ability to access libssh2 internals. + + This is necessary for `test_keyboard_interactive_auth_info_request` + now and might be necessary for others in the future, e.g. to avoid + the depreacted public base64 decoding API. + + - move `test_keyboard_interactive_auth_info_request` into the main + test build loop. + + - move `simple` into the main test build loop too. + + - build `ssh2` also in static mode. + + - cleanup the way we detect and enable gcov. + + - fix indentation. + + Closes #967 + +- tidy-up: more whitespace in src + + Closes #966 + +- checksrc: fix `EQUALSNULL` warnings + + `s/([a-z0-9._>*-]+) == NULL/!\1/g` + + Closes #964 + +- Makefile.am: add new OS400 header [ci skip] + + Follow-up to 6dc42e9d625deb816a051d312d09e68926959e78 + +- checksrc: fix `NOTEQUALSZERO` warnings + + Closes #963 + +- checksrc: fix `SIZEOFNOPAREN` warnings + + `s/sizeof ([a-z0-9._>*-]+)/sizeof(\1)/g` + + Closes #962 + +- crypto: add `LIBSSH2_NO_HMAC_RIPEMD` option + + See also: 38015f4e46d8dbeea522dc7ee664522d4f47fc75 + See also: be31457f3071686b555a0f0b19e5dcf63d67fc27 + + Ref: https://github.com/stribika/stribika.github.io/issues/46 + + Closes #965 + +- tidy-up: example, tests continued + + - fix skip auth if `userauthlist` is NULL. + Closes #836 (Reported-by: @sudipm-mukherjee on github) + - fix most silenced `checksrc` warnings. + - sync examples/tests code between each other. + (output messages, error handling, declaration order, comments) + - stop including unnecessary headers. + - always deinitialize in case of error. + - drop some redundant variables. + - add error handling where missing. + - show more error codes. + - switch `perror()` to `fprintf()`. + - fix some `printf()`s to be `fprintf()`. + - formatting. + + Closes #960 + +- src: fix indentation of macro definitions (follow-up) + + Follow-up to d5438f4ba9036e8028f35258dd1ab97cc2edb37c + +- src: fix indentation of macro definitions + + And some comment cleanup. + + Closes #958 + +- example/ssh2_exec: drop conditional code for deprecated API + +GitHub (13 Apr 2023) +- [monnerat brought this change] + + Make OS/400 implementation work again (#953) + + * os400: support QADRT development files in a non-standard directory + + This enables the possibility to compile libssh2 even if the ascii + runtime development files are not installed system-wide. + + * userauth_kbd_packet: fix a pointer target type mismatch. + + A temporary variable matching the parameter type is used before copying + to the real target and checking for overflow (that should not occur!). + + * os400qc3: move and fix big number procedures + + A bug added by a previous code style cleaning is fixed. + _libssh2_random() now checks and return the success status. + + * os400qc3: fix cipher definition block lengths + + They were wrongly set to the key size. + + * Diffie-Hellman min/max modulus sizes are dependent of crypto-backend + + In particular, os400qc3 limits the maximum group size to 2048-bits. + Move definitions of these parameters to crypto backend header files. + + * kex: return an error if Diffie-Hellman key pair generation fails + + * os400: add an ascii assert.h header file + + * os400qc3: implement RSA SHA2 256/512 + +Viktor Szakats (13 Apr 2023) +- sftp: add open functions with custom attribute support + + Before this patch, libssh2 sent hardcoded `LIBSSH2_SFTP_ATTRIBUTES` + struct on handle open. This can be problematic on some special OS, + where the file size should be known on new file creation. I added + two new functions to resolve this issue. + + Patch-by: @vajdaakos on github via #506 + + Changes compared to #506: + - drop attr size fixup in favour of #946. + - move `memcpy()` under the state where we need it. + - bump filename length type to `size_t`. + - fix filenames in documentation and other nits. + + Closes #506 + Closes #947 + +- build: speed up and extend picky compiler options + + Implement picky warnings with clang in autotools. Extend picky gcc + warnings, sync them between build tools and compilers and greatly + speed up detection in CMake. + + - autotools: enable clang compiler warnings with `--enable-debug`. + + - autotools: enable more gcc compiler warnings with `--enable-debug`. + + - autotools/cmake: sync compiler warning options between gcc and clang. + + - sync compiler warning options between autotools and cmake. + + - cmake: reduce option-checks to speed up the detection phase. + Bring them down to 3 (from 35). Leaving some checks to keep the + CMake logic alive and for an easy way to add new options. + + clang 3.0 (2011-11-29) and gcc 2.95 (1999-07-31) now required. + + - autotools logic copied from curl, with these differences: + + - delete `-Wimplicit-fallthrough=4` due to a false positive. + + - reduce `-Wformat-truncation=2` to `1` due to a false positive. + + - simplify MinGW detection for `-Wno-pedantic-ms-format`. + + - cmake: show enabled picky compiler options (like autotools). + + - cmake: do compile `tests/simple.c` and `tests/ssh2.c`. + + - fix new compiler warnings. + + - `tests/CMakeLists.txt`: fix indentation. + + Original source of autotools logic: + - https://github.com/curl/curl/blob/a8fbdb461cecbfe1ac6ecc5d8f6cf181e1507da8/acinclude.m4 + - https://github.com/curl/curl/blob/a8fbdb461cecbfe1ac6ecc5d8f6cf181e1507da8/m4/curl-compilers.m4 + + Notice that the autotools implementation considers Apple clang as + legacy clang 3.7. CMake detection works more accurately, at the same + time more error-prone and difficult to update due to the sparsely + documented nature of Apple clang option evolution. + + Closes #952 + +- include: delete leading underscore from macro name + + It can cause compiler warnings in 3rd-party code. + + Follow-up to 59666e03f04927e5fe3e8d8772d40729f63c570e + + Closes #957 + +- ci: use OpenSSL 3 on AppVeyor VS2022 images + + Closes #954 + +- build: be friendly with 3rd-party build tools + + After recent build changes, 3rd party build that took the list of + C source to compile them as-is, stopped working as expected, due to + `blowfish.c` and crypto-backend C sources no longer expected to compile + separately but via `bcrypt_pbkdf.c` and `crypto.c`, respectively. + + This patch ensures that compiling these files directly result in an + empty object instead of redundant code and duplicated symbols. + + Also: + - add a compile-time error if none of the supported crypto backends + are enabled. + - fix `libssh2_crypto_engine()` for wolfSSL and os400qc3. + Rearrange code to avoid a hard-to-find copy of crypto-backend + selection guards. + + Follow-up to 4f0f4bff5a92dce6a6cd7a5600a8ee5660402c3f + Follow-up to ff3c774e03585252b70a9ee0fcf254de7b14a767 + + Closes #951 + +- sftp: calculate attr size based on attr content in `sftp_open()` + + Improve robustness by replacing constant argument of `sftp_attrsize()` + in `sftp_open()` with the actual `flag` value read from the `attr` we + plan to transfer. Restores state of this before + 37624b61e3ec4aa65a608800613d00b55ced56d7. + + Prerequisite for #947, #506. + + Also improve readability a bit and link to SFTP specs. Delete comment + about version 6: The latest spec no longer features the mentioned + "DO NOT IMPLEMENT" notice. + + Closes #946 + +- man: fixups + + - add missing `.fi` tags. + - fix misplaced `.nf` tags. + - add `.nf`/`.fi` tags `SYNOPSIS` where missing. + - fix missing/wrong function name from `SH NAME`. + - fix wrong function name in `TH`. + - keep return values in a separate line. + - indent. + - fold long lines. + - deleted `libssh2_channel_direct_streamlocal()`, there is no such function. + - add missing types. + - add missing headers. + + Closes #949 + +- include: indentation fixes + +- tidy-up: misc & minor cmake MSVS fix + + - `libssh2.rc`: document language/codepage codes. + + Ref: https://learn.microsoft.com/windows/win32/intl/code-page-identifiers + + - convert to Markdown: `docs/BINDINGS`, `docs/HACKING` + + Blind update for `vms/libssh2_make_help.dcl`. Please double-check. + + - cmake: fix to recognize dash-style warning options (`-Wn`) with MSVC. + + - `NMakefile`: sync `rd` command with `Makefile.mk`. + + - delete a CVS header. + + - cmake: simplify a `LIBSSH2_HAVE_ZLIB` macro. + + - few other nits and whitespace mods. + + Closes #943 + +GitHub (10 Apr 2023) +- [Viktor Szakats brought this change] + + Support for direct-streamlocal@openssh.com UNIX socket connection (#945) + + This patch allow to use direct-streamlocal service from OpenSSH 6.7, + that allows UNIX socket connections. + + Mods: + - delete unrelated condition: + Ref: https://github.com/libssh2/libssh2/pull/216#discussion_r374748111 + - rebase on master, whitespace updates. + + Patch-by: @gjalves Gustavo Junior Alves + + Closes #216 + Closes #632 + Closes #945 + +Viktor Szakats (10 Apr 2023) +- build: support `libssh2.rc` with autotools + + Caveat: When building `--enable-static` and `--enable-shared` at the + same time, the compiled Windows resource is also included in the + static library. This appears to be an autotools limitation, with no + way to have different input lists (or different custom options) for + shared and static libraries, even though it builds them separately. + + The workaround is to build static libraries in a separate + `./configure` + `make` pass. + + Closes #944 + +- crypto: add `LIBSSH2_NO_DSA` to disable DSA support + + See also: be31457f3071686b555a0f0b19e5dcf63d67fc27 + + Closes #942 + +- build: unify source lists + + - introduce `src/crypto.c` as an umbrella source that does nothing else + than include the selected crypto backend source. Moving this job from + the built-tool to the C preprocessor. + + - this allows dropping the various techniques to pick the correct crypto + backend sources in autotools, CMake and other build method. Including + the per-backend `Makefile..inc` makefiles. + + - copy a trick from curl and instead of maintaining duplicate source + lists for CMake, convert the GNU Makefile kept for autotools + automatically. Do this in `docs`, `examples` and `src`. + + Ref: https://github.com/curl/curl/blob/dfabe8bca218d2524af052bd551aa87e13b8a10b/CMakeLists.txt#L1399-L1413 + + Also fixes missing `libssh2_setup.h` from `src/CMakeFiles.txt` after + 59666e03f04927e5fe3e8d8772d40729f63c570e. + + - move `Makefile.inc` from root to `src`. + + - reformat `src/Makefile.inc` to list each source in separate lines, + re-align the continuation character and sort the lists alphabetically. + + - update `docs/HACKING-CRYPTO` accordingly. + + - autotools: update the way we add crypto-backends to `LIBS`. + + - delete old CSV headers, indent, and merge two lines in + `docs/Makefile.am` and `src/Makefile.am`. + + - add `libssh2.pc` to `.gitignore`, while there. + + Closes #941 + +GitHub (9 Apr 2023) +- [Zenju brought this change] + + sftp: always clear protocol error (#787) + +Viktor Szakats (9 Apr 2023) +- cmake: add `HIDE_SYMBOLS` option & do symbol hiding on *nix + + - implement symbol hiding on non-Windows platforms. + + The essence of the detection logic was copied from: + https://github.com/curl/curl/blob/dfabe8bca218d2524af052bd551aa87e13b8a10b/CMake/CurlSymbolHiding.cmake + + Then simplified and shortened. This method doesn't require a recent + CMake version, nor an external, auto-generated C header. + + Move `configure_file()` after `set(LIBSSH2_API ...)`, for the config + file to pick up `LIBSSH2_API`s value. + + Closes #602 + + - add CMake option `HIDE_SYMBOLS`. + + This setting means to hide non-public functions from the libssh2 + dynamic library when set to `ON`. The default. + + When set to `OFF`, make all non-static/internal functions visible + in the dynamic library. + + This setting requires `BUILD_SHARED_LIBS=ON`. + + - honor this setting on Windows. + + By setting the `LIBSSH2_EXPORTS` manual macro again, and stop + recognizing the automatic CMake macro for this purpose: + `libssh2_shared_EXPORT`. + + Closes #939 + +- build: make `windows.h` even leaner + + Disable GDI and NLS features in `windows.h`. libssh2 doesn't use these. + + Closes #940 + +- blowfish: build improvements + + - include `blowfish.c` into `bcrypt_pbkdf.c`, instead of + compiling it as a distinct object. + + - make low-level blowfish functions static. This prevents this symbols + to pollute the public namespace of libssh2. It also allows the + compiler to inline these functions. + + - integrate `blf.h` header into `bcrypt_pbkdf.c` as well. + + - use `_DEBUG_BLOWFISH` instead of `#if 0`. + + - fix `_DEBUG_BLOWFISH` compiler warnings and other nits. + + - `#undef` `inline` before redefining it in `libssh2_priv.h`. + (copied from `blowfish.c`) + + - delete unused `inline` redefinitions from `blowfish.c`. + + - disable unused low-level blowfish functions. + + - formatting, header order. + + Closes #938 + +- libssh2.rc: fix debug flag, other cleanups + + - fix to use `LIBSSH2DEBUG` macro to set the debug flag. + (was `DEBUGBUILD`, a curl-specific macro) + + - use manifest constants instead of literals + + - change language to neutral + + Closes #937 + +- tidy-up: example, tests + + - drop unnecessary `WIN32`-specific branches. + + - add `static`. + + - sync header inclusion order. + + - sync some common code between examples/tests. + + - fix formatting/indentation. + + - fix some `checksrc` errors not caught by `checksrc`. + + Closes #936 + +- tests/mansyntax.sh: avoid `if !` for portability + + Ref: https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Limitations-of-Builtins.html#Limitations-of-Builtins + + Fixes #704 + Closes #935 + +- tidy-up: indentation in guarded #includes [ci skip] + +- Makefile.mk: drop `PROOT` variable [ci skip] + +- build: hand-crafted config rework & header tidy-up + + - introduce the concept of a project level setup header + `src/libssh2_setup.h`, that is used by `src`, `example` and `tests` + alike. Move there all common platform/compiler configuration from + `src/libssh2_priv.h`, individual sources and `CMakeFiles.txt` files. + Also move there our hand-crafted (= not auto-generated by CMake or + autotools) configuration `win32/libssh2-config.h`. + + - `win32` directory is empty now, delete it. + + - `Makefile.mk`: adapt to the above. Build-directory is the target + triplet, or any custom name set via `BLD_DIR`. + + - sync header path order between build systems: + build/src -> source/src -> source/include + + - delete redundant references to `windows.h`, `winsock2.h`, + `ws2tcpip.h`. + + - delete unnecessary #includes, update order (`libssh2_setup.h` first, + `winsock2.h` first), simplify where possible. + + This makes the code warning-free without `WIN32_LEAN_AND_MEAN`. + At the same time this patch applies this macro globally, to avoid + header bloat. + + - example: add missing *nix header guards. + + - example: fix misindented `HAVE_UNISTD_H` `#ifdef`s. + + - set `WIN32` with all build-tools. + + - set `HAVE_SYS_PARAM_H` in the hand-crafted config for MinGW. + To match auto-detection. + + - move a source-specific macro to `misc.c` from `libssh2_priv.h`. + + See the PR's individual commits for step-by-step updates. + + Closes #932 + +- Makefile.mk: build tests and other improvements [ci skip] + + - use `example` target for building examples (was: `test`). + + - add support for building tests via the `test` target. + + - accept lib-only options in a new `LIBSSH2_CPPFLAGS_LIB` variable. + + Useful to pass `-DLIBSSH2_EXPORTS` for correct `dllexport` in + `libssh2.dll`. + + - fix to put dynamic library in lib directory for non-Windows builds + + - fix to not delete lib objects on `testclean` + +- test_warmup: re-implement as `test()` + + Instead of overriding `main()`. To align with the other tests. + + Overriding `main()` can cause duplicate symbols without using a lib for + the `runner` code. + + Follow-up to 40ac6b230a309d35c57aa65a8f6d7ab6654aa3d8 + + Closes #934 + +- NMakefile: drop `/DEBUG` linker option in release mode [ci skip] + +- NMakefile: simplify [ci skip] + +- Makefile.mk: merge two rules [ci skip] + +- TODO: update item about compiler warnings [ci skip] + + Follow-up to 08354e0abbe86d4cc5088d210d53531be6d8981a + Follow-up to 29347905721d2e7fbb97dabfb0071bee51db3013 + Follow-up to 5a96f494ee0b00282afb2db2e091246fc5e1774a + Follow-up to 463449fb9ee7dbe5fbe71a28494579a9a6890d6d + Follow-up to 02f2700a61157ce5a264319bdb80754c92a40a24 + +GitHub (5 Apr 2023) +- [ihsinme brought this change] + + example/x11: Add null-termination (#749) + +Viktor Szakats (5 Apr 2023) +- crypto: fix `LIBSSH2_NO_MD5` compiler warnings + + Follow-up to be31457f3071686b555a0f0b19e5dcf63d67fc27 + + Closes #933 + +- build: add new man pages + + Follow-up to c20c81ab105cdf27f5a4e2604bd13085f46e21de + +GitHub (5 Apr 2023) +- [Daniel Silverstone brought this change] + + Configurable session read timeout (#892) + + This set of changes provides a mechanism to runtime-configure the + previously #define'd timeout for reading packets from a session. The + intention here is to also extend libcurl to be able to use this + interface so that when fetching from sftp servers which are very slow + to return directory listings, connections do not time-out so much. + + * Add new field to session to hold configurable read timeout + + * Updated `_libssh2_packet_require()`, `_libssh2_packet_requirev()`, + and `sftp_packet_requirev()` to use new field in session structure + + * Updated docs for API functions to set/get read timeout field in + session structure + + * Updated `libssh2.h` to declare the get/set read timeout functions + + Co-authored-by: Jon Axtell + Credit: Daniel Silverstone + +Viktor Szakats (4 Apr 2023) +- cmake: whitespace fixes [ci skip] + +- libssh2.h: bump LIBSSH2_COPYRIGHT year [ci skip] + +- Makefile.mk: move portable GNU Make file to the root + + Move the GNU Make file formerly known as `win32/GNUmakefile` to the + root directory from `win32`. It now supports any platform with a + GCC-like toolchain, while also keeping support for win32. + + For non-Windows platforms it's necessary to provide a hand-crafted + `libssh2_config.h` header for now. + + Usage: `make -f Makefile.mk` + +- src: include `limits.h` for `*_MAX` macros + + Follow-up to 5a96f494ee0b00282afb2db2e091246fc5e1774a + + Reported-by: OldWorldOrdr on github + Fixes #928 + Closes #930 + +- build: MSVS warning suppression option tidy-up + + - in `win32/libssh2_config.h` replace `_CRT_SECURE_NO_DEPRECATE` with + `_CRT_SECURE_NO_WARNINGS`, to use the official macro for this, like + in CMake. + + Also, it's now safe to move it back under `_MSC_VER`. + + Suppressing: + + `warning C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead.` + `warning C4996: 'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead.` + + - move `_CRT_NONSTDC_NO_DEPRECATE` to `example` and `tests`. + Not needed for `src`. + + Suppressing: + + `warning C4996: 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _strdup.` + `warning C4996: 'write': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _write.` + + - move `_WINSOCK_DEPRECATED_NO_WARNINGS` from source files to + CMake files, in `example` and `tests`. Also limit this to MSVC. + + Suppressing: + + `warning C4996: 'inet_addr': Use inet_pton() or InetPton() instead` + + TODO: try fixing these instead of suppressing. + + Closes #929 + +- win32/GNUmakefile: make it movable [ci skip] + + - add `BLD_DIR` to customize the output directory (where libs, .zip, + obj subdir will go). This directory must exist. + + It remains `./win32` for Windows builds. + + - add `CONFIG_H_DIR` option to customize `libssh2_config.h` location. + + It remains `./win32` for Windows builds. + + - include `.def` in distro zip for Windows. + + - ready to move to the root directory. + +- win32/GNUmakefile: drop an unnecessary variable [ci skip] + +- windows: re-add `libssh2.rc` + + Lost while moving it from the win32 directory + + Follow-up to 194cfc0f84192809c87f846140e5bf06b7a864af + +- crypto: add `LIBSSH2_NO_MD5` to disable MD5 support + + Closes #927 + +- hostkey: fix `hash_len` field constants + + Replace incorrect `MD5_DIGEST_LENGTH` with `SHA_DIGEST_LENGTH` for these + hostkey algos: + + - `ssh-rsa` and `ssh-dss` + + Ref: 7a5ffc8cee259bbde82ab92515cd8fea2166854b (2004-12-07 Initial) + + - `ssh-rsa-cert-v01@openssh.com` + + Ref: 4b21e49d9d2db74579b18804ed1f5eeb16578b2f (2022-07-28) + Ref: #710 + + Also delete local fall-back definition of `MD5_DIGEST_LENGTH` (added + in 9af7eb48dc3854ce8ee0589f7e2beb944e064847). Macro is no longer used. + + Reported-by: Markus-Schmidt on github + Fixes #919 + Closes #926 + +- ci: add MSVS 2008/2010 build tests and fix warnings + + Also: + + - fix newly surfaced (bogus) warnings in examples with MSVS 2010: + + ``` + ..\..\example\direct_tcpip.c(262): warning C4127: conditional expression is constant + ``` + Happens for every `FD_SET()` macro reference. + + Ref: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46677835/job/ni4hs97bh18c14ap + + - silence MSVS 2010 predefined Windows macro warnings: + + ``` + ..\..\src\wincng.c(867): warning C4306: 'type cast' : conversion from 'int' to 'LPCSTR' of greater size + ..\..\src\wincng.c(897): warning C4306: 'type cast' : conversion from 'int' to 'LPCSTR' of greater size + ..\..\src\wincng.c(1132): warning C4306: 'type cast' : conversion from 'int' to 'LPCSTR' of greater size + ``` + + Ref: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46678071/job/08t5ktvkcgdghp7r + + Closes #925 + +- transport: rename local `RANDOM_PADDING` macro + + Rename `RANDOM_PADDING` macro used internally to enable some code. + + Committed in the initial version of `transport.c` in + 9d55db6501aa4e21f0858cf36cdc2ddc11b96e83 (2007-02-02). libssh2 code + never defined it. + + The name happens to collide with a Windows macro in `wincrypt.h`. + `transport.c` doesn't include this header, but it includes `winsock2.h`, + and it turns out it can also define this macro in some cases, e.g. + when `WIN32_LEAN_AND_MEAN` is not set. + + To be on the safe side, prefix the name with `LIBSSH2_` to avoid + enabling it by accident. + + Q: Maybe it'd be best to delete it with the guarded code? + + Reported-by: Markus-Schmidt on github + Fixes #921 + Closes #924 + +- windows: move `libssh2.rc` to the `src` directory + + Closes #918 + +- autotools: delete unused conditional `HAVE_SYS_UN_H` + + No longer necessary after moving the disabling/enabling logic from + build tool to `example/x11.c`. + + Reverts 4774d500e724bc4e548f743a0cb644ab05599474 + Follow-up to d245c66cc0029e480674394c23e8be1c9410f7ad + +- win32/GNUmakefile: update help & exit without crypto backend [ci skip] + + Follow-up to: 5bcd25c4c980e9765c00a2f20ac5348635063aad + Follow-up to: 68fd02fba002c8c6af3ba51a2780de46b47b3787 + +- build: respect autotools `DLL_EXPORT` in `libssh2.h` + + The `DLL_EXPORT` macro is automatically set by autotools when building + the libssh2 DLL. Certain toolchains might require this to correctly + export symbols, so make sure to respect it in `libssh2.h` to enable + `declspec(dllexport)`. + + With this patch we have a manual macro for that (`LIBSSH2_EXPORT`), + this autotools one, the CMake one, and `_WINDLL` (added in + c355d31ff94a1622526c4988b9d09074f7f7605d), possibly defined by Visual + Studio. + + Closes #917 + +- build: make `HAVE_LIBCRYPT32` local to `wincng.c` + + libssh2 uses `wincrypt.h` aka the `crypt32` Windows system library + for the function `CryptDecodeObjectEx()` [1]. This function has been + available for Win32 (and UWP/WinRT apps) for a long while. Even old + MinGW supports it, and also Watcom 1.9, of the rare/old compilers + I checked. + + CMake had it permanently enabled, while it also did an extra check + for the header to add the lib to the lib list. Autotools did the + detection proper. Other builds had it permanently enabled. + + It seems safe to assume this function/header/lib is available in all + environments we support. + + In this patch we simplify by deleting these detections and feature + flags from all build tools. + + Keep the feature flag internal to `wincng.h`, and for extra safety add + the new macro `LIBSSH2_WINCNG_DISABLE_WINCRYPT` do disable it via + custom `CPPFLAGS`. + + WinCNG's other requirement is `bcrypt`. That also has been universally + available for a long time. Here the only known outlier is old/legacy + MinGW, which is missing support. + + [1] https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptdecodeobjectex + + Closes #916 + +- autotools: delete `src/libssh2.pc.in` reference [ci skip] + + Follow-up to 06f281921907fa077884c7020917661ca805b9d3 + +- tidy-up: null-mac/cipher documentation + + Move documentation for these deleted build-level options from + autotools/cmake docs to the source code itself. + + Follow-up to 50c9bf868e833258d23c5f55ed546d1fcd5687d0 + + Closes #915 + +- cmake: re-use existing `libssh2.pc` template + + Instead of maintaining a second copy of `libssh2.pc.in` in `src` just + for CMake, teach CMake to use the existing template in the root dir, + that we already use with autotools. + + Closes #914 + +- delete redundant `HAVE_STDLIB_H` + + libssh2 used this standard C89 header unconditionally before this patch. + + Delete the feature checks and all unnecessary header guards. + + Closes #913 + +- NMakefile: drop redundant variable and assignments [ci skip] + +- delete redundant `HAVE_WINSOCK2_H` + + `libssh2.h` required `winsock2.h` for `_WIN32` since + 81d53de4dc5ee39bd6215958c7dce3b12731195e (2011-06-04). + + Apply that to the whole codebase. This makes it unnecessary to detect + `HAVE_WINSOCK2_H` and allows to drop all its uses. + + Completes TODO from b66d7317ca6c882afbe52fe426f68c119c40d348 + + TODO: Straighten out the use a mixture of `HAVE_WINDOWS_H`, + `WIN32`, `_WIN32` to detect Windows. + +- cmake: detect WinCNG last + + This gives a chance to auto-detect mbedTLS on Windows with CMake. + +- NMakefile: rename config variables, default to WinCNG [ci skip] + + - replace `OPENSSLINC` and `OPENSSLLIB` with `OPENSSL_PATH`. + Assume `include` and `lib` subdirs for headers and libs. + + - replace `WITH_ZLIB`, `ZLIBINC` and `ZLIBLIB` with `ZLIB_PATH`. + Assume `include` and `lib` subdirs for header and lib. + + - make WinCNG the default if `WITH_OPENSSL` is not set. + +- win32/GNUmakefile: rename object dir and update .gitignore [ci skip] + + From `-{release|debug}` to `{release|debug}-`. + + Follow-up to 68fd02fba002c8c6af3ba51a2780de46b47b3787 + +- win32/GNUmakefile: add libgcrypt support [ci skip] + + In the previous commit 969487113aae856e43d3d905c3f2260246d44f9b, + the commit message should read `win32/GNUmakefile: ` instead of + `libssh2-gnumake.sh: `. Sorry for the mixup. + +- libssh2-gnumake.sh: make variable names platform-agnostic [ci skip] + + Also more consistent. Refer to DLL/SO/shared as 'dyn'. + + Also add comment on how to find customizable environment variables. + +- win32/GNUmakefile: make it support non-Windows builds [ci skip] + + With 20-ish extra lines, make this Makefile support all GCC-like + toolchains. + + The temporary directory becomes `-{release|debug}` from + the former `{release|debug}`. + + Also change the lib directory name in the `dist` package from + `win32` to `lib`, to match other packages and build tools. + +- win32/GNUmakefile: default to WinCNG [ci skip] + + Also check for wolfSSL before mbedTLS to match CMake. + +- win32/GNUmakefile: fixups to previous commit [ci skip] + + - `-lws2_32` is necessary when building examples. + + - drop a temporary variable. + + Follow-up to d245c66cc0029e480674394c23e8be1c9410f7ad + +- delete redundant `HAVE_WS2TCPIP_H` + + It was used once in `src/libssh2_priv.h`, but without any effect. + The header included `ws2tcpip.h` twice, once guarded by + `HAVE_WS2TCPIP_H` and another time by `HAVE_WINSOCK2_H`. + + Dedupe these to not use `HAVE_WS2TCPIP_H`. Then delete detection + of this feature from all build methods. + + TODO: Replace `HAVE_WINSOCK2_H` with `_WIN32`/`WIN32`. + +- win32/libssh2_config.h: set `HAVE_LONGLONG` & `HAVE_STDLIB_H` [ci skip] + + - enable `HAVE_LONGLONG` for MinGW and MSVC versions supporting it. + + Necessary for `GNUmakefile`/`NMakefile` builds to create the same + binaries as CMake/autotools ones do. + + - enable `HAVE_STDLIB_H`. It has been universally available on + Windows for a long time. + + Fixes these clang-cl warnings: + ``` + src\wincng.c(444,5) : warning: implicit declaration of function 'free' is invalid in C99 [-Wimplicit-function-declaration] + free(buf); + ^ + src\wincng.c(491,20) : warning: implicitly declaring library function 'malloc' with type 'void *(unsigned long long)' [-Wimplicit-function-declaration] + pbHashObject = malloc(dwHashObject); + ^ + src\wincng.c(491,20) : note: include the header or explicitly provide a declaration for 'malloc' + src\wincng.c(2106,14) : warning: implicitly declaring library function 'realloc' with type 'void *(void *, unsigned long long)' [-Wimplicit-function-declaration] + bignum = realloc(bn->bignum, length); + ^ + src\wincng.c(2106,14) : note: include the header or explicitly provide a declaration for 'realloc' + 3 warnings generated. + ``` + +- example: make `x11` exclusion build-tool-agnostic + + Whether to build the `x11` example or not was decided by each build + tool. CMake didn't build it even on supported platforms. GNUMakefile + used a specific blocklist for it, while autotools enabled it based on + feature-detection. + + Migrate the enabler logic to an #ifdef in source and build `x11` + unconditionally with all build tools. + + On unsupported platforms (=Windows) this program now displays a short + message stating that fact. + + Also: + + - fix `x11.c` warnings uncovered after CMake started building it. + + - use `libssh2_socket_t` type for portability in `x11.c` too. + + - use detected header guards in `x11.c`. + + - delete a duplicate reference to `-lws2_32` from `win32/GNUmakefile` + while there. + + Closes #909 + +- .gitignore updates [ci skip] + +- tidy-up: whitespace, sorting, comment and naming fixups + +- cmake: add missing man pages + +- cmake: dedupe and merge config detection + + Before this patch CMake did feature detections in three files: + `src/CMakefiles.txt`, `examples/CMakefiles.txt` and + `tests/CMakefiles.txt`. + + Merge and move them to the root `CMakefiles.txt`. + + After this patch we end up with a single `src/libssh2_config.h`. This + brings CMake in sync with autotools builds, which already worked with + a single config header. + + This also prevents mistakes where feature detection went out of sync + between `src` & `tests` (see ae90a35d15d97154ac0c8554bce99ebfb18ee825). + `tests` do compile sources from `src` directly, so these should always + be in sync. + + It also allows to better integrate hand-crafted, platform-specific + config headers into the builds, like the one currently residing in + the `win32` directory (and also in `vms` and `os400`). Subject to an + upcoming PR. + + Also fix a warning revealed after this patch made CMake correctly + enable `HAVE_GETTIMEOFDAY` for `example` programs. + + Closes #906 + +- cmake: dedupe crypto-backend detection + + Before this patch CMake did crypto-backend detection in both + `src/CMakefiles.txt` and `tests/CMakefiles.txt`. + + Merge them and move it to the root `CMakefiles.txt`. + + While here, also add zlib for OpenSSL. Necessary when using OpenSSL + builds with zlib enabled. + + Closes #905 + +- cmake: add missing #cmakedefines to src + + - `HAVE_MEMSET_S` missing since + 03092292597ac601c3f9f0c267ecb145dda75e4e (2018-08-02) + + - `HAVE_EXPLICIT_BZERO` and `HAVE_EXPLICIT_MEMSET` missing since + 00005682f7b9a1aa42be50e269056ea873637047 (2023-03-28) + +GitHub (31 Mar 2023) +- [Viktor Szakats brought this change] + + tidy-up: NMakefile (#903) + +Viktor Szakats (30 Mar 2023) +- GNUmakefile: adjust win32/.gitignore [ci skip] + +- build: delete references to deleted NMake files [ci skip] + + Follow-up to 057522bb0f15c10c33159e12899ecc60e40aa6ef + +GitHub (30 Mar 2023) +- [Viktor Szakats brought this change] + + NMakefile: merge them into a single file [ci skip] (#902) + + Also: + + - allow to override `AR` and `ARFLAGS`. + + - The extra `src` subdir in the target directory is no longer, to + simplify things. + + - gone the dynamically generated `objects.mk`. Now replaced with some + tricky logic to do that inline. + + - add necessary `LIBS` for WinCNG. (untested) + + Lightly tested via clang-cl. + +- [Viktor Szakats brought this change] + + maketgz: tidy-up [ci skip] (#901) + + - fix shellcheck warnings: + - use quotes + - use `$()` + - use `printf` (instead of calling perl). + - indent. + - copy/adapt header comment from curl to `maketgz`. + +- [Viktor Szakats brought this change] + + ci: flatten AppVeyor jobs, add debug builds (#900) + + This results in better job names (now including CPU), avoiding the + complex exception rules, and fine-tuning the order and variation of + these tests. + + Enable `LIBSSH2DEBUG` for two of the existing jobs. + +- [Viktor Szakats brought this change] + + ci: add VS2022 builds (incl. ARM64) to AppVeyor (#899) + + - add MSVS 2022 WinCNG builds for x64 and ARM64, + replacing MSVS 2013 WinCNG builds for x64 and x86. + + - add MSVS 2022 OpenSSL builds for x64. + + - fix a compiler warning uncovered by the new ARM64 build: + + ``` + tests\openssh_fixture.c(393,17): warning C4477: 'fprintf' : format string '%d' requires an argument of type 'int', but variadic argument 1 has type 'libssh2_socket_t' + tests\openssh_fixture.c(393,17): message : consider using '%lld' in the format string + tests\openssh_fixture.c(393,17): message : consider using '%Id' in the format string + tests\openssh_fixture.c(393,17): message : consider using '%I64d' in the format string + ``` + + - echo the actual CMake command-line. + + - cmake: echo the DLL filenames found by the OpenSSL DLL-finder + heuristics. + + - cmake: delete `libcrypto.dll` and `libssl.dll` names from the above + logic. + + I've added these in 19884e5055b6c65f0df93d7cc776a01c518a2f06. That + resulted in CMake picking up a rogue `libcrypto.dll` (with no + `libssl.dll` pair) from `C:\Windows\System32\` on the + `Visual Studio 2022` image, breaking tests. + + Turns out, OpenSSL v1.0.2 uses the "EAY" names, but let's not re-add + those either, because CMake mis-picks those up from + `C:/OpenSSL-Win64/bin/`, even while pointing `OPENSSL_ROOT_DIR` to a + v1.1.1 installation. + + - cmake: set `NO_DEFAULT_PATH` for OpenSSL DLL lookup to avoid picking + up all kinds of wrong DLLs. CMake considers not the first, but the + _last_ hit the valid one. This happened to be + `C:/Program Files/Meson/lib*-1_1.dll` when using the + `Visual Studio 2022` image. + + Ref: https://cmake.org/cmake/help/latest/command/find_file.html + + - cmake: leave two commented debug lines that will be useful next time + the DLL detection lookup goes wrong. + + Ref: https://cmake.org/cmake/help/latest/variable/CMAKE_FIND_DEBUG_MODE.html + + - on error, also dump `CMakeFiles/CMakeConfigureLog.yaml` if it exists + (requires CMake 3.26 and newer) + +- [Viktor Szakats brought this change] + + src: fix compiler warning on Darwin (#898) + + ``` + src/session.c:675:52: warning: implicit conversion loses integer precision: 'long' to '__darwin_suseconds_t' (aka 'int') [-Wshorten-64-to-32] + tv.tv_usec = (ms_to_next - tv.tv_sec*1000) * 1000; + ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~ + ``` + +Viktor Szakats (29 Mar 2023) +- tidy-up: tabs to spaces in Makefile.am [ci skip] + + Follow-up to 2f16d8105c9491beb2a02b3081f4f1c2a224fa62 + +GitHub (29 Mar 2023) +- [Viktor Szakats brought this change] + + netware: delete support (#888) + + Last related commit happened 15 years ago. + NetWare had it last release in 2009. + + All links referenced from the make file are inaccessible. + +- [Viktor Szakats brought this change] + + wolfssl: add workaround for HMAC_Update() len arg difference (#897) + + It's `int` in wolfSSL. `size_t` in OpenSSL/quictls/LibreSSL/BoringSSL. + + Ref: https://github.com/wolfSSL/wolfssl/blob/ba47562d182e10e59813da012e0ab8ef20892231/wolfssl/openssl/hmac.h#L60-L61 + + /cc @wolfSSL + +- [Viktor Szakats brought this change] + + cmake: introduce variables for lib target names (#896) + + Make our CMake config more self-documenting by introducing variables + for the shared and static lib target names. Without this, it might be + non-trivial to find out which line is referring to a target name vs + libname, export name or other occurrences of `libssh2`. + + This allows to rename back the shared lib target name to the value used + before 4e2580628dd1f8dc51ac65ac747ebcf0e93fa3d1: + `libssh2_shared` -> `libssh2`, if necessary for compatibility. Notice: + before that patch, `libssh2` name referred to either the static or + shared lib, depending on build settings. + +- [Viktor Szakats brought this change] + + detect and use explicit_bzero() and explicit_memset() (#895) + + Also skip detecting these and `memset_s()` for Windows targets in CMake, + to save detection time. On Windows we always use `SecureZeroMemory()`. + +- [Viktor Szakats brought this change] + + ci: bump mbedtls (#894) + +- [Viktor Szakats brought this change] + + GNUmakefile: minor fix for DYN mode [ci skip] (#893) + + Follow-up to b8762c1003d97e109efa587bdc760ff9873949eb + +- [Viktor Szakats brought this change] + + build: delete MS Dev Studio build files (#891) + + Last updated in 2007. + + Also delete `VCPROJ` target remains (necessary files seem to have + been missing from the repo all along) for Visual Studio 2008. + +Viktor Szakats (28 Mar 2023) +- checksrc: fix reference in Makefile.am, update options [ci skip] + +GitHub (28 Mar 2023) +- [Viktor Szakats brought this change] + + build: delete native Watcom wmake support with Win32 (#889) + + CMake supports generating Watcom wmake files: + https://cmake.org/cmake/help/v3.1/generator/Watcom%20WMake.html + +- [Viktor Szakats brought this change] + + checksrc: update and fix warnings (#890) + + Update from: + https://github.com/curl/curl/blob/5fec927374e4d9553205d861f2dcb39ec78002cc/scripts/checksrc.pl + + - suppress these new checks: + + - EQUALSNULL: 320 warnings + - NOTEQUALSZERO: 142 warnings + - TYPEDEFSTRUCT: 16 warnings + + We can enabled them in the future. + + - fix all other new ones. + + - also fix whitespace in two `NMakefile` files. + +- [Viktor Szakats brought this change] + + tidy-up: fix/update URLs (#887) + +- [Viktor Szakats brought this change] + + tidy-up: fix typos (#886) + + detected by codespell 2.2.4. + +- [Viktor Szakats brought this change] + + tidy-up: replace tabs and other whitespace (#885) + + There are a few non-whitespace changes, see them here: + https://github.com/libssh2/libssh2/pull/885/files?w=1 + +- [Viktor Szakats brought this change] + + ci: drop cmake --parallel (#884) + + `--parallel 2` did not seem to make builds faster. Neither did 4 or 6. + + Delete this option from both GHA and AppVeyor jobs. + + On AppVeyor, with VS, it uses MSBuild under the hood where apparently + `--parallel` doesn't do much [1]. The suggested MSBuild-specific option + `/p:CL_MPcount=2` did not improve build times either. + + CMake spends significant time (comparable to building the project + itself) on feature detection, it'd be nice to execute those in parallel, + but I found not such CMake option. + + [1] https://discourse.cmake.org/t/parallel-does-not-really-enable-parallel-compiles-with-msbuild/964 + + Partial revert of 7a039d9a7a2945c10b4622f38eeed21ba6b4ec55 + +- [Viktor Szakats brought this change] + + rework how to enable insecure null-cipher/null-MAC (#873) + + Null-cipher and null-MAC are security footguns we want to avoid. + + Existing option names to toggle these were ambiguous and gave room for + misinterpretation. Some projects may have had these options enabled by + accident. + + This patch aims to make it more difficult to enable them, and making + sure that existing methods require an update to stay enabled. + + - delete CMake/autotools settings to enable the "none" cipher and MAC. + + - rename existing C macros that can enable them. + + To use them, pass them as custom `CPPFLAGS` to the build. + + - enable them only if `LIBSSH2DEBUG` is also enabled. + + Best would be to delete them, though they may have some use while + developing libssh2 itself, or debugging. + +- [Viktor Szakats brought this change] + + delete old gex (SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) build option (#872) + + libssh2 supports an "old" style KEX message + `SSH2_MSG_KEX_DH_GEX_REQUEST_OLD`, as an off-by-default build option. + + OpenSSH deprecated/disabled this feature in v6.9 (2015-07-01): + https://www.openssh.com/releasenotes.html#6.9 + + This patch deletes this obsolete feature from libssh2, with no option + to enable it. + + Added to libssh2 in: cf8ca63ea0c9388c8ae9079961d7e6a91b72b5c8 (2004-12-31) + RFC: https://datatracker.ietf.org/doc/html/rfc4419 (2006-03) + +- [Viktor Szakats brought this change] + + src: more tolerant snprintf() local override (#881) + + `#undef snprintf` before redefining it, when `HAVE_SNPRINTF` is not + defined, even though `snprintf` is available and it should have been. + Possibly with 3rd party builds. + + Downside is that cases of missing `HAVE_SNPRINTF` are less trivially + detected at compile-time. + +- [Viktor Szakats brought this change] + + ci: fix cmake warning with AppVeyor WinCNG builds (#883) + + ``` + CMake Warning: + Manually-specified variables were not used by the project: + + OPENSSL_ROOT_DIR + ``` + + Follow-up to 0834b9bcc85b90c78afff103f909b5a909b95e45 + +- [Viktor Szakats brought this change] + + ci: cmake `ENABLE_WERROR` -> `ON` (#877) + + Consider warnings as errors for CMake jobs in CI. + +Viktor Szakats (26 Mar 2023) +- src: silence compiler warnings 4 (alignment in WinCNG) + + Silence alignment warnings in WinCNG, by reworking the code. + + Also add two unrelated casts to avoid gcc compiler warnings + in surrounding code. + + `increases required alignment from 1 to 4 [-Wcast-align]` + `increases required alignment from 1 to 8 [-Wcast-align]` + + See warning details in the PR's individual commits. + + Reviewed-by: Marc Hörsken in + Cherry-picked from #846 + Closes #880 + +- src: silence compiler warnings 3 (change types) + + Apply type changes to avoid casts and warnings. In most cases this + means changing to a larger type, usually `size_t` or `ssize_t`. + + Change signedness in a few places. + + Also introduce new variables to avoid reusing them for multiple + purposes, to avoid casts and warnings. + + - add FIXME for public `libssh2_sftp_readdir_ex()` return type. + + - fix `_libssh2_mbedtls_rsa_sha2_verify()` to verify if `sig_len` + is large enough. + + - fix `_libssh2_dh_key_pair()` in `wincng.c` to return error if + `group_order` input is negative. + + Maybe we should also reject zero? + + - bump `_libssh2_random()` size type `int` -> `size_t`. Add checks + for WinCNG and OpenSSL to return error if requested more than they + support (`ULONG_MAX`, `INT_MAX` respectively). + + - change `_libssh2_ntohu32()` return value `unsigned int` -> `uint32_t`. + + - fix `_libssh2_mbedtls_bignum_random()` to check for a negative `top` + input. + + - size down `_libssh2_wincng_key_sha_verify()` `hashlen` to match + Windows'. + + - fix `session_disconnect()` to limit length of `lang_len` + (to 256 bytes). + + - fix bad syntax in an `assert()`. + + - add a few `const` to casts. + + - `while(1)` -> `for(;;)`. + + - add casts that didn't fit into #876. + + - update `docs/HACKING-CRYPTO` with new sizes. + + May need review for OS400QC3: /cc @monnerat @jonrumsey + + See warning details in the PR's individual commits. + + Cherry-picked from #846 + Closes #879 + +- src: silence compiler warnings 2 (ZLIB interface) + + Silence warnings in the ZLIB interface by adding casts and changing + types. + + See PR for individual commits. + + Cherry-picked from #846 + Closes #878 + +- src: silence compiler warnings 1 + + Most of the changes aim to silence warnings by adding casts. + + An assortment of other issues, mainly compiler warnings, resolved: + + - unreachable code fixed by using `goto` in + `publickey_response_success()` in `publickey.c`. + + - potentially uninitialized variable in `sftp_open()`. + + - MSVS-specific bogus warnings with `nid_type` in `kex.c`. + + - check result of `kex_session_ecdh_curve_type()`. + + - add missing function declarations. + + - type changes to fit values without casts: + - `cmd_len` in `scp_recv()` and `scp_send()`: `int` -> `size_t` + - `Blowfish_expandstate()`, `Blowfish_expand0state()` loop counters: + `uint16_t` -> `int` + - `RECV_SEND_ALL()`: `int` -> `ssize_t` + - `shell_quotearg()` -> `unsigned` -> `size_t` + - `sig_len` in `_libssh2_mbedtls_rsa_sha2_sign()`: + `unsigned` -> `size_t` + - `prefs_len` in `libssh2_session_method_pref()`: `int` -> `size_t` + - `firstsec` in `_libssh2_debug_low()`: `int` -> `long` + - `method_len` in `libssh2_session_method_pref()`: `int` -> `size_t` + + - simplify `_libssh2_ntohu64()`. + + - fix `LIBSSH2_INT64_T_FORMAT` for MinGW. + + - fix gcc warning by not using a bit field for + `burn_optimistic_kexinit`. + + - fix unused variable warning in `_libssh2_cipher_crypt()` in + `libgcrypt.c`. + + - fix unused variables with `HAVE_DISABLED_NONBLOCKING`. + + - avoid const stripping with `BIO_new_mem_buf()` and OpenSSL 1.0.2 and + newer. + + - add a missing const in `wincng.h`. + + - FIXME added for public: + - `libssh2_channel_window_read_ex()` `read_avail` argument type. + - `libssh2_base64_decode()` `datalen` argument type. + + - fix possible overflow in `sftp_read()`. + + Ref: 4552c73cd58fccb1fc49cb0f25f86619133e560f + + - formatting in `wincng.h`. + + See warning details in the PR's individual commits. + + Cherry-picked from #846 + Closes #876 + +GitHub (24 Mar 2023) +- [Viktor Szakats brought this change] + + cmake: automatic exports macro tidy-up (#875) + + In a recent CMake update I left the original CMake EXPORTS macro + unchanged (`libssh2_EXPORTS`) for compatibility. + + However, that macro was also recently added [1] and not present in an + official release yet, so we might as well just use the new native one + instead (`libssh2_shared_EXPORTS`), defined by CMake automatically. + This way we don't need to define the old macro manually. + + CMake forms this macro from the lib's internal name as defined in + `add_library()` by appending `_EXPORTS`. That target name changed from + `libssh2` to `libssh2_shared` after introducing dual shared + static + builds in the recent update. + + If we're here, add a new, stable, build-tool agnostic macro with the + same effect, for non-CMake use: `LIBSSH2_EXPORTS` + + [1] 1f0fe7443a1ecddd320f2c693607b2afee9bbe2f (2021-10-26) + + Follow-up to 4e2580628dd1f8dc51ac65ac747ebcf0e93fa3d1 + +- [Viktor Szakats brought this change] + + maketgz: add .xz, .bz2, .zip source archive formats (#874) + + Copied from curl: + https://github.com/curl/curl/blob/4528690cd51e5445df74aef8f83470a602683797/maketgz#L174-L222 + + [ci skip] + +Viktor Szakats (23 Mar 2023) +- dist: delete reference to recently deleted file [ci skip] + + Follow-up to b8762c1003d97e109efa587bdc760ff9873949eb + +GitHub (23 Mar 2023) +- [Viktor Szakats brought this change] + + cmake: separate compilation passes for shared/static (#871) + + Before this patch, cmake did a single compilation pass when we enabled + both shared and static lib targets. This saves build time (esp. with + MinGW targets and cross-compiling), but has the disadvantage that static + libs built this way must have PIC enabled (offering slightly less + performance) and `dllexport` enabled also, which means that executables + linking the static libssh2 lib export its public symbols. + + To avoid these downsides, this patch separates the two passes and + creates a non-PIC, non-`dllexport` static lib, even when also building + the shared lib. + +- [Viktor Szakats brought this change] + + ci: test with OpenSSL v1.1.1 on AppVeyor (#870) + + Was: v1.0.2. + + Keep using v1.0.2 with the static-only test. To make sure we don't break + support. + +- [Viktor Szakats brought this change] + + ci: speed up static-only build tests on AppVeyor (#868) + + - limit static-only build to a single platform (x64). + + - skip running ctest for the static-only build. + + - use MSVS 2013 for static-only builds. It's faster. + + - run static-only test before WinCNG ones. Otherwise it's often skipped + due to WinCNG failures (#804). + +- [Viktor Szakats brought this change] + + cmake: fix error with static lib off and example/tests on (#869) + + Regression from 4e2580628dd1f8dc51ac65ac747ebcf0e93fa3d1 + +- [Viktor Szakats brought this change] + + ci: parallelize more (#867) + +- [Viktor Szakats brought this change] + + cmake/src: move build options before target definitions (#864) + + To allow more flexibility when defining targets. + +- [Viktor Szakats brought this change] + + ci: use static+shared builds to cut number of cmake jobs (#865) + + With CMake builds supporting static-shared libssh2 builds in a single + pass, we no longer need to run static and shared jobs separately. For + the same effect it's enough to run builds with both shared and static + builds enabled. Halving CI jobs. + + We add an extra run to test the CMake config-path without shared builds + enabled. + + This allows to add useful jobs, e.g. MSVS 2022 or ZLIB-enabled builds + for Windows, valgrind builds or other useful stuff, without stretching + CI run times further. + + Ref: #863 + +Viktor Szakats (22 Mar 2023) +- cmake: allow building static + shared libs in a single pass + + - `BUILD_SHARED_LIBS=ON` no longer disables building static lib. + + When set, we build the static lib with PIC enabled. + + For shared lib only, set `BUILD_STATIC_LIBS=OFF`. For static lib + without PIC, leave this option disabled. + + - new setting: `BUILD_STATIC_LIBS`. `ON` by default. + + Force-enabled when building examples or tests (we build those in + static mode always.) + + - fix to exclude Windows Resource from the static lib. + + - fix to not overwrite static lib with shared implib on Windows + platforms using identical suffix for them (MSVS). By using + `libssh2_imp<.ext>` implib filename. + + - add support for `STATIC_LIB_SUFFIX` setting to set an optional suffix + (e.g. `_static`) for the static lib. (experimental, not documented). + Overrides the above when set. + + - fix to set `dllexport` when building shared lib. + + - set `TrackFileAccess=false` for MSVS. + + For faster builds, shorter verbose logs. + + - tests: new test linking against shared libssh2: `test_warmup_shared` + + - tests: simplify 'runner' lib by merging 3 libs into a single one. + + - tests: drop hack from `test_keyboard_interactive_auth_info_request` + build. + + We no longer need to compile `src/misc.c` because we always link + libssh2 statically. + + - tests: limit `FIXTURE_WORKDIR=` to the `runner` target. + + TL;DR: Default behavior unchanged: static (no-PIC), no shared. + Enabling shared unchanged, but now also builds a static (PIC) + lib by default. + + Based-on: b60dca8b6450a9729670986d2899cca54ccdbb6d #547 by berney on github + Fixes: #547 + Fixes: #675 + Closes: #863 + +- include: silence warnings with casts in public `libssh2_sftp.h` + + Avoid triggering warnings in macros coming from public libssh2 headers. + + Cherry-picked from: #846 + Closes #862 + +- example, tests: address compiler warnings + + Fix or silence all C compiler warnings discovered with (or without) + `PICKY_COMPILER=ON` (in CMake). This means all warnings showing up in + CI (gcc, clang, MSVS 2013/2015), in local tests on macOS (clang 14) and + Windows cross-builds using gcc (12) and llvm/clang (14/15). + + Also fix the expression `nread -= nread` in `sftp_RW_nonblock.c`. + + Cherry-picked from: #846 + Closes #861 + +- openssl: require `EVP_aes_128_ctr()` support + + libssh2 built with OpenSSL and without its `EVP_aes_128_ctr()`, aka + `HAVE_EVP_AES_128_CTR`, option are working incorrectly. This option + wasn't always auto-detected by autotools up until recently (#811). + Non-cmake, non-autotools build methods never enabled it automatically. + + OpenSSL supports this options since at least v1.0.2, which is already + EOLed and considered obsolete. OpenSSL forks (LibreSSL, BoringSSL) + supported it all along. + + In this patch we enable this option unconditionally, now requiring + OpenSSL supporting this function, or one of its forks. + + Also modernize OpenSSL lib references to what 1.0.2 and newer versions + have been using. + + Fixes #739 + +- wincng: fix memory leak in `_libssh2_dh_secret()` + + Patch-by: iruis on github + Assisted-by: Marc Hörsken + Bug #846, commit e3487092ef9553af67633c6747cb9ab2f86465e0. + Fixes #856 + Closes #858 + +GitHub (19 Mar 2023) +- [Viktor Szakats brought this change] + + nw, os400, watcom: stop setting unused macros [ci skip] (#859) + +Viktor Szakats (19 Mar 2023) +- cmake: fix `ENABLE_WERROR=ON` breaking auto-detections + + - cmake: fix compiler warnings in `CheckNonblockingSocketSupport`. + detection functions. + + Without this, these detections fail when `ENABLE_WERROR=ON`. + + - cmake: disable ENABLE_WERROR for MSVC during symbol checks in `src`. + + CMake's built-in symbol check function `check_symbol_exists()` + generate warnings with MSVC. With warnings considered errors, these + detections fail permanently. Our workaround is to disable + warnings-as-errors while running these checks. + + ``` + CheckSymbolExists.c(8): warning C4054: 'type cast': from function pointer '__int64 (__cdecl *)(const char *,char **,int)' to data pointer 'int *' + in `return ((int*)(&strtoll))[argc];` + ``` + + Ref: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46537222/job/4vg4yg333mu2lg9b + + - example: replace `strcasecmp()` with C89 `strcmp()`. + + To avoid using CMake symbol checks in `example`. + + Another option is to duplicate the `check_symbol_exists()` workaround + from `src`, but I figure it's not worth the complexity. We use + `strcasecmp()` solely to check optional command-line options for + example programs, and those are fine as lower-case. + + Without this, these detections fail when `ENABLE_WERROR=ON`. + + - also delete `__function__` detection/use in `example`. + + To avoid the complexity for the sake of using it at a single place in + of the example's error branch. Replace that use with a literal name of + the function. + + - cmake: also use `CMakePushCheckState` functions instead of manual + save/restore. + + Closes #857 + +- build: improve a test build workaround with bcrypt + + - cmake: extend workaround for linking a test with shared libssh2. + + One of the tests uses internal libssh2 functions, and with CMake it + compiles `src/misc.c` directly for this. `misc.c` references bcrypt / + blowfish code. This needs a workaround for build configs where libssh2 + doesn't export these. + + Before this patch, we enabled this workaround for MSVC. + + In the patch we extend this to all Windows. There is no CI test for + this, but gcc and llvm/clang + mingw64 builds also need it. This may + well apply to other configurations (it should, as shared libs are not + supposed to export internal functions), so also make it easy to enable + it at a single point. + + [ autotools builds force-link this one test against static libssh2. ] + + - make `misc.c` not depend on bcrypt. + + By moving out our `bcrypt_pbkdf()` wrapper into `bcrypt_pbkdf.c` + itself. + + This allows to compile `misc.c` into tests without pulling in bcrypt / + blowfish functions, and simplify the above workaround. + + Source code uses `HAVE_BCRYPT_PBKDF`, a leftover from original bcrypt + source. We never define this inside libssh2. Defining it breaks the + build, and this patch doesn't change that. + + - make `bcrypt_pbkdf()` static. + + While here, make the low-level `bcrypt_pbkdf()` function static to + avoid namespace pollution. + + Closes #855 + +GitHub (17 Mar 2023) +- [Viktor Szakats brought this change] + + ci: more timeout adjustments (#853) + + - add timeout to SSH connection wait loop in AppVeyor test prep. + (2 minutes) + + - switch to per-step timeout for GitHub CI cmake/ctest runs. + (10 minutes) + + ctest timeout (of 450 seconds) didn't seem to make any difference. + +Viktor Szakats (17 Mar 2023) +- ci: set timeout to ctest and GitHub CI jobs + + - `ctest` shows a the default timeout '10000000' (turns out to be + in seconds), cause infinite waits e.g. in case the necessary server + worker is not available. + + CMake CI tests take approx: + - GitHub / Linux : 125 seconds + - AppVeyor / Windows: 300 seconds + + New timeouts are: 450 and 900 seconds respectively. + + - set timeouts for style-check, fuzz, Linux and Windows GitHub CI + jobs to avoid hanging forever. + + Also: + + - move `choco install` to before_test to make builds start faster + in `appveyor.yml`. + + - fix some yamllint `ON`/`OFF`-confusion issue by quoting these + values in `appveyor.yml`. + + - fix indentation in `appveyor.yml`. + + - convert to GitHub workflows to LF line-ending. + + Ref: https://github.com/libssh2/libssh2/pull/655#issuecomment-1472853493 + + Closes #851 + +GitHub (17 Mar 2023) +- [Viktor Szakats brought this change] + + ci: update mbedTLS repo URL, delete Travis CI (#850) + + Last Travis CI session run on 2021-11-18. + + Ref: https://app.travis-ci.com/github/libssh2/libssh2 + Ref: https://travis-ci.org/github/libssh2/libssh2/builds + +- [Viktor Szakats brought this change] + + appveyor.yml: reorder tests to return relevant feedback earlier (#849) + + - build x64 first + + x64 is the more interesting target. Most type conversion issues are + revealed here. Also more commonly used by now. + + - test VS 2013 earlier + + - test WinCNG earlier + + - delete reference to no longer used VS 2008 + + After this patch we end up starting with all Shared builds (2015, 2013, + OpenSSL, WinCNG), then continue with Static ones. Shared/Static makes + a minor if any difference in builds/tests compared to different VS + versions of TLS backends. + + -- + + CI run times: + + Preparation + build takes: + 8 x VS2015 4.5 mins -> total: 36 + 8 x VS2013 2 mins -> total: 16 + Total: 52 mins + + with our 30 tests, it increases to: + 8 x VS2015 8-10 mins -> total: 72 + 8 x VS2013 6- 9 mins -> total: 60 + Total: 132 mins + + Without tests: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46475315 + With tests: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46480549 + +Dan Fandrich (14 Mar 2023) +- src: check for NULL pointer passed to _libssh2_get_string + + Callers should be protecting against this, but it's prudent to check + here anyway. + + Fixes #802 + Closes #848 + +Viktor Szakats (14 Mar 2023) +- appveyor.yml: choco install improvements [ci skip] + + - avoid outputting 4000 log lines by hiding the progress bar. + Reduces log size by 5x. + + - decrease timeout (from the default 2700 seconds). + + - omit unnecessary output. + + Tested as part of #846 + +GitHub (14 Mar 2023) +- [Jakob Egger brought this change] + + build: update instructions for autoreconf (#847) + + The "convenience script" talks about the "buildconf" file, + which is no longer recommended. + +- [Viktor Szakats brought this change] + + win32: set HAVE_STRTOLL with MSVS 2013 and newer (#845) + + As in curl: + https://github.com/curl/curl/blob/7fa6e36583b52dd8f1e639b370c9a2849be81b54/lib/config-win32.h#L221 + +- [Viktor Szakats brought this change] + + GNUmakefile: move HAVE_STRTOLL to libssh2_config.h [ci skip] (#844) + +- [Viktor Szakats brought this change] + + src: silence unused variable warnings (#843) + +Viktor Szakats (13 Mar 2023) +- GNUmakefile: add wolfSSL support + major rework + + - add wolfSSL support. + - reduce size and redundant logic. + - fix a bunch of small issues. + - rework configuration, now with: `CC`, `AR`, `RC`, `TRIPLET`, `CFLAGS`, + `CPPFLAGS`, `LDFLAGS`, `RCFLAGS`, `LIBS`, `LIBSSH2_DLL_SUFFIX`, + `LIBSSH2_LDFLAGS_LIB`, `LIBSSH2_LDFLAGS_BIN` (and more). + - merge examples build into the main Makefile. + - relative dependency paths are now the same for building libssh2 or + examples. + - drop detection for obsolete OpenSSL versions (can be configure via new + `OPENSSL_LIBS`). + - merge dev/dist distribution zip options. + - build libssh2 with `-DHAVE_STRTOLL`. + - tidy-up. + - build examples in static mode by default (use `DYN` to build them in + shared mode). + - drop forced (in non-debug mode) `-O2`. + - drop Win9x support. + - deprecate `ARCH` in favour of custom options and `TRIPLET`. + - drop Windows resources from examples for simplicity + - drop `WITH_ZLIB`. Default `ZLIB_PATH` to enable zlib support. + - drop `LIBSSH2_DLL_A_SUFFIX`, use standard value `.dll` (as in + `libssh2.dll.a`). + - always link `bcrypt` (for LibreSSL and OpenSSL) and `crypt32` + (for wolfSSL). + - unhide executed build commands. + - fix mbedTLS `lib` path + - drop specific options to force static linking. Custom options seems + a better way for this. + - based on similar work made for curl: + https://github.com/curl/curl/commit/a8861b6ccdd7ca35b6115588a578e36d765c9e38 + + Closes #842 + +GitHub (13 Mar 2023) +- [Viktor Szakats brought this change] + + wincng: fix memory leak in libssh2_dh_key_pair() (#829) + + Fixes #722 + +- [Viktor Szakats brought this change] + + src: C89-compliant _libssh2_debug() macro (#831) + + Before this patch, with debug logging disabled, libssh2 code used a + variadic macro to catch `_libssh2_debug()` calls, and convert them to + no-ops. In certain conditions, it used an empty inline function instead. + + Variadic macro is a C99 feature. It means that depending on compiler, + and build settings, it littered the build log with warnings about this. + + The new solution uses the trick of passing the variable arg list as a + single argument and pass that down to the debug function with a regular + macro. When disabled, another regular C89-compatible macro converts it + to a no-op. + + This makes inlining, C99 variadic macros and maintaining the conditions + for each unnecessary and also makes the codebase compile more + consistently, e.g. with forced C standards and/or picky warnings. + + TL;DR: It makes this feature C89-compliant. + +- [Viktor Szakats brought this change] + + openssl: fix possible compiler warning in macro condition (#839) + + Building with wolfSSL or pre-OpenSSL v1.1.1 triggered it. + + ``` + ../src/openssl.h:130:5: warning: 'LIBRESSL_VERSION_NUMBER' is not defined, evaluates to 0 [-Wundef] + LIBRESSL_VERSION_NUMBER >= 0x3070000fL + ^ + ``` + + Regression from 2e2812dde8c1fc9b48eca592823770ab2e601f7a + +- [Viktor Szakats brought this change] + + GNUmakefile: cleanups [ci skip] (#840) + + - indent + - sync `test/GNUmakefile` with main + - delete `RANLIB` + - use `else if` + - use more `?=` + - use ASCII-7 copyright symbol (in test) + +- [Viktor Szakats brought this change] + + win32: convert tabs to spaces [ci skip] (#838) + + Also strip stray newlines from `win32/rules.mk`. + +- [Viktor Szakats brought this change] + + ci: retry choco install on appveyor (#837) + + Trying to mitigate occasional intermittent failures while installing + docker. + + Ref: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46460704/job/g3t7bro6ta6n3pk6#L52 + +- [Viktor Szakats brought this change] + + cmake: drop unnecessary exception for warmup build (#835) + +- [Viktor Szakats brought this change] + + cmake: reflect minimum version in docs (#834) + + Follow-up to 505ea626b6e125b7ce15caf453b522192008a884 + +- [Viktor Szakats brought this change] + + cmake: add wolfSSL support to tests (#833) + + wolfSSL supports building with zlib as a dependency, that's the reason + for the ZLIB logic in the patch. + + Also add it to `docs/INSTALL_CMAKE.md` and to the help text in + `src/CMakeLists.txt`. + + Running tests not actually tested. + + Follow-up to 9f217a17f6f3c2047c4a1668a5c037a75a02abfd + + Ref: #817 + +- [Viktor Szakats brought this change] + + tests: workaround for intermittent first test failures (#832) + + Flakiness got continously worse these last days. It didn't seem related + to recent commits. Flakiness also picked up in GitHub CI runs, something + rarely seen before. Manual restart consistently fixed them. + + The repeating pattern was the _first_ test (`test_hostkey`) failing, + with `libssh2_session_handshake failed (-13): Failed getting banner`. + Failures came after a lengthy wait, suggesting a timeout. + + I then reversed the order of the first two tests, and it turned out that + the _first_ test failed again (`test_hostkey_hash`). Also pointing to a + timeout issue. + + Then I added a dummy test to "warm up" whatever needs warming up in the + layers of CI + Docker + ssh server and their interconnects. This helped, + and GitHub CI tests run without failure right for the first time. + AppVeyor CI also improved a little. + + This patch adds a new first test called `test_warmup`, that creates a + new libssh2 session, and exits with success even if that attempt failed. + + A stop-gap solution at best, and there is no guarantee it will continue + to fix this or similar future issues, but it's also untenable to have + almost every CI run fail for intermittent reasons. + + In some [1] cases [2] it's not the first test failing intermittently. + That's a different issue, and this patch doesn't fix it. + + [1] #804 + [2] https://ci.appveyor.com/project/libssh2org/libssh2/builds/46440828/job/8rej6cq6itg7vc4w#L500 + +- [Viktor Szakats brought this change] + + cmake: detect HAVE_SNPRINTF for tests (#830) + + Turns out `test_keyboard_interactive_auth_info_request.c` requires + `src/libssh2_priv.h`, which in turn requires a correctly set + `HAVE_SNPRINTF`. + + Follow-up to 4cdf785cd313c3272d04c2ef7458a35d44533d8b. + +- [Viktor Szakats brought this change] + + cmake: unset forced CMAKE_C_STANDARD 90 (#822) + + Added in cf80f2f4b5255cc85a04ee43b27a29c678c1edb1 (on 2016-08-14), + with the title "Basic dockerised test suite". + + It's not clear why a C standard was explicitly set, but a side-effect + of this is that CMake-built binaries diverged from ones built with + autotools or GNU Make (using the same compiler and configuration). + + Another issue is that this may introduce ABI incompatibility with + binaries built with a different C standard flag, e.g. the C compiler + default or one used for other components of a final app. + + Seems unlikely, but if our tests require this option, we should set it + for the CI builds only? + +- [Viktor Szakats brought this change] + + example: silence MSVS 2013 C4127 warnings (#828) + +- [Viktor Szakats brought this change] + + cmake: reposition ws2_32 to make binutils ld work again (#827) + + This restores socket libs to their pre-regression positions. + + Without this, `ld` doesn't find `ws2_32` symbols when referenced + from TLS libs. + + Regression from 31fb8860dbaae3e0b7d38f2a647ee527b4b2a95f + +- [Viktor Szakats brought this change] + + fix compiling with LIBSSH2_NO_CLEAR_MEMORY and OpenSSL (#825) + + Regression from a0e424a51c27cc27af611ba20d134f9a9ae35273 + + Fixes #824 + +- [Viktor Szakats brought this change] + + snprintf: add missing prototype for local replacement (#820) + + Should fix these warnings with MSVS 2013 and older: + `agent.c(294): warning C4013: '_libssh2_snprintf' undefined; assuming extern returning int` + + Follow-up to 4cdf785cd313c3272d04c2ef7458a35d44533d8b. + +- [Viktor Szakats brought this change] + + build: set _FILE_OFFSET_BITS=64 for mingw-w64 (#821) + + autotools builds already did auto-detect and set this mingw-specific + macro, but CMake and GNU Make builds did not. This patch fixes that. + + Necessary for `src/scp.c`. + +- [Viktor Szakats brought this change] + + cmake: add os400qc3.c to SOURCES (#826) + + This re-syncs the list of compiled objects in cmake builds with + non-cmake builds. + + Follow-up to 16619a8eddec35bb8582d1c334db0fc13b0817c4. + +- [Viktor Szakats brought this change] + + build: silence bogus C4127 warnings with MSVS 2013 and earlier (#819) + + E.g.: + `channel.c(370): warning C4127: conditional expression is constant` + Ref: + https://ci.appveyor.com/project/libssh2org/libssh2/builds/46437333/job/5rak1vcl9hue31ei#L190 + +- [Viktor Szakats brought this change] + + cmake: use only needed socket libs when checking non-blocking sockets (#816) + + Based on patch by Christian Beier. + + Fixes #694 + Closes #712 + +- [Viktor Szakats brought this change] + + cmake: update openssl dll list (#818) + + Add OpenSSL 3 and versionless DLL names. Also modernize warning messages + and variable names. + + Do we need the OpenSSL-Windows-specific check and the related + `RUNTIME_DEPENDENCIES` feature? The list of OpenSSL DLLs was out of date + for 1.5 years without anybody noticing. Keeping it fresh is a chore and + copying around DLL dependencies rarely helps as much as expected. This + check also results in unuseful warnings in certain build scenarios, e.g. + when linking to OpenSSL statically. + +- [Viktor Szakats brought this change] + + cmake: add wolfSSL support (#817) + + Implement wolfSSL support for libssh2 when building with CMake. + + Configuration example from curl-for-win: + ``` + -DCRYPTO_BACKEND=wolfSSL + -DWOLFSSL_LIBRARY=/path-to/wolfssl/lib/libwolfssl.a + -DWOLFSSL_INCLUDE_DIR=/path-to/wolfssl/include + ``` + + Module `cmake/Findwolfssl.cmake` copied from: + https://github.com/ngtcp2/ngtcp2/blob/e4d920c4b7a350d63b6978c68b216b76faa12635/cmake/Findwolfssl.cmake + via commit: + https://github.com/ngtcp2/ngtcp2/commit/296396d3730b721ad97f9de22f525400f8524c0e + by Stefan Eissing + +- [Viktor Szakats brought this change] + + cmake: restore non-Windows socket lib detection (#815) + + I mistakenly pruned some non-Windows logic, also missing the fact that + our local `check_function_exists_may_need_library()` set the `NEED_*` + variables. Oddly, only `src` imported this function, yet also `examples` + and `tests` called it indirectly. The referenced `HAVE_SOCKET` / + `HAVE_INET_ADDR` variables might be coming from an upstream CMake + project? Leaving those there also, just in case. + + Regression from 31fb8860dbaae3e0b7d38f2a647ee527b4b2a95f + +Viktor Szakats (7 Mar 2023) +- build: more fixes and tidy-up (mostly for Windows) + + - cmake: always link `ws2_32` on Windows. Also add it to `libssh2.pc`. + + Fixes #745 + + - agent: fix gcc compiler warning: + `src/agent.c:296:35: warning: 'snprintf' output truncated before the last format character [-Wformat-truncation=]` + + - autotools: fix `EVP_aes_128_ctr` detection with binutils `ld` + + The prerequisite for a successful detection is setting + `LIBS=-lbcrypt` if the chosen openssl-compatible library requires + it, e.g. libressl, or quictls/openssl built with + `-DUSE_BCRYPTGENRANDOM`. + + With llvm `lld`, detection works out of the box. With binutils `ld`, + it does not. The reason is `ld`s world-famous pickiness with lib + order. + + To fix it, we pass all custom libs before and after the TLS libs. + This ugly hack makes `ld` happy and detection succeed. + + - agent: fix Windows-specific warning: + `src/agent.c:318:10: warning: implicit conversion loses integer precision: 'LRESULT' (aka 'long long') to 'int' [-Wshorten-64-to-32]` + + - src: fix llvm/clang compiler warning: + `src/libssh2_priv.h:987:28: warning: variadic macros are a C99 feature [-Wvariadic-macros]` + + - src: support `inline` with `__GNUC__` (llvm/clang and gcc), fixing: + ``` + src/libssh2_priv.h:990:8: warning: extension used [-Wlanguage-extension-token] + static inline void + ^ + ``` + + - blowfish: support `inline` keyword with MSVC. + + Also switch to `__inline__` (from `__inline`) for `__GNUC__`: + https://gcc.gnu.org/onlinedocs/gcc/Inline.html + https://clang.llvm.org/docs/UsersManual.html#differences-between-various-standard-modes + + - example/test: fix MSVC compiler warnings: + + - `example\direct_tcpip.c(209): warning C4244: 'function': conversion from 'unsigned int' to 'u_short', possible loss of data` + - `tests\session_fixture.c(96): warning C4013: 'getcwd' undefined; assuming extern returning int` + - `tests\session_fixture.c(100): warning C4013: 'chdir' undefined; assuming extern returning int` + + - delete unused macros: + - `HAVE_SOCKET` + - `HAVE_INET_ADDR` + - `NEED_LIB_NSL` + - `NEED_LIB_SOCKET` + - `HAVE_NTSTATUS_H` + - `HAVE_NTDEF_H` + + - build: delete stale zlib/openssl version numbers from path defaults. + + - cmake: convert tabs to spaces, add newline at EOFs. + + Closes #811 + +- cmake: make `test_read` runs cross-build-friendly + + Improve tests added in 7487dcf4b4ddae54b2a850737789b57b4251b0ae by + running `test_read` commands directly. This makes external shell/batch + files unnecessary, and is friendlier with cross-builds and when run + from non-default shells, like MSYS2. + + Also extend CRYPT/MAC test error messages with the CRYPT/MAC name. + + External runner shell scripts kept for future use. + + Closes #814 + +- src: enable clear memory on all platforms + + - convert `_libssh2_explicit_zero()` to macro. This allows inlining + where supported (e.g. `SecureZeroMemory()`). + + - replace `SecureZeroMemory()` (in `wincng.c`) and + `LIBSSH2_CLEAR_MEMORY`-guarded `memset()` (in `os400qc3.c`) with + `_libssh2_explicit_zero()` macro. + + - delete `LIBSSH2_CLEAR_MEMORY` guards, which enables secure-zeroing + universally. + + - add `LIBSSH2_NO_CLEAR_MEMORY` option to disable secure-zeroing. + + - while here, delete double/triple inclusion of `misc.h`. + `libssh2_priv.h` included it already. + + Closes #810 + +- cmake: bump minimum version to 3.1 (from 2.8.12) + + This allows to delete some fallback code. + + CMake release dates: + - 2014-12-15: 3.1 + - 2013-10-07: 2.8.12 + + Closes #813 + +- snprintf: unify fallback logic + + Before this patch, the `snprintf()` fallback logic for envs not + supporting this function (i.e. Visual Studio 2013 and older) varied + depending on build tool, and used different techniques in examples, + tests and libssh2 itself. + + This patch aims to apply a common logic to libssh2 and examples/tests. + + - libssh2: use local `snprintf()` fallback with all build tools. + + We already had a local implementation, but only with CMake. Move that + to the library as `_libssh2_snprintf()`, and map `snprintf()` to it + when `HAVE_SNPRINTF` is not set. + + Also change the length type from `int` to `size_t`, and fix + formatting. + + - set or detect `HAVE_SNPRINTF` in non-CMake builds. + + Detect in autotools. Keep existing logic in `win32/libssh2_config.h`. + Always set for OS/400, NetWare and VMS, keeping existing behaviour. + (OS/400 builds use a different local implementation) + + - examples/tests: drop the CMake-specific fallback logic and map + `snprintf()` to `_snprintf()` for old MSVC versions, like we did + before with other build tools. This is unsafe, but should be fine for + these uses. + + - `win32/libssh2_config.h`: make it easier to read. + + Closes #812 + +- cmake: build fixes with OpenSSL/LibreSSL on Windows + + - Link `bcrypt` for newer (non-fork) OpenSSL. + + - Link `bcrypt` and `ws2_32` when using (non-fork) OpenSSL or LibreSSL, + to allow `Looking for EVP_aes_128_ctr` detecting this feature. + + With the feature available, but not found by CMake, build failed with: + `openssl.c:636:21: error: incompatible integer to pointer conversion assigning to 'EVP_CIPHER *' (aka 'struct evp_cipher_st *') from 'int' [-Wint-conversion]` + + Closes #809 + +- build fixes and improvements (mostly for Windows) + + - in `hostkey.c` check the result of `libssh2_sha256_init()` and + `libssh2_sha512_init()` calls. This avoid the warning that we're + ignoring the return values. + + - fix code using `int` (or `SOCKET`) for sockets. Use libssh2's + dedicated `libssh2_socket_t` and `LIBSSH2_INVALID_SOCKET` instead. + + - fix compiler warnings due to `STATUS_*` macro redefinitions between + `ntstatus.h` / `winnt.h`. Solve it by manually defining the single + `STATUS` value we need from `ntstatus.h` and stop including the whole + header. + Fixes #733 + + - improve Windows UWP/WinRT builds by detecting it with code copied + from the curl project. Then excluding problematic libssh2 parts + according to PR by Dmitry Kostjučenko. + Fixes #734 + + - always use `SecureZeroMemory()` on Windows. + + We can tweak this if not found or not inlined by a C compiler which + we otherwise support. Same if it causes issues with UWP apps. + + Ref: https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa366877(v=vs.85) + Ref: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlsecurezeromemory + + - always enable `LIBSSH2_CLEAR_MEMORY` on Windows. CMake and + curl-for-win builds already did that. Delete `SecureZeroMemory()` + detection from autotools' WinCNG backend logic, that this + setting used to depend on. + + TODO: Enable it for all platforms in a separate PR. + TODO: For clearing buffers in WinCNG, call `_libssh2_explicit_zero()`, + insead of a local function or explicit `SecureZeroMemory()`. + + - Makefile.inc: move `os400qc3.h` to `HEADERS`. This fixes + compilation on non-unixy platforms. Recent regression. + + - `libssh2.rc`: replace copyright with plain ASCII, as in curl. + + Ref: curl/curl@1ca62bb + Ref: curl/curl#7765 + Ref: curl/curl#7776 + + - CMake fixes and improvements: + + - enable warnings with llvm/clang. + - enable more comprehensive warnings with gcc and llvm/clang. + Logic copied from curl: + https://github.com/curl/curl/blob/233810bb5f6c5e7bedfc10bdd36607b958c0cfe4/CMakeLists.txt#L131-L148 + - fix `Policy CMP0080` CMake warning by deleting that reference. + - add `ENABLE_WERROR` (default: `OFF`) option. Ported from curl. + - add `PICKY_COMPILER` (default: `ON`) option, as known from curl. + + It controls both the newly added picky warnings for llvm/clang and + gcc, and also the pre-existing ones for MSVC. + + - `win32/GNUmakefile` fixes and improvements: + + - delete `_AMD64_` and add missing `-m64` for x64 builds under test. + - add support for `ARCH=custom`. + It disables hardcoded Intel 64-bit and Intel 32-bit options, + allowing ARM64 builds. + - add support for `LIBSSH2_RCFLAG_EXTRAS`. + To pass custom options to windres, e.g. in ARM64 builds. + - add support for `LIBSSH2_RC`. To override `windres`. + - delete support for Metrowerks C. Last released in 2004. + + - `win32/libssh2_config.h`: delete unnecessary socket #includes + + `src/libssh2_priv.h` includes `winsock2.h` and `ws2tcpip.h` further + down the line, triggered by `HAVE_WINSOCK2_H`. + + `mswsock.h` does not seem to be necessary anymore. + + Double-including these (before `windows.h`) caused compiler failures + when building against BoringSSL and warnings with LibreSSL. We could + work this around by passing `-DNOCRYPT`. Deleting the duplicates + fixes these issues. + + Timeline: + 2013: c910cd382dfa07fed2adaabf688af9e4a084fa1d deleted `mswsock.h` from `src/libssh2_priv.h` + 2008: 8c43bc52b1e3de2c8fc7899a80aec0e98de4e2d8 added `winsock2.h` and `ws2tcpip.h` to `src/libssh2_priv.h` + 2005: dc4bb1af967d2c53e90349f2f37324c622e714f5 added the now deleted #includes + + - delete or replace `LIBSSH2_WIN32` with `WIN32`. + + - replace hand-rolled `HAVE_WINDOWS_H` macro with `WIN32`. Also delete + its detections/definitions. + + - delete unused `LIBSSH2_DARWIN` macro. + + - delete unused `writev()` Windows implementation + + There is no reference to `writev()` since 2007-02-02, commit + 9d55db6501aa4e21f0858cf36cdc2ddc11b96e83. + + - fix a bunch of MSVC / llvm/clang / gcc compiler warnings: + + - `warning C4100: '...': unreferenced formal parameter` + - using value of undefined PP macro `LIBSSH2DEBUG` + - missing void from function definition + - `if()` block missing in non-debug builds + - unreferenced variable in non-debug builds + - `warning: must specify at least one argument for '...' parameter of variadic macro [-Wgnu-zero-variadic-macro-arguments]` + in `_libssh2_debug()` + - `warning C4295: 'ciphertext' : array is too small to include a terminating null character` + - `warning C4706: assignment within conditional expression` + - `warning C4996: 'inet_addr': Use inet_pton() or InetPton() instead or + define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings` + By suppressning it. Would be best to use inet_pton() as suggested. + On Windows this needs Vista though. + - `warning C4152: nonstandard extension, function/data pointer conversion in expression` + (silenced locally) + - `warning C4068: unknown pragma` + + Ref: https://ci.appveyor.com/project/libssh2org/libssh2/builds/46354480/job/j7d0m34qgq8rag5w + + Closes #808 + +Dan Fandrich (1 Mar 2023) +- Add tests to check individual crypt & HMAC methods + + One specific crypt or hmac method is requested to be negotiated, then + several MB of data is transferred. + +- Add test to read lots of data over a channel + + Connects to the ssh server then downloads several MB of data. This + tests the data transfer path as well as boundary cases in packet + handling as data is split into smaller SSH blocks. + +GitHub (27 Feb 2023) +- [Will Cosgrove brought this change] + + Disable deprecated warnings for OpenSSL 3 #805 (#806) + + Disable deprecated warnings (for now) when building against OpenSSL 3 for a clean build. + + Reported: + Daniel Stenberg + +Dan Fandrich (24 Feb 2023) +- Fix a couple of warnings of errors in MSVC builds + + Two warnings (in tests & examples) in particular would cause problems: + bad format causing invalid data output or a bad chdir due to out of + scope buffer use. + +- tests: Support running tests in out-of-tree builds + + Various files are found by referencing the srcdir environment variable + in that case. + + Closes #801 + +- Improve the ssh2 example program to run a command + + This performs better as an example since it shows more working code, and + in the simplest possible way. It also turns the program into an actually + useful tool out of the box, able to run an arbitrary command (with one + restriction) on a remote machine and return the response, without + needing to touch the source. + + Closes #800 + +GitHub (14 Feb 2023) +- [Will Cosgrove brought this change] + + Add NULL session check to _libssh2_error_flags() (#796) + + Don't dereference null if a null session happens to make it into _libssh2_error_flags() + +Dan Fandrich (7 Feb 2023) +- Reorder AES crypt methods so stronger ones are first + + This make it more likely that a stronger one will be negotiated rather + than a weaker variant. + +- CI: update uses: dependencies to the latest versions + + We were seeing some deprecation warning messages on some of the older + ones. + +- transport.c: Add some comments + +- Add missing files to automake makefiles & build tests + + Many files have been added to the cmake build files but not the automake + ones in recent years. Missing ones have been added so automake "make + dist" will now create a usable tar ball. + + The integration tests using Docker are now built with automake as well + (with "make check"). They are not run yet since they aren't working yet + on Linux. + +- tests: Fix gcc compile warnings + + These were mostly due to missing and non-ANSI prototypes. + +- Enable trace debugging in example/ssh2 + + This is intended to be a test program, so debugging is likely to be + useful by default. + +- Improve example/ssh2 to allow unmodified use of public key auth + + The previous hard-coded key file paths were not valid for normal users. + Make the paths relative to the user's home directory instead so they + can work out of the box. Add a banner showing what connection will be + attempted to make it easier for the user to see what is being attempted. + Enable trace debugging since this is designed as a test program. + +GitHub (13 Dec 2022) +- [Viktor Szakats brought this change] + + openssl.h: enable ed25519 for LibreSSL 3.7.0 (#778) + + This brings LibreSSL libssh2 builds on par with OpenSSL. + +Dan Fandrich (5 Dec 2022) +- configure.ac: check for sys/param.h + + This file is required by glibc for the test suite. + +GitHub (12 Nov 2022) +- [Viktor Szakats brought this change] + + tests: add option to run tests without docker (#762) + + via `export OPENSSH_NO_DOCKER=1`. + + SSH server host can be set via: + `export OPENSSH_SERVER_HOST=127.0.0.1` + + SSH server port via existing: + `export OPENSSH_SERVER_PORT=4711` + + This requires more work to be usable out of the box. The necessery sshd + config is (partly) embedded into `tests/openssh_server/Dockerfile`. + + After this patch, it is possible to run tests in envs where docker is + not installed or not available, by running a preconfigured, + non-containerized sshd. + +- [Michael Buckley brought this change] + + Skip leading \r and \n characters in banner_receive() (#769) + + Fixes #768 + + Credit: + Michael Buckley + +- [Zenju brought this change] + + Fixed error handling of _libssh2_packet_requirev callers (#767) + + Notes: + + some callers of _libssh2_packet_requirev() fail to set _libssh2_error(). + This creates the situation where e.g. libssh2_session_handshake() fails, but libssh2_session_last_error() confusingly returns LIBSSH2_ERROR_NONE. + + Credit: + Zenju + +- [Will Cosgrove brought this change] + + Revert usage of EVP_CipherUpdate #764 #739 (#765) + + Revert usage of EVP_CipherUpdate from wolfSSL PR to fix #764 #739. + +- [Will Cosgrove brought this change] + + Fix regression with rsa_sha2_verify #758 (#763) + + Fixes comparison with the result value coming from `mbedtls_rsa_pkcs1_verify`. Success is 0, not 1. + +Marc Hoersken (24 Oct 2022) +- CI: fix AppVeyor status failing for starting jobs + +Viktor Szakats (24 Oct 2022) +- delete cast5 - null-cipher mapping + +- more feature guard cleanup + +- indent + +- formatting + +- fold long lines + +- cleanup + +- temporarily silence checksrc + +- add mbedTLS 3.x support + + Make libssh2 compile cleanly with mbedTLS 3.x and later. + + This patch makes use of `MBEDTLS_PRIVATE()`, which is not the + recommended, future-proof way to access mbedTLS data structures. This + method may break with a minor upgrade, according to the authors. This + is also the method used by libcurl. + + Also: + + - Fix a potentially uninitialized variable in + `libssh2_mbedtls_rsa_sha2_sign()`. This happened in an error path, + resulting in an unnecessary mbedTLS API call, with an uninitialized + `md_type`. + + - Bump mbedTLS version used in CI tests to 3.2.1. + + Fixes #751 + +- tests: add option to enable all trace messages in fixture + + via `export FIXTURE_TRACE_ALL=1`. + +- win32/GNUmakefile: add mbedTLS support + + via `export MBEDTLS_PATH=`. + +Marc Hoersken (21 Oct 2022) +- CI: fix AppVeyor job links only working for most recent build + + Ref: https://github.com/curl/curl/pull/9768#issuecomment-1286675916 + Reported-by: Daniel Stenberg + + Follow up to #754 + +- CI: add missing permission section to AppVeyor status workflow + + Follow up to #754 + +- Remove OSSFuzz integration which was replaced with CIFuzz (#756) + + Confirmed-by: Max Dymond + +- Rename workflow file appveyor.yml to appveyor_docker.yml + +- Streamline names of CI workflow jobs + +- [Jeroen Ooms brought this change] + + Add CI for mingw-w64 via msys2 (#742) + + Credit: Jeroen Ooms + +- CI: report AppVeyor build status for each job (#754) + + Also give each job on AppVeyor CI a human-readable name. + + This aims to make job and therefore build failures more visible. + +GitHub (29 Sep 2022) +- [Michael Buckley brought this change] + + Support for sk-ecdsa-sha2-nistp256 and sk-ssh-ed25519 keys, FIDO (#698) + + Notes: + Add support for sk-ecdsa-sha2-nistp256@openssh.com and sk-ssh-ed25519@openssh.com key exchange for FIDO auth using the OpenSSL backend. Stub API for other backends. + + Credit: + Michael Buckley + +- [Y. Yang brought this change] + + Fix DLL import library name (#711) + + Notes: + Fix DLL import library name + + https://aur.archlinux.org/packages/mingw-w64-libssh2 + https://cmake.org/cmake/help/latest/prop_tgt/IMPORT_PREFIX.html + + Credit: + metab0t + Y. Yang + +- [skundu07 brought this change] + + Add RSA-SHA2 support for the WinCNG backend (#736) + + Notes: + Added code to support RSA-SHA2 for WinCNG backend. + + Credit: + skundu07 + +- [Gabriel Smith brought this change] + + sftp: Prevent files from being skipped if the output buffer is too small (#746) + + Notes: + LIBSSH2_ERROR_BUFFER_TOO_SMALL is returned if the buffer is too small + to contain a returned directory entry. On this condition we jump to the + label `end`. At this point the number of names left is decremented + despite no name being returned. + + As suggested in #714, this commit moves the error label after the + decrement of `names_left`. + + Fixes #714 + + Credit: + Co-authored-by: Gabriel Smith + +- [bgermann brought this change] + + Drop advertisement clause on Blowfish (#747) + + Originally driven by https://github.com/pyca/bcrypt/issues/169, OpenBSD + removed Niels Provos's BSD advertisement clause in version 7.1: + + https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/lib/libsa/blowfish.c.diff?r1=1.1&r2=1.2 + https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/lib/libsa/blowfish.h.diff?r1=1.1&r2=1.2 + + This enables using libssh2 in GPL software. + +- [zhaochongliu brought this change] + + Support building with gcc < version 8 + + Files: CMakeLists.txt + + Notes: don't use gcc arguments that don't exist in gcc versions lower than 8 if building with older gcc. + + Credit: + zhaochongliu + +- [Miguel de Icaza brought this change] + + Document the obscure LIBSSH2_ERROR_BAD_USE when writing to a channel (#713) + + Document the obscure LIBSSH2_ERROR_BAD_USE when writing to a channel + + Credit: + Miguel de Icaza + +- [Michael Buckley brought this change] + + Don't erroneously log SSH_MSG_REQUEST_FAILURE packets from keepalive (#727) + + Notes: + When setting a ServerAliveInterval using libssh2_keepalive_config() with want_reply set to true, some servers will reply to the keep-alive requests with a single SSH_MSG_REQUEST_FAILURE packet. This is an allowed behavior in RFC 4254, section 4. + + Credit: + Michael Buckley + +- [Ryan Kelley brought this change] + + Updating docs for libssh2_channel_flush_ex (#728) + + Notes: + In #614 it was identified the docs do not accurately show how libssh2_channel_flush_ex() return value is set. I have updated the doc's to correctly show what the function is returning. + + Credit: + Ryan Kelley + +- [Sandeep Bansal brought this change] + + Support RSA certificate authentication (#710) + + * Adding support for signed RSA keys and unit test + + Credit: + Sandeep Bansal + +Viktor Szakats (2 Jul 2022) +- configure: add --disable-tests option + +- cmake: do not add libssh2.rc to the static library + +GitHub (23 May 2022) +- [AyushiN brought this change] + + Fixed typo #697 (#701) + + Credit: + AyushiN + +- [Viktor Szakats brought this change] + + Openssl: add support for LibreSSL 3.5.x (#700) + + LibreSSL 3.5.0 made more structures opaque, so let's enable existing + support for that when building against these LibreSSL versions. + + Ref: https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.5.0-relnotes.txt + + Credit: + Viktor Szakats + +- [Michael Buckley brought this change] + + Ensure KEX replies don't include extra bytes (#696) + + Addresses #695 + + Credit: + Michael Buckley, reported by Harry Sintonen + +- [Zenju brought this change] + + Fix buffer overflow during SSH_MSG_USERAUTH_BANNER (#693) + + File: userauth.c + Notes: + This patch fixes application crashes due to heap corruption. Turns out the null terminator is written one byte outside of the allocated area. + Credit: + Zenju + +- [Will Cosgrove brought this change] + + Changed NULL check to avoid logic change + +- [Will Cosgrove brought this change] + + NULL check before calling session_handshake + +- [Harry Sintonen brought this change] + + Fix build since openssl 1.1.0 when ECDSA and/or RIPEMD are disabled (#666) + + File: openssl.h + + Notes: + In openssl 1.1.0 and later openssl decided to change some of the defines used to check if certain features are not compiled in the libraries. This updates the define checks. + + Credit: + Harry Sintonen + Co-authored-by: Harry Sintonen + +- [gbaraldi brought this change] + + Add RSA-SHA2 support for the mbedtls backend (#688) + + File: mbedtls.c + + Notes: + * Add sha2 support for RSA key upgrading to mbedTLS backend + + Credit: + gbaraldi + +Daniel Stenberg (21 Mar 2022) +- misc/libssh2_copy_string: avoid malloc zero bytes + + Avoids the inconsistent malloc return code for malloc(0) + + Closes #686 + +Marc Hoersken (17 Mar 2022) +- wincng: rename struct field referring to the DH private big number + + Closes #684 + +- tests/openssh_fixture.c: print command after variable expansion + +- CI: store and reuse OpenSSH Server docker image used for tests + + Supersedes #588 + Fixes #665 + Closes #685 + +GitHub (26 Feb 2022) +- [Will Cosgrove brought this change] + + Added LibreSSL to crypto backend list + +- [Will Cosgrove brought this change] + + Added crypto backend list to template + + Added OS version as well + +- [Will Cosgrove brought this change] + + Revert "Option to build both static and shared libraries (#547)" (#675) + + This reverts commit b60dca8b6450a9729670986d2899cca54ccdbb6d. + + #547 doesn't build clean anymore with the keyboard interactive changes. + +- [berney brought this change] + + Option to build both static and shared libraries (#547) + + files: cmakelists.txt + + Notes: + * Option to build both static and shared libraries when using CMake + + Credit: + berney + +- [xalopp brought this change] + + Use modern API in userauth_keyboard_interactive() (#663) + + Files: userauth_kbd_packet.c, userauth_kbd_packet.h, test_keyboard_interactive_auth_info_request.c, userauth.c + + Notes: + This refactors `SSH_MSG_USERAUTH_INFO_REQUEST` processing in `userauth_keyboard_interactive()` in order to improve robustness, correctness and readability or the code. + + * Refactor userauth_keyboard_interactive to use new api for packet parsing + * add unit test for userauth_keyboard_interactive_parse_response() + * add _libssh2_get_boolean() and _libssh2_get_byte() utility functions + + Credit: + xalopp + +- [xalopp brought this change] + + Fix formatting in manual page (#667) + + Fixed formatting of `LIBSSH2_ERROR_AUTHENTICATION_FAILED` in the errors section. + + credit: xalopp + +- [tihmstar brought this change] + + NULL terminate server_sign_algorithms string (#669) + + files: packet.c, libssh2_priv.h + + notes: + * Fix heap buffer overflow in _libssh2_key_sign_algorithm + + When allocating `session->server_sign_algorithms` which is a `char*` is is important to also allocate space for the string-terminating null byte at the end and make sure the string is actually null terminated. + + Without this fix, the `strchr()` call inside the `_libssh2_key_sign_algorithm` (line 1219) function will try to parse the string and go out of buffer on the last invocation. + + Credit: tihmstar + Co-authored-by: Will Cosgrove + +- [Will Cosgrove brought this change] + + free RSA2 related memory (#664) + + Free `server_sign_algorithms` and `sign_algo_prefs`. + +- [Will Cosgrove brought this change] + + Legacy Agent support for rsa2 key upgrading/downgrading #659 (#662) + + Files: libssh2.h, agent.c, userauth.c + + Notes: + Part 2 of the fix for #659. This adds rsa key downgrading for agents that don't support sha2 upgrading. It also adds better trace output for debugging/logging around key upgrading. + + Credit: + Will Cosgrove (signed off by Michael Buckley) + +- [Ian Hattendorf brought this change] + + Support rsa-sha2 agent flags (#661) + + File: agent.c + Notes: implements rsa-sha2 flags used to tell the agent which signing algo to use. + https://tools.ietf.org/id/draft-miller-ssh-agent-01.html#rfc.section.4.5.1 + + Credit: + Ian Hattendorf + +Daniel Stenberg (13 Jan 2022) +- [Sunil Nimmagadda brought this change] + + ssh: Add support for userauth banner. + + The new libssh2_userauth_banner API allows to get an optional + userauth banner sent with SSH_MSG_USERAUTH_BANNER packet by the + server. + + Closes #610 + +GitHub (6 Jan 2022) +- [Michael Buckley brought this change] + + Fix a memcmp errors in code that was changed from memmem to memcmp (#656) + + Notes: + Fixed supported algo prefs list check when upgrading rsa keys + + Credit: Michael Buckley + +- [Hayden Roche brought this change] + + Add support for a wolfSSL crypto backend. (#629) + + It uses wolfSSL's OpenSSL compatibility layer, so rather than introduce new + wolfssl.h/c files, the new backend just reuses openssl.h/c. Additionally, + replace EVP_Cipher() calls with EVP_CipherUpdate(), since EVP_Cipher() is not + recommended. + + Credit: Hayden Roche + +- [Bastien Durel brought this change] + + Runtime engine detection with libssh2_crypto_engine() (#643) + + File: + version.c, HACKING-CRYPTO, libssh2.h, libssh2_crypto_engine.3, makefile. + + Notes: + libssh2_crypto_engine() API to get crypto engine at runtime. + + Credit: Bastien Durel + +- [Will Cosgrove brought this change] + + RSA SHA2 256/512 key upgrade support RFC 8332 #536 (#626) + + Notes: + * Host Key RSA 256/512 support #536 + * Client side key hash upgrading for RFC 8332 + * Support for server-sig-algs, ext-info-c server messages + * Customizing preferred server-sig-algs via the preference LIBSSH2_METHOD_SIGN_ALGO + + Credit: Anders Borum, Will Cosgrove + +- [xalopp brought this change] + + fix: use userauth name length to check memory boundaries for userauth name, fixes #653 (#654) + + File: userauth.c + + Notes: + Fixes `userauth_kybd_auth_name_len` length check + + Co-authored-by: Xaver Lopenstedt + +- [Daniel Stenberg brought this change] + + agent: handle overly large comment lengths (#651) + + Reported-by: Harry Sintonen + +- [Daniel Stenberg brought this change] + + userauth: check for too large userauth_kybd_auth_name_len (#650) + + ... before using it. + + Reported-by: MarcoPoloPie + Fixes #649 + +Daniel Stenberg (17 Dec 2021) +- .github/SECURITY.md: fix the URL + +- .github/SECURITY.md: add security policy + +GitHub (30 Nov 2021) +- [Will Cosgrove brought this change] + + hostkey_method_ssh_ed25519_init() check key bounds (#645) + + * hostkey_method_ssh_ed25519_init() check key bounds + + File: hostkey.c + + Notes: + Additional key length checking before calling _libssh2_ed25519_new_public() + + Credit: + Will Cosgrove + +- [Will Cosgrove brought this change] + + Fix error message in memory_read_privatekey #636 + + file: userauth.c + note: fix error message + credit: + volund + +- [cntrump brought this change] + + Update maketgz for macOS (#543) + + File: + maketgz + + Notes: + Fix error on macOS: sed: -e: No such file or directory + + Credit: + cntrump + +- [Jun Tseng brought this change] + + CMake update minimum version to 2.8.12 (#639) + + File: + CMakeLists.txt + + Notes: + Following CMake's advice, Update the minimum required version. + + Credit: + Jun Tseng + +Daniel Stenberg (8 Nov 2021) +- [David Korczynski brought this change] + + ci: Add CIFuzz integration + + Notes: + Add CIFuzz integration to run fuzzer using the OSS-Fuzz infrastructure + at each PR. + + Signed-off-by: David Korczynski + Closes #635 + +GitHub (26 Oct 2021) +- [Uwe L. Korn brought this change] + + Use libssh2_EXPORTS as an alternative to _WINDLL (#470) + + Files: libssh2.h + + Notes: + `_WINDLL` is only defined when a Visual Studio CMake generator is used, `libssh2_EXPORTS` is used though for all CMake generator if a shared libssh2 library is being built. + + Credit: + Uwe L. Korn + +Viktor Szakats (1 Oct 2021) +- 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 + +Daniel Stenberg (25 Sep 2021) +- README: use www.libssh2.org for the license link + +- libssh2.h: bump it to 1.10.1-dev + +- mailing list: moved to lists.haxx.se + +GitHub (2 Sep 2021) +- [Laurent Stacul brought this change] + + 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 + +- [Will Cosgrove brought this change] + + openssh_fixture.c: fix warning (#621) + + File: openssh_fixture.c + + Notes: + Fix `portable_sleep` return type warning + + Credit: + Will Cosgrove + +- [Will Cosgrove brought this change] + + 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 + +- [Will Cosgrove brought this change] + + Update .gitignore + + Add .DS_Store files for macOS + +- [Laurent Stacul brought this change] + + Makefile.am: Add missing key in case openssl > 1.1.0 (#617) + + File: Makefile.am + + Notes: fix missing test keys + + Credit: + Laurent Stacul + +Version 1.10.0 (29 Aug 2021) + Daniel Stenberg (29 Aug 2021) - [Will Cosgrove brought this change] @@ -2009,4823 +10894,3 @@ GitHub (2 Aug 2018) * ECDSA key types are now explicit Issue was brough up in pull request #248 - -Will Cosgrove (2 May 2018) -- [Jakob Egger brought this change] - - Add Instructions for building from Master (#249) - -GitHub (27 Apr 2018) -- [Will Cosgrove brought this change] - - Initialize sb_intl #226 - -Will Cosgrove (19 Apr 2018) -- [doublex brought this change] - - buffer overflow (valgrind) (#159) - -- [Brendan Shanks brought this change] - - mbedTLS: Remove some C99-style intermingled variable declarations (#196) - -GitHub (18 Apr 2018) -- [Will Cosgrove brought this change] - - fix for #160 - -Will Cosgrove (18 Apr 2018) -- [doublex brought this change] - - fix memory leak when using mbedtls backend (#158) - - _libssh2_bn_init_from_bin/_libssh2_bn_free would leak bignum from mbedtls_calloc(). - -- [Brendan Shanks brought this change] - - mbedTLS: Avoid multiple definition errors for context handles (#197) - -- [Tseng Jun brought this change] - - Fix the EVP cipher meth memory leakage problem (#244) - - * Fix the EVP cipher meth memory leakage problem - - Looks good, thanks for the fixes. - -Marc Hörsken (31 Mar 2018) -- [Will Cosgrove brought this change] - - Added ECDSA defines for WinCNG (#245) - - Fixed missing defines preventing building using WinCNG - -GitHub (30 Mar 2018) -- [Will Cosgrove brought this change] - - Fix for _libssh2_rsa_new with OpenSSL 1.0.x - - missing d value assignment. - -Will Cosgrove (20 Mar 2018) -- [Etienne Samson brought this change] - - A collection of small fixes (#198) - - * tests: Remove if-pyramids - - * tests: Switch run_command arguments - - * tests: Make run_command a vararg function - - * tests: Xcode doesn't obey CMake's test working directory - - * openssl: move manual AES-CTR cipher into crypto init - - * cmake: Move our include dir before all other include paths - -GitHub (15 Mar 2018) -- [Will Cosgrove brought this change] - - Fixes incorrect indexing of KEX prefs string - - After stripping out an invalid KEX pref entry, it would incorrectly advance again leaving invalid values in the list. - -Viktor Szakats (13 Mar 2018) -- tests: fix checksrc warnings - - Also: - * add 'static' qualifier to file-wide const buffers - * fix a non-ANSI C89 comment - * silence a mismatched fprintf() mask warning by adding a cast - -- cmake: recognize OpenSSL 1.1 .dll names - - Also fix some comment typos and a stray tab. - -- docs: update an URL [ci skip] - -Daniel Stenberg (12 Mar 2018) -- docs/SECURITY: the max embargo is 14 days now - -Viktor Szakats (12 Mar 2018) -- docs: spelling fixes [ci skip] - - Closes https://github.com/libssh2/libssh2/pull/222 - -GitHub (12 Mar 2018) -- [Will Cosgrove brought this change] - - Fixed minor tabs/spacing issues - -- [Will Cosgrove brought this change] - - Update kex.c - -- [Will Cosgrove brought this change] - - Added basic bounds checking #206 - - Basic bounds checking in ecdh_sha2_nistp() - -- [Will Cosgrove brought this change] - - Fixed Clang warning #206 - - Fixed possible garbage value for secret in an error case - -- [Will Cosgrove brought this change] - - Fixed incorrect #if to #ifdef #206 - - When checking HAVE_OPAQUE_STRUCTS. - -Viktor Szakats (12 Mar 2018) -- src: suppress two checksrc warnings - - Ref: https://github.com/libssh2/libssh2/pull/235 - -- src: address fopen() warnings, add missing copyright headers - - Ref: https://github.com/libssh2/libssh2/pull/235 - -- src: replace sprintf() with snprintf() - - Ref: https://github.com/libssh2/libssh2/pull/235 - -- src: fix checksrc warnings - - Use checksrc.pl from the curl project, with (for now) - suppressed long line warnings and indentation set to - 4 spaces. Fixes are whitespace for the most part. - - Warning count went down from 2704 to 12. - - Also fix codespell typos, two non-ANSI C89 comments - and a stray tab in include/libssh2.h. - - Ref: https://github.com/libssh2/libssh2/pull/235 - -- checksrc: add source style checker - - This is a slightly extended version of this original source - from the curl project: - https://github.com/curl/curl/blob/8b754c430b9a4c51aa606c687ee5014faf7c7b06/lib/checksrc.pl - - This version adds the following options to customize it for - libssh2 (plus some whitespace formatting): - - `-i` to override indentation spaces (2) - `-m` to override maximum line length (79) - - Command-line used to check libssh2 sources: - - $ ./checksrc.pl -i4 -m500 *.c *.h - - Closes https://github.com/libssh2/libssh2/pull/236 - -- src: add static qualifier - - To private, const strings. - - Closes https://github.com/libssh2/libssh2/pull/237 - -- [Will Cosgrove brought this change] - - Add support for ECDSA keys and host keys (#41) - - This commit lands full ECDSA key support when using the OpenSSL - backend. Which includes: - - New KEX methods: - ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521 - - Can now read OpenSSL formatted ECDSA key files. - - Now supports known host keys of type ecdsa-sha2-nistp256. - - New curve types: - NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1 - - Default host key preferred ordering is now nistp256, nistp384, - nistp521, rsa, dss. - - Ref: https://github.com/libssh2/libssh2/issues/41 - - Closes https://github.com/libssh2/libssh2/pull/206 - -GitHub (15 Dec 2017) -- [Will Cosgrove brought this change] - - Fixed possible crash when decoding invalid data - - When trying to decode invalid data, it frees the buffer but doesn't nil it so the caller gets a junk memory pointer which they could potentially double free. - -- [Will Cosgrove brought this change] - - Remove call to OpenSSL_add_all_ciphers() - - Now lives in libssh2 init() from PR #189 - -- [Will Cosgrove brought this change] - - Fixed incorrect reference to decrypted block - - Fixed incorrectly copied memory from p->buf into init instead of from the decrypted buffer block. The only reason this worked was because the crypt() function decrypts the value in-place and overwrites p->buf. I'm working on a fork that no longer does this and exposed this bug. - -Will Cosgrove (20 Oct 2017) -- [Pan brought this change] - - Fix typo in crypt.c (#218) - -Kamil Dudka (17 Oct 2017) -- session: avoid printing misleading debug messages - - ... while throwing LIBSSH2_ERROR_EAGAIN out of session_startup() - - If the session runs in blocking mode, LIBSSH2_ERROR_EAGAIN never reaches - the libssh2 API boundary and, in non-blocking mode, these messages are - suppressed by the condition in _libssh2_error_flags() anyway. - - Closes #211 - -Viktor Szakats (15 Oct 2017) -- win32/GNUmakefile: allow customizing dll suffixes - - - New `LIBSSH2_DLL_SUFFIX` envvar will add a suffix to the generated - libssh2 dll name. Useful to add `-x64` to 64-bit builds so that - it can live in the same directory as the 32-bit one. By default - this is empty. - - - New `LIBSSH2_DLL_A_SUFFIX` envvar to customize the suffix of the - generated import library (implib) for libssh2 .dll. It defaults - to `dll`, and it's useful to modify that to `.dll` to have the - standard naming scheme for mingw-built .dlls, i.e. `libssh2.dll.a`. - - Ref: https://github.com/curl/curl/commit/aaa16f80256abc1463fd9374815130a165222257 - - Closes https://github.com/libssh2/libssh2/pull/215 - -- makefile.m32: allow to override gcc, ar and ranlib - - Allow to ovverride certain build tools, making it possible to - use LLVM/Clang to build libssh2. The default behavior is unchanged. - To build with clang (as offered by MSYS2), these settings can - be used: - - LIBSSH2_CC=clang - LIBSSH2_AR=llvm-ar - LIBSSH2_RANLIB=llvm-ranlib - - Also adjust ranlib parameters to be compatible with LLVM/Clang's - ranlib tool. - - Closes https://github.com/libssh2/libssh2/pull/214 - -GitHub (27 Sep 2017) -- [Will Cosgrove brought this change] - - Fixes out of bounds memory access (#210) - - If an invalid PEM file is read and the lines are longer than 128 characters it will go out of bounds and crash on line 91. - -Will Cosgrove (11 Sep 2017) -- [Kamil Dudka brought this change] - - scp: do not NUL-terminate the command for remote exec (#208) - - It breaks SCP download/upload from/to certain server implementations. - - The bug does not manifest with OpenSSH, which silently drops the NUL - byte (eventually with any garbage that follows the NUL byte) before - executing it. - - Bug: https://bugzilla.redhat.com/1489736 - -GitHub (21 Aug 2017) -- [Viktor Szakats brought this change] - - openssl.c: remove no longer used variable (#204) - - after e378d2e30a40bd9bcee06dc3a4250f269098e200 - -- [Will Cosgrove brought this change] - - Fix for #188 (#189) - - * Update openssl.c - - * Create openssl.h - -Will Cosgrove (24 May 2017) -- [Marcel Raad brought this change] - - openssl: fix build with OpenSSL 1.1 API (#176) - - When building with OPENSSL_API_COMPAT=0x10100000L, OpenSSL_add_all_algorithms - and OpenSSL_add_all_ciphers don't exist. The corresponding functionality is - handled automatically with OpenSSL 1.1. - -- [Sune Bredahl brought this change] - - Add support for SHA256 hostkey fingerprints (#180) - - Looks good, thanks! - -GitHub (12 May 2017) -- [Will Cosgrove brought this change] - - Fix memory leak of crypt_ctx->h using openSSL 1.1+ (#177) - - Need to use EVP_CIPHER_CTX_free instead of EVP_CIPHER_CTX_reset. - -Marc Hoersken (2 Mar 2017) -- tests/openssh_server/authorized_keys: add key_rsa_encrypted.pub - -- tests: add simple test for passphrase-protected PEM file support - -- os400qc3: enable passphrase-protected PEM file support using pem.c - -- pem: fix indentation and replace assert after 386e012292 - -- [Keno Fischer brought this change] - - pem: add passphrase-protected PEM file support for libgcrypt and wincng - - Since they use our own PEM parser which did not support encrypted - PEM files, trying to use such files on these backends failed. - Fix that by augmenting the PEM parser to support encrypted PEM files. - -- [Thomas brought this change] - - misc: use time constant implementation for AES CTR increment - -- [Thomas brought this change] - - wincng: add AES CTR mode support (aes128-ctr, aes192-ctr, aes256-ctr) - -- [Thomas brought this change] - - openssl: move shared AES-CTR code into misc - -Daniel Stenberg (20 Dec 2016) -- [Alex Crichton brought this change] - - kex: acknowledge error code from libssh2_dh_key_pair() - - Fixes a segfault using ssh-agent on Windows - - This commit fixes a segfault seen dereferencing a null pointer on - Windows when using ssh-agent. The problem ended up being that errors - weren't being communicated all the way through, causing null pointers to - be used when functions should have bailed out sooner. - - The `_libssh2_dh_key_pair` function for WinCNG was modified to propagate - errors, and then the two callsites in kex.c of - `diffie_hellman_sha{1,256}` were updated to recognize this error and - bail out. - - Fixes #162 - Closes #163 - -Alexander Lamaison (27 Nov 2016) -- [monnerat brought this change] - - Implement Diffie-Hellman computations in crypto backends. (#149) - - Not all backends feature the low level API needed to compute a Diffie-Hellman - secret, but some of them directly implement Diffie-Hellman support with opaque - private data. The later approach is now generalized and backends are - responsible for all Diffie Hellman computations. - As a side effect, procedures/macros _libssh2_bn_rand and _libssh2_bn_mod_exp - are no longer needed outside the backends. - -Peter Stuge (16 Nov 2016) -- acinclude.m4: The mbedtls crypto backend actually requires libmbedcrypto - - Examples can't be linked with libmbedtls but need libmbedcrypto, and - any users of libssh2 which use libtool and libssh2.la would encounter - the same problem. - - This changes the mbedtls detection to search for libmbedcrypto, which - is the actual dependency for the backend. - -- acinclude.m4: Add CPPFLAGS=-I$prefix-dir/include in LIBSSH2_LIB_HAVE_LINKFLAGS - - This is absolutely neccessary for header files to be found when - AC_LIB_HAVE_LINKFLAGS searches for libraries. - -- acinclude.m4: Make saved variables in LIBSSH2_LIB_HAVE_LINKFLAGS uniform - -- docs/HACKING.CRYPTO: Improve documentation for autoconf build system - -Alexander Lamaison (16 Nov 2016) -- [Alex Arslan brought this change] - - Check for netinet/in.h in the tests cmake file (#148) - -- [Patrick Monnerat brought this change] - - Define new Diffie-Hellman context for mbedTLS - -- [monnerat brought this change] - - Make libssh2 work again on os400. (#118) - - * os400: minimum supported OS version is now V6R1. - Do not log compiler informational messages. - - * Implement crypto backend specific Diffie-Hellman computation. - - This feature is now needed on os400 because the QC3 library does not - implement bn_mod_exp() natively. Up to now, this function was emulated using - an RSA encryption, but commits ca5222ea819cc5ed797860070b4c6c1aeeb28420 and - 7934c9ce2a029c43e3642a492d3b9e494d1542be (CVE-2016-0787) broke the emulation - because QC3 only supports RSA exponents up to 512 bits. - - Happily, QC3 supports a native API for Diffie-Hellman computation, with - opaque random value: this commit implements the use of this API and, as a - side effect, enables support of this feature for any other crypto backend that - would use it. - - A "generic" Diffie-Hellman computation internal API supports crypto backends - not implementing their own: this generic API uses the same functions as before. - - * Fix typos in docs/HACKING.CRYPTO. - -- [Peter Stuge brought this change] - - acinclude.m4: Fixup OpenSSL EVP_aes_128_ctr() detection - -- [Peter Stuge brought this change] - - configure.ac: Add --with-crypto= instead of many different --with-$backend - - The new --with-crypto option replaces the previous backend-specific - --with-{openssl,libgcrypt,mbedtls,wincng} options and fixes some issues. - - * libgcrypt or mbedtls would previously be used whenever found, even - if configure was passed --without-libgcrypt or --without-mbedtls. - - * If --with-$backend was specified then configure would not fail even - if that library could not be found, and would instead use whichever - crypto library was found first. - - The new option defaults to `auto`, which makes configure check for all - supported crypto libraries in turn, choosing the first one found, or - exiting with an error if none can be found. - -- [Tony Kelman brought this change] - - Build mbedtls from source on Travis (#133) - - * Revert "Revert "travis: Test mbedtls too"" - - This reverts commit c4c60eac5ca756333034b07dd9e0b97741493ed3. - - * travis: Build mbedtls from source on Travis - - Use TOOLCHAIN_OPTION when calling cmake on mbedtls - - * tests: only run DSA tests for non-mbedtls - - crypto backends - -- [Peter Stuge brought this change] - - configure.ac src/Makefile.am: Remove dead AM_CONDITIONAL(OS400QC3) - - According to os400/README400 this backend can not be built - with configure+make, and the conditional is hard coded to false. - -- [Peter Stuge brought this change] - - configure.ac: Add -DNDEBUG to CPPFLAGS in non-debug builds - - There are a few uses of assert() in channel.c, sftp.c and transport.c. - -- [Peter Stuge brought this change] - - src/global.c: Fix conditional AES-CTR support - - Most of libssh2 already has conditional support for AES-CTR according to - the LIBSSH2_AES_CTR crypto backend #define, but global.c needed fixing. - -- [Peter Stuge brought this change] - - src/crypto.h src/userauth.c: Fix conditional RSA support - - Most of libssh2 already has conditional support for RSA according to - the LIBSSH2_RSA crypto backend #define, but crypto.h and userauth.c - needed a few small fixes. - -- [Peter Stuge brought this change] - - src/kex.c: Cast libssh2_sha{1,256}_update data arguments properly - - The update functions take a const unsigned char * but were called - with (const) char * in some places, causing unneccessary warnings. - -- [Peter Stuge brought this change] - - docs/HACKING.CRYPTO: Fix two type typos - -- [Sergei Trofimovich brought this change] - - acinclude.m4: fix ./configure --with-libgcrypt - - The change fixes passing of bogus gcrypt prefix. - Reproducible as: - - $ ./configure --with-libgcrypt - $ make V=1 - ... - /bin/sh ../libtool --tag=CC --mode=link gcc -g -O2 -Iyes/include -version-info 1:1:0 -no-undefined -export-symbols-regex '^libssh2_.*' -lgcrypt -lz -Lyes/lib -o libssh2.la -rpath /usr/local/lib channel.lo comp.lo crypt.lo hostkey.lo kex.lo mac.lo misc.lo packet.lo publickey.lo scp.lo session.lo sftp.lo userauth.lo transport.lo version.lo knownhost.lo agent.lo libgcrypt.lo pem.lo keepalive.lo global.lo -lgcrypt - ../libtool: line 7475: cd: yes/lib: No such file or directory - libtool: error: cannot determine absolute directory name of 'yes/lib' - - These - -Iyes/include - -Lyes/lib - come from libgcrypt code autodetection: - if test -n "$use_libgcrypt" && test "$use_libgcrypt" != "no"; then - LDFLAGS="$LDFLAGS -L$use_libgcrypt/lib" - CFLAGS="$CFLAGS -I$use_libgcrypt/include" - - I assume it's a typo to use yes/no flag as a prefix and changed - it to '$with_libgcrypt_prefix'. - - Reported-by: Mikhail Pukhlikov - Signed-off-by: Sergei Trofimovich - -- [Zenju brought this change] - - libssh2_sftp_init hang: last error not set - - The problem is that the original if statement simply returns NULL, but does not set the session last error code. The consequence is that libssh2_sftp_init() also returns NULL and libssh2_session_last_errno(sshSession) == LIBSSH2_ERROR_NONE. - - In my test the LIBSSH2_ERROR_EAGAIN is coming from sftp.c row 337: - if(4 != sftp->partial_size_len) - /* we got a short read for the length part */ - return LIBSSH2_ERROR_EAGAIN; - - with "partial_size_len == 0". Not sure if this is expected. - -- [Aidan Hobson Sayers brought this change] - - docs: correctly describe channel_wait_eof - - channel_wait_eof waits for channel->remote.eof, which is set on - receiving a `SSH_MSG_CHANNEL_EOF` message. This message is sent - when a party has no more data to send on a channel. - -- [Zenju brought this change] - - Fix MSVC 14 compilation warning (#92) - - 1> sftp.c - 1>libssh2-files\src\sftp.c(3393): warning C4456: declaration of 'retcode' hides previous local declaration - 1> libssh2-files\src\sftp.c(3315): note: see declaration of 'retcode' - -- [Salvador Fandino brought this change] - - LIBSSH2_ERROR_CHANNEL_WINDOW_FULL: add new error code - - In order to signal that the requested operation can not succeed - because the receiving window had been exhausted, the error code - LIBSSH2_ERROR_BUFFER_TOO_SMALL has been reused but I have found - that in certain context it may be ambigous. - - This patch introduces a new error code, - LIBSSH2_ERROR_CHANNEL_WINDOW_FULL, exclusive to signal that condition. - -- [Salvador Fandino brought this change] - - channel_wait_eof: handle receive window exhaustion - - Until now, in blocking mode, if the remote receiving window is - exhausted this function hangs forever as data is not read and the - remote side just keeps waiting for the window to grow before sending - more data. - - This patch, makes this function check for that condition and abort - with an error when it happens. - -- [Salvador Fandino brought this change] - - channel_wait_closed: don't fail when unread data is queued - - This function was calling channel_wait_eof to ensure that the EOF - packet has already been received, but that function also checks that - the read data queue is empty before reporting the EOF. That caused - channel_wait_closed to fail with a LIBSSH2_ERROR_INVAL when some data - was queued even after a successful call to libssh2_channel_wait_eof. - - This patch changes libssh2_channel_wait_closed to look directly into - channel->remote.eof so that both libssh2_channel_wait_eof and - libssh2_channel_wait_closed bahave consistently. - -- [Salvador Fandino brought this change] - - channel_wait_eof: fix debug message - -Daniel Stenberg (25 Oct 2016) -- libssh2.h: start working on 1.8.1 - -Version 1.8.0 (25 Oct 2016) - -Daniel Stenberg (25 Oct 2016) -- RELEASE-NOTES: adjusted for 1.8.0 - -Kamil Dudka (20 Oct 2016) -- Revert "aes: the init function fails when OpenSSL has AES support" - - This partially reverts commit f4f2298ef3635acd031cc2ee0e71026cdcda5864 - because it caused the compatibility code to call initialization routines - redundantly, leading to memory leakage with OpenSSL 1.1 and broken curl - test-suite in Fedora: - - 88 bytes in 1 blocks are definitely lost in loss record 5 of 8 - at 0x4C2DB8D: malloc (vg_replace_malloc.c:299) - by 0x72C607D: CRYPTO_zalloc (mem.c:100) - by 0x72A2480: EVP_CIPHER_meth_new (cmeth_lib.c:18) - by 0x4E5A550: make_ctr_evp.isra.0 (openssl.c:407) - by 0x4E5A8E8: _libssh2_init_aes_ctr (openssl.c:471) - by 0x4E5BB5A: libssh2_init (global.c:49) - -Daniel Stenberg (19 Oct 2016) -- [Charles Collicutt brought this change] - - libssh2_wait_socket: Fix comparison with api_timeout to use milliseconds (#134) - - Fixes #74 - -- [Charles Collicutt brought this change] - - Set err_msg on _libssh2_wait_socket errors (#135) - -- Revert "travis: Test mbedtls too" - - This reverts commit 3e6de50a24815e72ec5597947f1831f6083b7da8. - - Travis doesn't seem to support the mbedtls-dev package - -- maketgz: support "only" to only update version number locally - - and fix the date output locale - -- configure: make the --with-* options override the OpenSSL default - - ... previously it would default to OpenSSL even with the --with-[crypto] - options used unless you specificly disabled OpenSSL. Now, enabling another - backend will automatically disable OpenSSL if the other one is found. - -- [Keno Fischer brought this change] - - docs: Add documentation on new cmake/configure options - -- [Keno Fischer brought this change] - - configure: Add support for building with mbedtls - -- [wildart brought this change] - - travis: Test mbedtls too - -- [wildart brought this change] - - crypto: add support for the mbedTLS backend - - Closes #132 - -- [wildart brought this change] - - cmake: Add CLEAR_MEMORY option, analogously to that for autoconf - -- README.md: fix link typo - -- README: markdown version to look nicer on github - -Viktor Szakats (5 Sep 2016) -- [Taylor Holberton brought this change] - - openssl: add OpenSSL 1.1.0 compatibility - -Daniel Stenberg (4 Sep 2016) -- [Antenore Gatta brought this change] - - tests: HAVE_NETINET_IN_H was not defined correctly (#127) - - Fixes #125 - -- SECURITY: fix web site typo - -- SECURITY: security process - -GitHub (14 Aug 2016) -- [Alexander Lamaison brought this change] - - Basic dockerised test suite. - - This introduces a test suite for libssh2. It runs OpenSSH in a Docker - container because that works well on Windows (via docker-machine) as - well as Linux. Presumably it works on Mac too with docker-machine, but - I've not tested that. - - Because the test suite is docker-machine aware, you can also run it - against a cloud provider, for more realistic network testing, by setting - your cloud provider as your active docker machine. The Appveyor CI setup - in this commit does that because Appveyor doesn't support docker - locally. - -Kamil Dudka (3 Aug 2016) -- [Viktor Szakats brought this change] - - misc.c: Delete unused static variables - - Closes #114 - -Daniel Stenberg (9 Apr 2016) -- [Will Cosgrove brought this change] - - Merge pull request #103 from willco007/patch-2 - - Fix for security issue CVE-2016-0787 - -Alexander Lamaison (2 Apr 2016) -- [Zenju brought this change] - - Fix MSVC 14 compilation errors - - For _MSC_VER == 1900 these macros are not needed and create problems: - - - - 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\stdio.h(1925): warning C4005: 'snprintf': macro redefinition (compiling source file libssh2-files\src\mac.c) - - 1> \win32\libssh2_config.h(27): note: see previous definition of 'snprintf' (compiling source file libssh2-files\src\mac.c) - - 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\stdio.h(1927): fatal error C1189: #error: Macro definition of snprintf conflicts with Standard Library function declaration (compiling source file libssh2-files\src\mac.c) - -Daniel Stenberg (26 Mar 2016) -- [Brad Harder brought this change] - - _libssh2_channel_open: speeling error fixed in channel error message - -Alexander Lamaison (15 Mar 2016) -- Link with crypt32.lib on Windows. - - Makes linking with static OpenSSL work again. Although it's not - required for dynamic OpenSSL, it does no harm. - - Fixes #98. - -- [Craig A. Berry brought this change] - - Tweak VMS help file building. - - Primarily this is handling cases where top-level files moved into - the docs/ directory. I also corrected a typo and removed the - claim that libssh2 is public domain. - -- [Craig A. Berry brought this change] - - Build with standard stat structure on VMS. - - This gets us large file support, is available on any VMS release - in the last decade and more, and gives stat other modern features - such as 64-bit ino_t. - -- [Craig A. Berry brought this change] - - Update vms/libssh2_config.h. - - VMS does have stdlib.h, gettimeofday(), and OpenSSL. The latter - is appropriate to hard-wire in the configuration because it's - installed by default as part of the base operating system and - there is currently no libgcrypt port. - -- [Craig A. Berry brought this change] - - VMS can't use %zd for off_t format. - - %z is a C99-ism that VMS doesn't currently have; even though the - compiler is C99-compliant, the library isn't quite. The off_t used - for the st_size element of the stat can be 32-bit or 64-bit, so - detect what we've got and pick a format accordingly. - -- [Craig A. Berry brought this change] - - Normalize line endings in libssh2_sftp_get_channel.3. - - Somehow it got Windows-style CRLF endings so convert to just LF, - for consistency as well as not to confuse tools that will regard - the \r as content (e.g. the OpenVMS help librarian). - -Dan Fandrich (29 Feb 2016) -- libgcrypt: Fixed a NULL pointer dereference on OOM - -Daniel Stenberg (24 Feb 2016) -- [Viktor Szakats brought this change] - - url updates, HTTP => HTTPS - - Closes #87 - -Dan Fandrich (23 Feb 2016) -- RELEASE-NOTES: removed some duplicated names - -Version 1.7.0 (23 Feb 2016) - -Daniel Stenberg (23 Feb 2016) -- web: the site is now HTTPS - -- RELEASE-NOTES: 1.7.0 release - -- diffie_hellman_sha256: convert bytes to bits - - As otherwise we get far too small numbers. - - Reported-by: Andreas Schneider - - CVE-2016-0787 - -Alexander Lamaison (18 Feb 2016) -- Allow CI failures with VS 2008 x64. - - Appveyor doesn't support this combination. - -Daniel Stenberg (16 Feb 2016) -- [Viktor Szakats brought this change] - - GNUmakefile: list system libs after user libs - - Otherwise some referenced WinSock functions will fail to - resolve when linking against LibreSSL 2.3.x static libraries - with mingw. - - Closes #80 - -- [Viktor Szakats brought this change] - - openssl: apply new HAVE_OPAQUE_STRUCTS macro - - Closes #81 - -- [Viktor Szakats brought this change] - - openssl: fix LibreSSL support after OpenSSL 1.1.0-pre1/2 support - -Alexander Lamaison (14 Feb 2016) -- sftp.h: Fix non-C90 type. - - uint64_t does not exist in C90. Use libssh2_uint64_t instead. - -- Exclude sshd tests from AppVeyor. - - They fail complaining that sshd wasn't invoked with an absolute path. - -- Test on more versions of Visual Studio. - -- Fix Appveyor builds. - -Daniel Stenberg (14 Feb 2016) -- [Viktor Szakats brought this change] - - openssl: add OpenSSL 1.1.0-pre3-dev compatibility - - by using API instead of accessing an internal structure. - - Closes #83 - -- RELEASE-NOTES: synced with 996b04ececdf - -- include/libssh2.h: next version is 1.7.0 - -- configure: build "silent" if possible - -- sftp: re-indented some minor stuff - -- [Jakob Egger brought this change] - - sftp.c: ensure minimum read packet size - - For optimum performance we need to ensure we don't request tiny packets. - -- [Jakob Egger brought this change] - - sftp.c: Explicit return values & sanity checks - -- [Jakob Egger brought this change] - - sftp.c: Check Read Packet File Offset - - This commit adds a simple check to see if the offset of the read - request matches the expected file offset. - - We could try to recover, from this condition at some point in the future. - Right now it is better to return an error instead of corrupted data. - -- [Jakob Egger brought this change] - - sftp.c: Don't return EAGAIN if data was written to buffer - -- [Jakob Egger brought this change] - - sftp.c: Send at least one read request before reading - - This commit ensures that we have sent at least one read request before - we try to read data in sftp_read(). - - Otherwise sftp_read() would return 0 bytes (indicating EOF) if the - socket is not ready for writing. - -- [Jakob Egger brought this change] - - sftp.c: stop reading when buffer is full - - Since we can only store data from a single chunk in filep, - we have to stop receiving data as soon as the buffer is full. - - This adresses the following bug report: - https://github.com/libssh2/libssh2/issues/50 - -Salvador Fandiño (21 Jan 2016) -- agent_disconnect_unix: unset the agent fd after closing it - - "agent_disconnect_unix", called by "libssh2_agent_disconnect", was - leaving the file descriptor in the agent structure unchanged. Later, - "libssh2_agent_free" would call again "libssh2_agent_disconnect" under - the hood and it would try to close again the same file descriptor. In - most cases that resulted in just a harmless error, but it is also - possible that the file descriptor had been reused between the two - calls resulting in the closing of an unrelated file descriptor. - - This patch sets agent->fd to LIBSSH2_INVALID_SOCKET avoiding that - issue. - - Signed-off-by: Salvador Fandiño - -Daniel Stenberg (18 Jan 2016) -- [Patrick Monnerat brought this change] - - os400qc3: support encrypted private keys - - PKCS#8 EncryptedPrivateKeyinfo structures are recognized and decoded to get - values accepted by the Qc3 crypto library. - -- [Patrick Monnerat brought this change] - - os400qc3: New PKCS#5 decoder - - The Qc3 library is not able to handle PKCS#8 EncryptedPrivateKeyInfo structures - by itself. It is only capable of decrypting the (encrypted) PrivateKeyInfo - part, providing a key encryption key and an encryption algorithm are given. - Since the encryption key and algorithm description part in a PKCS#8 - EncryptedPrivateKeyInfo is a PKCS#5 structure, such a decoder is needed to - get the derived key method and hash, as well as encryption algorith and - initialisation vector. - -- [Patrick Monnerat brought this change] - - os400qc3: force continuous update on non-final hash/hmac computation - -- [Patrick Monnerat brought this change] - - os400qc3: Be sure hmac keys have a minimum length - - The Qc3 library requires a minimum key length depending on the target - hash algorithm. Append binary zeroes to the given key if not long enough. - This matches RFC 2104 specifications. - -- [Patrick Monnerat brought this change] - - os400qc3: Slave descriptor for key encryption key - - The Qc3 library requires the key encryption key to exist as long as - the encrypted key is used. Its descriptor token is then kept as an - "encrypted key slave" for recursive release. - -- [Patrick Monnerat brought this change] - - os400qc3.c: comment PEM/DER decoding - -- [Patrick Monnerat brought this change] - - os400qc3.c: improve ASN.1 header byte checks - -- [Patrick Monnerat brought this change] - - os400qc3.c: improve OID matching - -- [Patrick Monnerat brought this change] - - os400: os400qc3.c: replace malloc by LIBSSH2_ALLOC or alloca where possible - -- [Patrick Monnerat brought this change] - - os400: asn1_new_from_bytes(): use data from a single element only - -- [Patrick Monnerat brought this change] - - os400: fix an ILE/RPG prototype - -- [Patrick Monnerat brought this change] - - os400: implement character encoding conversion support - -- [Patrick Monnerat brought this change] - - os400: do not miss some external prototypes - - Build procedure extproto() did not strip braces from header files, thus - possibly prepended them to true prototypes. This prevented the prototype to - be recognized as such. - The solution implemented here is to map braces to semicolons, effectively - considering them as potential prototype delimiters. - -- [Patrick Monnerat brought this change] - - os400: Really add specific README - -- [Patrick Monnerat brought this change] - - os400: Add specific README and include new files in dist tarball - -- [Patrick Monnerat brought this change] - - os400: add compilation scripts - -- [Patrick Monnerat brought this change] - - os400: include files for ILE/RPG - - In addition, file os400/macros.h declares all procedures originally - defined as macros. It must not be used for real inclusion and is only - intended to be used as a `database' for macro wrapping procedures generation. - -- [Patrick Monnerat brought this change] - - os400: add supplementary header files/wrappers. Define configuration. - -- [Patrick Monnerat brought this change] - - Protect callback function calls from macro substitution - - Some structure fields holding callback addresses have the same name as the - underlying system function (connect, send, recv). Set parentheses around - their reference to suppress a possible macro substitution. - - Use a macro for connect() on OS/400 to resolve a const/nonconst parameter - problem. - -- [Patrick Monnerat brought this change] - - Add interface for OS/400 crypto library QC3 - -- [Patrick Monnerat brought this change] - - misc: include stdarg.h for debug code - -- [Patrick Monnerat brought this change] - - Document crypto library interface - -- [Patrick Monnerat brought this change] - - Feature an optional crypto-specific macro to rsa sign a data fragment vector - - OS/400 crypto library is unable to sign a precomputed SHA1 hash: however - it does support a procedure that hashes data fragments and rsa signs. - If defined, the new macro _libssh2_rsa_sha1_signv() implements this function - and disables use of _libssh2_rsa_sha1_sign(). - - The function described above requires that the struct iovec unused slacks are - cleared: for this reason, macro libssh2_prepare_iovec() has been introduced. - It should be defined as empty for crypto backends that are not sensitive - to struct iovec unused slack values. - -- [Patrick Monnerat brought this change] - - Fold long lines in include files - -- [Viktor Szakats brought this change] - - kex.c: fix indentation - - Closes #71 - -- [Viktor Szakats brought this change] - - add OpenSSL-1.1.0-pre2 compatibility - - Closes #70 - -- [Viktor Szakats brought this change] - - add OpenSSL 1.1.0-pre1 compatibility - - * close https://github.com/libssh2/libssh2/issues/69 - * sync a declaration with the rest of similar ones - * handle EVP_MD_CTX_new() returning NULL with OpenSSL 1.1.0 - * fix potential memory leak with OpenSSL 1.1.0 in - _libssh2_*_init() functions, when EVP_MD_CTX_new() succeeds, - but EVP_DigestInit() fails. - -Marc Hoersken (22 Dec 2015) -- wincng.c: fixed _libssh2_wincng_hash_final return value - - _libssh2_wincng_hash_final was returning the internal BCRYPT - status code instead of a valid libssh2 return value (0 or -1). - - This also means that _libssh2_wincng_hash never returned 0. - -- wincng.c: fixed possible memory leak in _libssh2_wincng_hash - - If _libssh2_wincng_hash_update failed _libssh2_wincng_hash_final - would never have been called before. - - Reported by Zenju. - -Kamil Dudka (15 Dec 2015) -- [Paul Howarth brought this change] - - libssh2.pc.in: fix the output of pkg-config --libs - - ... such that it does not include LDFLAGS used to build libssh2 itself. - There was a similar fix in the curl project long time ago: - - https://github.com/bagder/curl/commit/curl-7_19_7-56-g4c8adc8 - - Bug: https://bugzilla.redhat.com/1279966 - Signed-off-by: Kamil Dudka - -Marc Hoersken (6 Dec 2015) -- hostkey.c: align code path of ssh_rsa_init to ssh_dss_init - -- hostkey.c: fix invalid memory access if libssh2_dsa_new fails - - Reported by dimmaq, fixes #66 - -Daniel Stenberg (3 Nov 2015) -- [Will Cosgrove brought this change] - - gcrypt: define libssh2_sha256_ctx - - Looks like it didn't make it into the latest commit for whatever reason. - - Closes #58 - -- [Salvador Fandino brought this change] - - libssh2_session_set_last_error: Add function - - Net::SSH2, the Perl wrapping module for libssh2 implements several features* - on top of libssh2 that can fail and so need some mechanism to report the error - condition to the user. - - Until now, besides the error state maintained internally by libssh2, another - error state was maintained at the Perl level for every session object and then - additional logic was used to merge both error states. That is a maintenance - nighmare, and actually there is no way to do it correctly and consistently. - - In order to allow the high level language to add new features to the library - but still rely in its error reporting features the new function - libssh2_session_set_last_error (that just exposses _libssh2_error_flags) is - introduced. - - *) For instance, connecting to a remote SSH service giving the hostname and - port. - - Signed-off-by: Salvador Fandino - Signed-off-by: Salvador Fandiño - -- [Salvador Fandino brought this change] - - _libssh2_error: Support allocating the error message - - Before this patch "_libssh2_error" required the error message to be a - static string. - - This patch adds a new function "_libssh2_error_flags" accepting an - additional "flags" argument and specifically the flag - "LIBSSH2_ERR_FLAG_DUP" indicating that the passed string must be - duplicated into the heap. - - Then, the method "_libssh2_error" has been rewritten to use that new - function under the hood. - - Signed-off-by: Salvador Fandino - Signed-off-by: Salvador Fandiño - -- [Will Cosgrove brought this change] - - added engine.h include to fix warning - -- [sune brought this change] - - kex.c: removed dupe entry from libssh2_kex_methods[] - - Closes #51 - -- [Salvador Fandiño brought this change] - - userauth: Fix off by one error when reading public key file - - After reading the public key from file the size was incorrectly - decremented by one. - - This was usually a harmless error as the last character on the public - key file is an unimportant EOL. But if due to some error the public key - file is empty, the public key size becomes (uint)(0 - 1), resulting in - an unrecoverable out of memory error later. - - Signed-off-by: Salvador Fandi??o - -- [Salvador Fandino brought this change] - - channel: Detect bad usage of libssh2_channel_process_startup - - A common novice programmer error (at least among those using the - wrapping Perl module Net::SSH2), is to try to reuse channels. - - This patchs detects that incorrect usage and fails with a - LIBSSH2_ERROR_BAD_USE error instead of hanging. - - Signed-off-by: Salvador Fandino - -- [Will Cosgrove brought this change] - - kex: Added diffie-hellman-group-exchange-sha256 support - - ... and fixed HMAC_Init depricated usage - - Closes #48 - -Alexander Lamaison (21 Sep 2015) -- Prefixed new #defines to prevent collisions. - - Other libraries might have their own USE_WIN32_*FILES. - -- [keith-daigle brought this change] - - Update examples/scp.c to fix bug where large files on win32 would cause got to wrap and go negative - -- [David Byron brought this change] - - add libssh2_scp_recv2 to support large (> 2GB) files on windows - -Daniel Stenberg (17 Sep 2015) -- [sune brought this change] - - WinCNG: support for SHA256/512 HMAC - - Closes #47 - -- [brian m. carlson brought this change] - - Add support for HMAC-SHA-256 and HMAC-SHA-512. - - Implement support for these algorithms and wire them up to the libgcrypt - and OpenSSL backends. Increase the maximum MAC buffer size to 64 bytes - to prevent buffer overflows. Prefer HMAC-SHA-256 over HMAC-SHA-512, and - that over HMAC-SHA-1, as OpenSSH does. - - Closes #40 - -- [Zenju brought this change] - - kex: free server host key before allocating it (again) - - Fixes a memory leak when Synology server requests key exchange - - Closes #43 - -- [Viktor Szakats brought this change] - - GNUmakefile: up OpenSSL version - - closes #23 - -- [Viktor Szakats brought this change] - - GNUmakefile: add -m64 CFLAGS when targeting mingw64, add -m32/-m64 to LDFLAGS - - libssh2 equivalent of curl patch https://github.com/bagder/curl/commit/d21b66835f2af781a3c2a685abc92ef9f0cd86be - - This allows to build for the non-default target when using a multi-target mingw distro. - Also bump default OpenSSL dependency path to 1.0.2c. - -- [Viktor Szakats brought this change] - - GNUmakefile: add support for LIBSSH2_LDFLAG_EXTRAS - - It is similar to existing LIBSSH2_CFLAG_EXTRAS, but for - extra linker options. - - Also delete some line/file ending whitespace. - - closes #27 - -- [nasacj brought this change] - - hostkey.c: Fix compiling error when OPENSSL_NO_MD5 is defined - - Closes #32 - -- [Mizunashi Mana brought this change] - - openssl.h: adjust the rsa/dsa includes - - ... to work when built without DSA support. - - Closes #36 - -Alexander Lamaison (26 Jul 2015) -- Let CMake build work as a subproject. - - Patch contributed by JasonHaslam. - -- Fix builds with Visual Studio 2015. - - VS2015 moved stdio functions to the header files as inline function. That means check_function_exists can't detect them because it doesn't use header files - just does a link check. Instead we need to use check_symbol_exists with the correct headers. - -Kamil Dudka (2 Jul 2015) -- cmake: include CMake files in the release tarballs - - Despite we announced the CMake support in libssh2-1.6.0 release notes, - the files required by the CMake build system were not included in the - release tarballs. Hence, the only way to use CMake for build was the - upstream git repository. - - This commit makes CMake actually supported in the release tarballs. - -- tests/mansyntax.sh: fix 'make distcheck' with recent autotools - - Do not create symbolic links off the build directory. Recent autotools - verify that out-of-source build works even if the source directory tree - is not writable. - -- openssl: fix memleak in _libssh2_dsa_sha1_verify() - -Daniel Stenberg (12 Jun 2015) -- openssl: make libssh2_sha1 return error code - - - use the internal prefix _libssh2_ for non-exported functions - - - removed libssh2_md5() since it wasn't used - - Reported-by: Kamil Dudka - -- [LarsNordin-LNdata brought this change] - - SFTP: Increase speed and datasize in SFTP read - - The function sftp_read never return more then 2000 bytes (as it should - when I asked Daniel). I increased the MAX_SFTP_READ_SIZE to 30000 but - didn't get the same speed as a sftp read in SecureSSH. I analyzed the - code and found that a return always was dona when a chunk has been read. - I changed it to a sliding buffer and worked on all available chunks. I - got an increase in speed and non of the test I have done has failed - (both local net and over Internet). Please review and test. I think - 30000 is still not the optimal MAX_SFTP_READ_SIZE, my next goal is to - make an API to enable changing this value (The SecureSSH sftp_read has - more complete filled packages when comparing the network traffic) - -- bump: start working on 1.6.1 - -Version 1.6.0 (5 Jun 2015) - -Daniel Stenberg (5 Jun 2015) -- RELEASE-NOTES: synced with 858930cae5c6a - -Marc Hoersken (19 May 2015) -- wincng.c: fixed indentation - -- [sbredahl brought this change] - - wincng.c: fixed memleak in (block) cipher destructor - -Alexander Lamaison (6 May 2015) -- [Jakob Egger brought this change] - - libssh2_channel_open: more detailed error message - - The error message returned by libssh2_channel_open in case of a server side channel open failure is now more detailed and includes the four standard error conditions in RFC 4254. - -- [Hannes Domani brought this change] - - kex: fix libgcrypt memory leaks of bignum - - Fixes #168. - -Marc Hoersken (3 Apr 2015) -- configure.ac: check for SecureZeroMemory for clear memory feature - -- Revert "wincng.c: fix clear memory feature compilation with mingw" - - This reverts commit 2d2744efdd0497b72b3e1ff6e732aa4c0037fc43. - - Autobuilds show that this did not solve the issue. - And it seems like RtlFillMemory is defined to memset, - which would be optimized out by some compilers. - -- wincng.c: fix clear memory feature compilation with mingw - -Alexander Lamaison (1 Apr 2015) -- [LarsNordin-LNdata brought this change] - - Enable use of OpenSSL that doesn't have DSA. - - Added #if LIBSSH2_DSA for all DSA functions. - -- [LarsNordin-LNdata brought this change] - - Use correct no-blowfish #define with OpenSSL. - - The OpenSSL define is OPENSSL_NO_BF, not OPENSSL_NO_BLOWFISH. - -Marc Hoersken (25 Mar 2015) -- configure: error if explicitly enabled clear-memory is not supported - - This takes 22bd8d81d8fab956085e2079bf8c29872455ce59 and - b8289b625e291bbb785ed4add31f4759241067f3 into account, - but still makes it enabled by default if it is supported - and error out in case it is unsupported and was requested. - -Daniel Stenberg (25 Mar 2015) -- configure: make clear-memory default but only WARN if backend unsupported - - ... instead of previous ERROR. - -Marc Hoersken (24 Mar 2015) -- wincng.h: fix warning about computed return value not being used - -- nonblocking examples: fix warning about unused tvdiff on Mac OS X - -Daniel Stenberg (24 Mar 2015) -- openssl: fix compiler warnings - -- cofigure: fix --disable-clear-memory check - -Marc Hoersken (23 Mar 2015) -- scp.c: improved command length calculation - - Reduced number of calls to strlen, because shell_quotearg already - returns the length of the resulting string (e.q. quoted path) - which we can add to the existing and known cmd_len. - Removed obsolete call to memset again, because we can put a final - NULL-byte at the end of the string using the calculated length. - -- scp.c: improved and streamlined formatting - -- scp.c: fix that scp_recv may transmit not initialised memory - -- scp.c: fix that scp_send may transmit not initialised memory - - Fixes ticket 244. Thanks Torsten. - -- kex: do not ignore failure of libssh2_sha1_init() - - Based upon 43b730ce56f010e9d33573fcb020df49798c1ed8. - Fixes ticket 290. Thanks for the suggestion, mstrsn. - -- wincng.h: fix return code of libssh2_md5_init() - -- openssl.c: fix possible segfault in case EVP_DigestInit fails - -- wincng.c: fix possible use of uninitialized variables - -- wincng.c: fix unused argument warning if clear memory is not enabled - -- wincng: Added explicit clear memory feature to WinCNG backend - - This re-introduces the original feature proposed during - the development of the WinCNG crypto backend. It still needs - to be added to libssh2 itself and probably other backends. - - Memory is cleared using the function SecureZeroMemory which is - available on Windows systems, just like the WinCNG backend. - -- wincng.c: fixed mixed line-endings - -- wincng.c: fixed use of invalid parameter types in a8d14c5dcf - -- wincng.c: only try to load keys corresponding to the algorithm - -- wincng.c: moved PEM headers into definitions - -- wincng.h: fixed invalid parameter name - -- wincng: fixed mismatch with declarations in crypto.h - -- userauth.c: fixed warning C6001: using uninitialized sig and sig_len - -- pem.c: fixed warning C6269: possible incorrect order of operations - -- wincng: add support for authentication keys to be passed in memory - - Based upon 18cfec8336e and daa2dfa2db. - -- pem.c: add _libssh2_pem_parse_memory to parse PEM from memory - - Requirement to implement 18cfec8336e for Libgcrypt and WinCNG. - -- pem.c: fix copy and paste mistake from 55d030089b8 - -- userauth.c: fix another possible dereference of a null pointer - -- userauth.c: fix possible dereference of a null pointer - -- pem.c: reduce number of calls to strlen in readline - -Alexander Lamaison (17 Mar 2015) -- [Will Cosgrove brought this change] - - Initialise HMAC_CTX in more places. - - Missed a couple more places we init ctx to avoid openssl threading crash. - -- Build build breakage in WinCNG backend caused when adding libssh2_userauth_publickey_frommemory. - - The new feature isn't implemented for the WinCNG backend currently, but the WinCNG backend didn't contain any implementation of the required backend functions - even ones that returns an error. That caused link errors. - - This change fixes the problem by providing an implementation of the backend functions that returns an error. - -- Fix breakage in WinCNG backend caused by introducing libssh2_hmac_ctx_init. - - The macro was defined to nothing for the libgcrypt backend, but not for WinCNG. This brings the latter into line with the former. - -Daniel Stenberg (15 Mar 2015) -- userauth_publickey_frommemory.3: add AVAILABILITY - - ... it will be added in 1.6.0 - -- libssh2: next version will be called 1.6.0 - - ... since we just added a new function. - -- docs: add libssh2_userauth_publickey_frommemory.3 to dist - - The function and man page were added in commit 18cfec8336e - -- [Jakob Egger brought this change] - - direct_tcpip: Fixed channel write - - There were 3 bugs in this loop: - 1) Started from beginning after partial writes - 2) Aborted when 0 bytes were sent - 3) Ignored LIBSSH2_ERROR_EAGAIN - - See also: - https://trac.libssh2.org/ticket/281 - https://trac.libssh2.org/ticket/293 - -Alexander Lamaison (15 Mar 2015) -- [Will Cosgrove brought this change] - - Must init HMAC_CTX before using it. - - Must init ctx before using it or openssl will reuse the hmac which is not thread safe and causes a crash. - Added libssh2_hmac_ctx_init macro. - -- Add continuous integration configurations. - - Linux-based CI is done by Travis CI. Windows-based CI is done by Appveyor. - -- [David Calavera brought this change] - - Allow authentication keys to be passed in memory. - - All credits go to Joe Turpin, I'm just reaplying and cleaning his patch: - http://www.libssh2.org/mail/libssh2-devel-archive-2012-01/0015.shtml - - * Use an unimplemented error for extracting keys from memory with libgcrypt. - -Daniel Stenberg (14 Mar 2015) -- docs: include the renamed INSTALL* files in dist - -Alexander Lamaison (13 Mar 2015) -- Prevent collisions between CMake and Autotools in examples/ and tests/. - -- Avoid clash between CMake build and Autotools. - - Autotools expects a configuration template file at src/libssh2_config.h.in, which buildconf generates. But the CMake build system has its CMake-specific version of the file at this path. This means that, if you don't run buildconf, the Autotools build will fail because it configured the wrong header template. - - See https://github.com/libssh2/libssh2/pull/8. - -- Merge pull request #8 from alamaison/cmake - - CMake build system. - -- CMake build system. - - Tested: - - Windows: - - Visual C++ 2005/2008/2010/2012/2013/MinGW-w64 - - static/shared - - 32/64-bit - - OpenSSL/WinCNG - - Without zlib - - Linux: - - GCC 4.6.3/Clang 3.4 - - static/shared - - 32/64-bit - - OpenSSL/Libgcrypt - - With/Without zlib - - MacOS X - - AppleClang 6.0.0 - - static - - 64-bit - - OpenSSL - - Without zlib - - Conflicts: - README - -- Man man syntax tests fail gracefully if man version is not suitable. - -- Return valid code from test fixture on failure. - - The sshd test fixture was returning -1 if an error occurred, but negative error codes aren't technically valid (google it). Bash on Windows converted them to 0 which made setup failure look as though all tests were passing. - -- Let mansyntax.sh work regardless of where it is called from. - -Daniel Stenberg (12 Mar 2015) -- [Viktor Szakáts brought this change] - - mingw build: allow to pass custom CFLAGS - - Allow to pass custom `CFLAGS` options via environment variable - `LIBSSH2_CFLAG_EXTRAS`. Default and automatically added options of - `GNUmakefile` have preference over custom ones. This addition is useful - for passing f.e. custom CPU tuning or LTO optimization (`-flto - -ffat-lto-objects`) options. The only current way to do this is to edit - `GNUmakefile`. This patch makes it unnecessary. - - This is a mirror of similar libcurl patch: - https://github.com/bagder/curl/pull/136 - -- [Will Cosgrove brought this change] - - userauth: Fixed prompt text no longer being copied to the prompts struct - - Regression from 031566f9c - -- README: update the git repo locations - -- wait_socket: wrong use of difftime() - - With reversed arguments it would always return a negative value... - - Bug: https://github.com/bagder/libssh2/issues/1 - -- bump: start working toward 1.5.1 now - -Version 1.5.0 (11 Mar 2015) - -Daniel Stenberg (11 Mar 2015) -- RELEASE-NOTES: 1.5.0 release - -- [Mariusz Ziulek brought this change] - - kex: bail out on rubbish in the incoming packet - - CVE-2015-1782 - - Bug: http://www.libssh2.org/adv_20150311.html - -- docs: move INSTALL, AUTHORS, HACKING and TODO to docs/ - - And with this, cleanup README to be shorter and mention the new source - code home. - -- .gitignore: don't ignore INSTALL - -Dan Fandrich (4 Mar 2015) -- examples/x11.c: include sys/select.h for improved portability - -Daniel Stenberg (4 Mar 2015) -- RELEASE-NOTES: synced with a8473c819bc068 - - In preparation for the upcoming 1.5.0 release. - -Guenter Knauf (8 Jan 2015) -- NetWare build: added some missing exports. - -Marc Hoersken (29 Dec 2014) -- knownhost.c: fix use of uninitialized argument variable wrote - - Detected by clang scan in line 1195, column 18. - -- examples/x11.c: fix result of operation is garbage or undefined - - Fix use of uninitialized structure w_size_bck. - Detected by clang scan in line 386, column 28. - -- examples/x11.c: remove dead assigments of some return values - - Detected by clang scan in line 212, column 9. - Detected by clang scan in line 222, column 13. - Detected by clang scan in line 410, column 13. - -- examples/x11.c: fix possible memory leak if read fails - - Detected by clang scan in line 224, column 21. - -- examples/x11.c: fix invalid removal of first list element - - Fix use of memory after it was being freed. - Detected by clang scan in line 56, column 12. - -- userauth.c: make sure that sp_len is positive and avoid overflows - - ... if the pointer subtraction of sp1 - pubkey - 1 resulted in a - negative or larger value than pubkey_len, memchr would fail. - - Reported by Coverity CID 89846. - -- channel.c: remove logically dead code, host cannot be NULL here - - ... host cannot be NULL in line 525, because it is always - valid (e.g. at least set to "0.0.0.0") after lines 430 and 431. - - Reported by Coverity CID 89807. - -- session.c: check return value of session_nonblock during startup - - Reported by Coverity CID 89803. - -- session.c: check return value of session_nonblock in debug mode - - Reported by Coverity CID 89805. - -- pem.c: fix mixed line-endings introduced with 8670f5da24 - -- pem.c: make sure there's a trailing zero and b64data is not NULL - - ... if there is no base64 data between PEM header and footer. - Reported by Coverity CID 89823. - -- kex.c: make sure mlist is not set to NULL - - ... if the currently unsupported LANG methods are called. - Reported by Coverity CID 89834. - -- packet.c: i < 256 was always true and i would overflow to 0 - - Visualize that the 0-termination is intentional, because the array - is later passed to strlen within _libssh2_packet_askv. - -- silence multiple data conversion warnings - -Daniel Stenberg (23 Dec 2014) -- agent_connect_unix: make sure there's a trailing zero - - ... if the path name was too long. Reported by Coverity CID 89801. - -Marc Hoersken (22 Dec 2014) -- examples on Windows: use native SOCKET-type instead of int - - And check return values accordingly. - -- userauth.c: improve readability and clarity of for-loops - -Daniel Stenberg (22 Dec 2014) -- calloc: introduce LIBSSH2_CALLOC() - - A simple function using LIBSSH2_ALLOC + memset, since this pattern was - used in multiple places and this simplies code in general. - -Marc Hoersken (15 Dec 2014) -- libssh2_priv.h: Ignore session, context and format parameters - -- x11 example: check return value of socket function - -- examples: fixed mixed line-endings introduced with aedfba25b8 - -- wincng.c: explicitly ignore BCrypt*AlgorithmProvider return codes - - Fixes VS2012 code analysis warning C6031: - return value ignored: could return unexpected value - -- wincng.c: fix possible invalid memory write access - - Fixes VS2012 code analysis warning C6386: - buffer overrun: accessing 'pbOutput', the writable size is - 'cbOutput' bytes, but '3' bytes may be written: libssh2 wincng.c 610 - -- tests on Windows: check for WSAStartup return code - - Fixes VS2012 code analysis warning C6031: - return value ignored: could return unexpected value - -- wincng.c: fix possible NULL pointer de-reference of bignum - - Fixes VS2012 code analysis warning C6011: - dereferencing NULL pointer 'bignum'. libssh2 wincng.c 1567 - -- wincng.c: fix possible use of uninitialized memory - - Fixes VS2012 code analysis warning C6001: - using uninitialized memory 'cbDecoded'. libssh2 wincng.c 553 - -- packet.c: fix possible NULL pointer de-reference within listen_state - - Fixes VS2012 code analysis warning C6011: - dereferencing NULL pointer 'listen_state->channel'. libssh2 packet.c 221 - -- kex.c: fix possible NULL pointer de-reference with session->kex - - Fixes VS2012 code analysis warning C6011: - dereferencing NULL pointer 'session->kex'. libssh2 kex.c 1761 - -- agent.c: check return code of MapViewOfFile - - Fixes VS2012 code analysis warning C6387: 'p+4' may be '0': - this does not adhere to the specification for the function - 'memcpy': libssh2 agent.c 330 - - Fixes VS2012 code analysis warning C6387: 'p' may be '0': - this does not adhere to the specification for the function - 'UnmapViewOfFile': libssh2 agent.c 333 - -- examples on Windows: check for socket return code - - Fixes VS2012 code analysis warning C28193: - The variable holds a value that must be examined - -- examples on Windows: check for WSAStartup return code - - Fixes VS2012 code analysis warning C6031: - return value ignored: could return unexpected value - -Guenter Knauf (11 Dec 2014) -- wincng.c: silent some more gcc compiler warnings. - -- wincng.c: silent gcc compiler warnings. - -- Watcom build: added support for WinCNG build. - -- build: updated dependencies in makefiles. - -Daniel Stenberg (4 Dec 2014) -- configure: change LIBS not LDFLAGS when checking for libs - - Closes #289 - - Patch-by: maurerpe - -Guenter Knauf (3 Dec 2014) -- MinGW build: some more GNUMakefile tweaks. - - test/GNUmakefile: added architecture autodetection; added switches to - CFLAGS and RCFLAGS to make sure that the right architecture is used. - Added support to build with WinCNG. - -- sftpdir.c: added authentication method detection. - - Stuff copied over from ssh2.c to make testing a bit easier. - -- NMake build: fixed LIBS settings. - -- NMake build: added support for WinCNG build. - -- MinGW build: some GNUMakefile tweaks. - - Added architecture autodetection; added switches to CFLAGS and - RCFLAGS to make sure that the right architecture is used. - Added support to build with WinCNG. - -- MinGW build: Fixed redefine warnings. - -- Updated copyright year. - -Daniel Stenberg (31 Aug 2014) -- COPYING: bump the copyright year - -Dan Fandrich (28 Jul 2014) -- docs: fixed a bunch of typos - -- docs: added missing libssh2_session_handshake.3 file - -Marc Hoersken (19 May 2014) -- wincng.c: specify the required libraries for dependencies using MSVC - - Initially reported by Bob Kast as "for MS VS builds, specify the - libraries that are required so they don't need to go into all - project files that may use this library". Thanks a lot. - -- [Bob Kast brought this change] - - windows build: do not export externals from static library - - If you are building a DLL, then you need to explicitly export each - entry point. When building a static library, you should not. - - libssh2 was exporting the entry points whether it was building a DLL or a - static library. To elaborate further, if libssh2 was used as a static - library, which was being linked into a DLL, the libssh2 API would be - exported from that separate DLL. - -Daniel Stenberg (19 May 2014) -- [Mikhail Gusarov brought this change] - - Fix typos in manpages - -Marc Hoersken (18 May 2014) -- wincng.c: Fixed memory leak in case of an error during ASN.1 decoding - -- configure: Display individual crypto backends on separate lines - - This avoids line-wrapping in between parameters and makes the - error message look like the following: - - configure: error: No crypto library found! - Try --with-libssl-prefix=PATH - or --with-libgcrypt-prefix=PATH - or --with-wincng on Windows - -- [Bob Kast brought this change] - - libssh2_priv.h: a 1 bit bit-field should be unsigned - - some compilers may not like this - -- knownhost.c: Fixed warning that pointer targets differ in signedness - -- wincng.c: Fixed warning about pointer targets differing in signedness - -- tcpip-forward.c: Fixed warning that pointer targets differ in signedness - - libssh2_channel_forward_listen_ex uses ints instead of unsigned ints. - -- misc.c: Fixed warning about mixed declarations and code - -- libgcrypt.h: Fixed warning about pointer targets differing in signedness - -- wincng.h: Fixed warning about pointer targets differing in signedness - -- misc.c: Fixed warning about unused parameter abstract - -- tcpip-forward.c: Removed unused variables shost, sport and sockopt - -- wincng.h: Added forward declarations for all WinCNG functions - - Initially reported by Bob Kast as "Wincng - define function - prototypes for wincng routines". Thanks a lot. - - Also replaced structure definitions with type definitions. - -- [Bob Kast brought this change] - - libssh2.h: on Windows, a socket is of type SOCKET, not int - -- win32: Added WinCNG targets to generated Visual Studio project - - Inspired by Bob Kast's reports, this commit enables the compilation - of libssh2 with WinCNG using the generated Visual Studio project files. - This commit adds WinCNG support to parts of the existing Win32 build - infrastructure, until new build systems, like pre-defined VS project - files or CMake files may be added. - - This commit and b20bfeb3e519119a48509a1099c06d65aa7da1d7 raise one - question: How to handle build systems, like VS project files, that - need to include all source files regardless of the desired target, - including all supported crypto backends? For now the mentioned commit - added a check for LIBSSH2_OPENSSL to openssl.c and with this commit - the supported crypto backends are hardcoded within Makefile.am. - -- libssh2_priv msvc: Removed redundant definition of inline keyword - - Initially reported by Bob Kast as "Remove redundant 'inline' define". - Thanks a lot. - -- wincng: Made data parameter to hash update function constant - - Initially reported by Bob Kast as "formal parameter must be const - since it is used in contexts where the actual parameter may be const". - Thanks a lot. - -- wincng: fix cross-compilation against the w64 mingw-runtime package - -- openssl: Check for LIBSSH2_OPENSSL in order to compile with openssl - -- wincng: Fixed use of possible uninitialized variable pPaddingInfo - - Reported by Bob Kast, thanks a lot. - -- wincng: Added cast for double to unsigned long conversion - -- wincng: Cleaned up includes and check NTSTATUS using macro - - Removed header file combination that is not supported on a real - Windows platform and can only be compiled using MinGW. Replaced - custom NTSTATUS return code checks with BCRYPT_SUCCESS macro. - -Daniel Stenberg (16 Mar 2014) -- userauth_hostbased_fromfile: zero assign to avoid uninitialized use - - Detected by clang-analyze - -- channel_receive_window_adjust: store windows size always - - Avoid it sometimes returning without storing it, leaving calling - functions with unknown content! - - Detected by clang-analyzer - -- publickey_packet_receive: avoid junk in returned pointers - - clang-analyzer found this risk it would return a non-initialized pointer - in a success case - -Peter Stuge (16 Mar 2014) -- [Marc Hoersken brought this change] - - Added Windows Cryptography API: Next Generation based backend - -- [Marc Hoersken brought this change] - - knownhost.c: fixed that 'key_type_len' may be used uninitialized - - ../src/knownhost.c: In function 'libssh2_knownhost_readline': - ../src/knownhost.c:651:16: warning: 'key_type_len' may be used - uninitialized in this function [-Wmaybe-uninitialized] - rc = knownhost_add(hosts, hostbuf, NULL, - ^ - ../src/knownhost.c:745:12: note: 'key_type_len' was declared here - size_t key_type_len; - ^ - -- [Marc Hoersken brought this change] - - pem.c: always compile pem.c independently of crypto backend - -- Fix non-autotools builds: Always define the LIBSSH2_OPENSSL CPP macro - - Commit d512b25f69a1b6778881f6b4b5ff9cfc6023be42 introduced a crypto - library abstraction in the autotools build system, to allow us to more - easily support new crypto libraries. In that process it was found that - all other build system which we support are hard-coded to build with - OpenSSL. Commit f5c1a0d98bd51aeb24aca3d49c7c81dcf8bd858d fixes automake - introduced into non-autotools build systems but still overlooked the - CPP macro saying that we are using OpenSSL. - - Thanks to Marc Hörsken for identifying this issue and proposing a fix - for win32/{GNUmakefile,config.mk}. This commit uses a slightly different - approach but the end result is the same. - -Dan Fandrich (15 Mar 2014) -- channel_close: Close the channel even in the case of errors - -- sftp_close_handle: ensure the handle is always closed - - Errors are reported on return, but otherwise the close path is - completed as much as possible and the handle is freed on exit. - -Alexander Lamaison (6 Mar 2014) -- knownhost: Restore behaviour of `libssh2_knownhost_writeline` with short buffer. - - Commit 85c6627c changed the behaviour of `libssh2_knownhost_writeline` so that it stopped returning the number of bytes needed when the given buffer was too small. Also, the function changed such that is might write to part of the buffer before realising it is too small. - - This commit restores the original behaviour, whilst keeping the unknown-key-type functionality that 85c6627c. Instead of writing to the buffer piecemeal, the length of the various parts is calculated up front and the buffer written only if there is enough space. The calculated necessary size is output in `outlen` regardless of whether the buffer was written to. - - The main use-case for the original behaviour that this commit restores is to allow passing in a NULL buffer to get the actual buffer size needed, before calling the function again with the buffer allocated to the exact size required. - -- knownhost: Fix DSS keys being detected as unknown. - - I missing `else` meant ssh-dss format keys were being re-detected as unknown format. - -Dan Fandrich (6 Mar 2014) -- knownhosts: Abort if the hosts buffer is too small - - This could otherwise cause a match on the wrong host - -- agent_list_identities: Fixed memory leak on OOM - -- Fixed a few typos - -- userauth: Fixed an attempt to free from stack on error - -- Fixed a few memory leaks in error paths - -- Fixed two potential use-after-frees of the payload buffer - - The first might occur if _libssh2_packet_add returns an error, as - fullpacket_state wasn't reset to idle so if it were possible for - fullpacket to be called again, it would return to the same state - handler and re-use the freed p->packet buffer. - - The second could occur if decrypt returned an error, as it freed the - packet buffer but did not clear total_num, meaning that freed buffer - could be written into again later. - -Alexander Lamaison (28 Nov 2013) -- Fix missing `_libssh2_error` in `_libssh2_channel_write`. - - In one case, the error code from `_libssh2_transport_read` was being returned from `_libssh2_channel_write` without setting it as the last error by calling `_libssh2_error`. This commit fixes that. - - Found when using a session whose socket had been inadvertently destroyed. The calling code got confused because via `libssh2_session_last_error` it appeared no error had occurred, despite one being returned from the previous function. - -Kamil Dudka (21 Nov 2013) -- [Mark McPherson brought this change] - - openssl: initialise the digest context before calling EVP_DigestInit() - - When using the OpenSSL libraries in FIPS mode, the function call - EVP_DigestInit() is actually #defined to FIPS_digestinit(). - Unfortunately wheres EVP_DigestInit() initialises the context and then - calls EVP_DigestInit_ex(), this function assumes that the context has - been pre-initialised and crashes when it isn't. - - Bug: https://trac.libssh2.org/ticket/279 - - Fixes #279 - -- [Marc Hörsken brought this change] - - .gitignore: Ignore files like src/libssh2_config.h.in~ - -Peter Stuge (13 Nov 2013) -- Move automake conditionals added by commit d512b25f out of Makefile.inc - - Commit d512b25f69a1b6778881f6b4b5ff9cfc6023be42 added automake - conditionals to Makefile.inc but since Makefile.inc is included - from Makefile for all other build systems that does not work. - - This commit instead adds Makefile.OpenSSL.inc and Makefile.libgcrypt.inc - and moves the automake conditional to its proper place, src/Makefile.am. - - The automake conditional includes the correct Makefile.$name.inc per - the crypto library selection/detection done by configure. - - All non-autotools build system files in libssh2 are hardcoded to use - OpenSSL and do not get a conditional but at least there is some reuse - because they can all include the new Makefile.OpenSSL.inc. - -Daniel Stenberg (27 Oct 2013) -- [Salvador Fandino brought this change] - - Set default window size to 2MB - - The default channel window size used until now was 256KB. This value is - too small and results on a bottleneck on real-life networks where - round-trip delays can easily reach 300ms. - - The issue was not visible because the configured channel window size - was being ignored and a hard-coded value of ~22MB being used instead, - but that was fixed on a previous commit. - - This patch just changes the default window size - (LIBSSH2_CHANNEL_WINDOW_DEFAULT) to 2MB. It is the same value used by - OpenSSH and in our opinion represents a good compromise between memory - used and transfer speed. - - Performance tests were run to determine the optimum value. The details - and related discussion are available from the following thread on the - libssh2 mailing-list: - - http://www.libssh2.org/mail/libssh2-devel-archive-2013-10/0018.shtml - http://article.gmane.org/gmane.network.ssh.libssh2.devel/6543 - - An excerpt follows: - - "I have been running some transfer test and measuring their speed. - - My setup was composed of a quad-core Linux machine running Ubuntu 13.10 - x86_64 with a LXC container inside. The data transfers were performed - from the container to the host (never crossing through a physical - network device). - - Network delays were simulated using the tc tool. And ping was used to - verify that they worked as intended during the tests. - - The operation performed was the equivalent to the following ssh command: - - $ ssh container "dd bs=16K count=8K if=/dev/zero" >/dev/null - - Though, establishment and closing of the SSH connection was excluded - from the timings. - - I run the tests several times transferring files of sizes up to 128MB - and the results were consistent between runs. - - The results corresponding to the 128MB transfer are available here: - - https://docs.google.com/spreadsheet/ccc?key=0Ao1yRmX6PQQzdG5wSFlrZl9HRWNET3ZyN0hnaGo5ZFE&usp=sharing - - It clearly shows that 256KB is too small as the default window size. - Moving to a 512MB generates a great improvement and after the 1MB mark - the returns rapidly diminish. Other factors (TCP window size, probably) - become more limiting than the channel window size - - For comparison I also performed the same transfers using OpenSSH. Its - speed is usually on par with that of libssh2 using a window size of 1MB - (even if it uses a 2MB window, maybe it is less aggressive sending the - window adjust msgs)." - - Signed-off-by: Salvador Fandino - -- [Salvador brought this change] - - _libssh2_channel_read: Honour window_size_initial - - _libssh2_channel_read was using an arbitrary hard-coded limit to trigger - the window adjusting code. The adjustment used was also hard-coded and - arbitrary, 15MB actually, which would limit the usability of libssh2 on - systems with little RAM. - - This patch, uses the window_size parameter passed to - libssh2_channel_open_ex (stored as remote.window_size_initial) plus the - buflen as the base for the trigger and the adjustment calculation. - - The memory usage when using the default window size is reduced from 22MB - to 256KB per channel (actually, if compression is used, these numbers - should be incremented by ~50% to account for the errors between the - decompressed packet sizes and the predicted sizes). - - My tests indicate that this change does not impact the performance of - transfers across localhost or a LAN, being it on par with that of - OpenSSH. On the other hand, it will probably slow down transfers on - networks with high bandwidth*delay when the default window size - (LIBSSH2_CHANNEL_WINDOW_DEFAULT=256KB) is used. - - Signed-off-by: Salvador Fandino - -- [Salvador Fandino brought this change] - - knownhosts: handle unknown key types - - Store but don't use keys of unsupported types on the known_hosts file. - - Currently, when libssh2 parses a known_host file containing keys of some - type it doesn't natively support, it stops reading the file and returns - an error. - - That means, that the known_host file can not be safely shared with other - software supporting other key types (i.e. OpenSSH). - - This patch adds support for handling keys of unknown type. It can read - and write them, even if they are never going to be matched. - - At the source level the patch does the following things: - - - add a new unknown key type LIBSSH2_KNOWNHOST_KEY_UNKNOWN - - - add a new slot (key_type_name) on the known_host struct that is - used to store the key type in ascii form when it is not supported - - - parse correctly known_hosts entries with unknown key types and - populate the key_type_name slot - - - print correctly known_hosts entries of unknown type - - - when checking a host key ignore keys that do not match the key - - Fixes #276 - -- windows build: fix build errors - - Fixes various link errors with VS2010 - - Reported-by: "kdekker" - Fixes #272 - -- man page: add missing function argument - - for libssh2_userauth_publickey_fromfile_ex() - - Reported-by: "pastey" - - Fixes #262 - -- [Salvador brought this change] - - Fix zlib deflate usage - - Deflate may return Z_OK even when not all data has been compressed - if the output buffer becomes full. - - In practice this is very unlikely to happen because the output buffer - size is always some KBs larger than the size of the data passed for - compression from the upper layers and I think that zlib never expands - the data so much, even on the worst cases. - - Anyway, this patch plays on the safe side checking that the output - buffer is not exhausted. - - Signed-off-by: Salvador - -- [Salvador brought this change] - - comp_method_zlib_decomp: Improve buffer growing algorithm - - The old algorithm was O(N^2), causing lots and lots of reallocations - when highly compressed data was transferred. - - This patch implements a simpler one that just doubles the buffer size - everytime it is exhausted. It results in O(N) complexity. - - Also a smaller inflate ratio is used to calculate the initial size (x4). - - Signed-off-by: Salvador - -- [Salvador brought this change] - - Fix zlib usage - - Data may remain in zlib internal buffers when inflate() returns Z_OK - and avail_out == 0. In that case, inflate has to be called again. - - Also, once all the data has been inflated, it returns Z_BUF_ERROR to - signal that the input buffer has been exhausted. - - Until now, the way to detect that a packet payload had been completely - decompressed was to check that no data remained on the input buffer - but that didn't account for the case where data remained on the internal - zlib buffers. - - That resulted in packets not being completely decompressed and the - missing data reappearing on the next packet, though the bug was masked - by the buffer allocation algorithm most of the time and only manifested - when transferring highly compressible data. - - This patch fixes the zlib usage. - - Signed-off-by: Salvador - -- [Salvador brought this change] - - _libssh2_channel_read: fix data drop when out of window - - After filling the read buffer with data from the read queue, when the - window size was too small, "libssh2_channel_receive_window_adjust" was - called to increase it. In non-blocking mode that function could return - EAGAIN and, in that case, the EAGAIN was propagated upwards and the data - already read on the buffer lost. - - The function was also moving between the two read states - "libssh2_NB_state_idle" and "libssh2_NB_state_created" both of which - behave in the same way (excepting a debug statment). - - This commit modifies "_libssh2_channel_read" so that the - "libssh2_channel_receive_window_adjust" call is performed first (when - required) and if everything goes well, then it reads the data from the - queued packets into the read buffer. - - It also removes the useless "libssh2_NB_state_created" read state. - - Some rotted comments have also been updated. - - Signed-off-by: Salvador - -- [Salvador Fandino brought this change] - - window_size: redid window handling for flow control reasons - - Until now, the window size (channel->remote.window_size) was being - updated just after receiving the packet from the transport layer. - - That behaviour is wrong because the channel queue may grow uncontrolled - when data arrives from the network faster that the upper layer consumes - it. - - This patch adds a new counter, read_avail, which keeps a count of the - bytes available from the packet queue for reading. Also, now the window - size is adjusted when the data is actually read by an upper layer. - - That way, if the upper layer stops reading data, the window will - eventually fill and the remote host will stop sending data. When the - upper layers reads enough data, a window adjust packet is delivered and - the transfer resumes. - - The read_avail counter is used to detect the situation when the remote - server tries to send data surpassing the window size. In that case, the - extra data is discarded. - - Signed-off-by: Salvador - -Peter Stuge (15 Sep 2013) -- configure.ac: Call zlib zlib and not libz in text but keep option names - -- configure.ac: Reorder --with-* options in --help output - -- configure.ac: Rework crypto library detection - - This further simplifies adding new crypto libraries. - -- Clean up crypto library abstraction in build system and source code - - libssh2 used to explicitly check for libgcrypt and default to OpenSSL. - - Now all possible crypto libraries are checked for explicitly, making - the addition of further crypto libraries both simpler and cleaner. - -- configure.ac: Add zlib to Requires.private in libssh2.pc if using zlib - -- Revert "Added Windows Cryptography API: Next Generation based backend" - - This reverts commit d385230e15715e67796f16f3e65fd899f21a638b. - -Daniel Stenberg (7 Sep 2013) -- [Leif Salomonsson brought this change] - - sftp_statvfs: fix for servers not supporting statfvs extension - - Fixes issue arising when server does not support statfvs and or fstatvfs - extensions. sftp_statvfs() and sftp_fstatvfs() after this patch will - handle the case when SSH_FXP_STATUS is returned from server. - -- [Marc Hoersken brought this change] - - Added Windows Cryptography API: Next Generation based backend - -- [Kamil Dudka brought this change] - - partially revert "window_size: explicit adjustments only" - - This partially reverts commit 03ca9020756a4e16f0294e5b35e9826ee6af2364 - in order to fix extreme slowdown when uploading to localhost via SFTP. - - I was able to repeat the issue on RHEL-7 on localhost only. It did not - occur when uploading via network and it did not occur on a RHEL-6 box - with the same version of libssh2. - - The problem was that sftp_read() used a read-ahead logic to figure out - the window_size, but sftp_packet_read() called indirectly from - sftp_write() did not use any read-ahead logic. - -- _libssh2_channel_write: client spins on write when window full - - When there's no window to "write to", there's no point in waiting for - the socket to become writable since it most likely just will continue to - be. - - Patch-by: ncm - Fixes #258 - -- _libssh2_channel_forward_cancel: avoid memory leaks on error - - Fixes #257 - -- _libssh2_packet_add: avoid using uninitialized memory - - In _libssh2_packet_add, called by _libssh2_packet_read, a call to - _libssh2_packet_send that is supposed to send a one-byte message - SSH_MSG_REQUEST_FAILURE would send an uninitialized byte upon re-entry - if its call to _send returns _EAGAIN. - - Fixes #259 - -- _libssh2_channel_forward_cancel: accessed struct after free - - ... and the assignment was pointless anyway since the struct was about - to be freed. Bug introduced in dde2b094. - - Fixes #268 - -Peter Stuge (2 Jun 2013) -- [Marc Hoersken brought this change] - - Fixed compilation using mingw-w64 - -- [Marc Hoersken brought this change] - - knownhost.c: use LIBSSH2_FREE macro instead of free - - Use LIBSSH2_FREE instead of free since - _libssh2_base64_encode uses LIBSSH2_ALLOC - -Daniel Stenberg (18 May 2013) -- [Matthias Kerestesch brought this change] - - libssh2_agent_init: init ->fd to LIBSSH2_INVALID_SOCKET - - ... previously it was left at 0 which is a valid file descriptor! - - Bug: https://trac.libssh2.org/ticket/265 - - Fixes #265 - -- userauth_password: pass on the underlying error code - - _libssh2_packet_requirev() may return different errors and we pass that - to the parent instead of rewriting it. - - Bug: http://libssh2.org/mail/libssh2-devel-archive-2013-04/0029.shtml - Reported by: Cosmin - -Peter Stuge (9 May 2013) -- [Marc Hoersken brought this change] - - libcrypt.c: Fix typo in _libssh2_rsa_sha1_sign() parameter type - -Kamil Dudka (4 May 2013) -- configure.ac: replace AM_CONFIG_HEADER with AC_CONFIG_HEADERS - - Reported by: Quintus - Bug: https://trac.libssh2.org/ticket/261 - -Guenter Knauf (12 Apr 2013) -- Fixed copyright string for NetWare build. - -Daniel Stenberg (9 Apr 2013) -- [Richard W.M. Jones brought this change] - - sftp: Add support for fsync (OpenSSH extension). - - The new libssh2_sftp_fsync API causes data and metadata in the - currently open file to be committed to disk at the server. - - This is an OpenSSH extension to the SFTP protocol. See: - - https://bugzilla.mindrot.org/show_bug.cgi?id=1798 - -- [Richard W.M. Jones brought this change] - - sftp: statvfs: Along error path, reset the correct 'state' variable. - -- [Richard W.M. Jones brought this change] - - sftp: seek: Don't flush buffers on same offset - - Signed-off-by: Richard W.M. Jones - -Guenter Knauf (9 Feb 2013) -- Updated dependency libs. - -- Fixed tool macro names. - -Daniel Stenberg (29 Nov 2012) -- [Seth Willits brought this change] - - compiler warnings: typecast strlen in macros - - ... in macro parameters to avoid compiler warnings about lost precision. - - Several macros in libssh2.h call strlen and pass the result directly to - unsigned int parameters of other functions, which warns about precision - loss because strlen returns size_t which is unsigned long on at least - some platforms (such as OS X). The fix is to simply typecast the - strlen() result to unsigned int. - -- libssh2.h: bump version to 1.4.4-DEV - -Version 1.4.3 (27 Nov 2012) - -Daniel Stenberg (27 Nov 2012) -- RELEASE-NOTES: fixed for 1.4.3 - -- sftp_read: return error if a too large package arrives - -Peter Stuge (13 Nov 2012) -- Only define _libssh2_dsa_*() functions when building with DSA support - -Guenter Knauf (8 Nov 2012) -- Added .def file to output. - -Kamil Dudka (1 Nov 2012) -- libssh2_hostkey_hash.3: update the description of return value - - The function returns NULL also if the hash algorithm is not available. - -Guenter Knauf (24 Oct 2012) -- Fixed mode acciedently committed. - -- Ignore generated file. - -- Added hack to make use of Makefile.inc. - - This should avoid further maintainance of the objects list. - -- Fixed MSVC NMakefile. - - Added missing source files; added resource for DLL. - -Kamil Dudka (22 Oct 2012) -- examples: use stderr for messages, stdout for data - - Reported by: Karel Srot - Bug: https://bugzilla.redhat.com/867462 - -- openssl: do not leak memory when handling errors - - ,.. in aes_ctr_init(). Detected by Coverity. - -- channel: fix possible NULL dereference - - ... in libssh2_channel_get_exit_signal(). Detected by Coverity. - -- Revert "aes: the init function fails when OpenSSL has AES support" - - This partially reverts commit f4f2298ef3635acd031cc2ee0e71026cdcda5864. - - We need to use the EVP_aes_???_ctr() functions in FIPS mode. - -- crypt: use hard-wired cipher block sizes consistently - -- openssl: do not ignore failure of EVP_CipherInit() - -- kex: do not ignore failure of libssh2_md5_init() - - The MD5 algorithm is disabled when running in FIPS mode. - -Daniel Stenberg (21 Aug 2012) -- [Peter Krempa brought this change] - - known_hosts: Fail when parsing unknown keys in known_hosts file. - - libssh2_knownhost_readfile() silently ignored problems when reading keys - in unsupported formats from the known hosts file. When the file is - written again from the internal structures of libssh2 it gets truntcated - to the point where the first unknown key was located. - - * src/knownhost.c:libssh2_knownhost_readfile() - return error if key - parsing fails - -- AUTHORS: synced with 42fec44c8a4 - - 31 recent authors added - -- [Dave Hayden brought this change] - - compression: add support for zlib@openssh.com - - Add a "use_in_auth" flag to the LIBSSH2_COMP_METHOD struct and a - separate "zlib@openssh.com" method, along with checking session->state - for LIBSSH2_STATE_AUTHENTICATED. Appears to work on the OpenSSH servers - I've tried against, and it should work as before with normal zlib - compression. - -- [Dmitry Smirnov brought this change] - - configure: gcrypt doesn't come with pkg-config support - - ... so use plain old -lgcrypt to the linker to link with it. - - Fixes #225 - -- sftp_read: Value stored to 'next' is never read - - Detected by clang-analyzer - -- publickey_init: errors are negative, fix check - - Detected by clang-analyzer. - -- [Maxime Larocque brought this change] - - session_free: wrong variable used for keeping state - - If libssh2_session_free is called without the channel being freed - previously by libssh2_channel_free a memory leak could occur. - - A mismatch of states variables in session_free() prevent the call to - libssh2_channel_free function. session->state member is used instead of - session->free_state. - - It causes a leak of around 600 bytes on every connection on my systems - (Linux, x64 and PPC). - - (Debugging done under contract for Accedian Networks) - - Fixes #246 - -Guenter Knauf (29 Jun 2012) -- Small NetWare makefile tweak. - -- Some small Win32 makefile fixes. - -Daniel Stenberg (19 Jun 2012) -- libssh2_userauth_publickey_fromfile_ex.3: mention publickey == NULL - -- comp_method_zlib_decomp: handle Z_BUF_ERROR when inflating - - When using libssh2 to perform an SFTP file transfer from the "JSCAPE MFT - Server" (http://www.jscape.com) the transfer failed. The default JSCAPE - configuration is to enforce zlib compression on SSH2 sessions so the - session was compressed. The relevant part of the debug trace contained: - - [libssh2] 1.052750 Transport: unhandled zlib error -5 - [libssh2] 1.052750 Failure Event: -29 - decompression failure - - The trace comes from comp_method_zlib_decomp() in comp.c. The "unhandled - zlib error -5" is the status returned from the zlib function - inflate(). The -5 status corresponds to "Z_BUF_ERROR". - - The inflate() function takes a pointer to a z_stream structure and - "inflates" (decompresses) as much as it can. The relevant fields of the - z_stream structure are: - - next_in - pointer to the input buffer containing compressed data - avail_in - the number of bytes available at next_in - next_out - pointer to the output buffer to be filled with uncompressed - data - avail_out - how much space available at next_out - - To decompress data you set up a z_stream struct with the relevant fields - filled in and pass it to inflate(). On return the fields will have been - updated so next_in and avail_in show how much compressed data is yet to - be processed and next_out and avail_out show how much space is left in - the output buffer. - - If the supplied output buffer is too small then on return there will be - compressed data yet to be processed (avail_in != 0) and inflate() will - return Z_OK. In this case the output buffer must be grown, avail_out - updated and inflate() called again. - - If the supplied output buffer was big enough then on return the - compressed data will have been exhausted (avail_in == 0) and inflate() - will return Z_OK, so the data has all been uncompressed. - - There is a corner case where inflate() makes no progress. That is, there - may be unprocessed compressed data and space available in the output - buffer and yet the function does nothing. In this case inflate() will - return Z_BUF_ERROR. From the zlib documentation and the source code it - is not clear under what circumstances this happens. It could be that it - needs to write multiple bytes (all in one go) from its internal state to - the output buffer before processing the next chunk of input but but - can't because there is not enough space (though my guesses as to the - cause are not really relevant). Recovery from Z_BUF_ERROR is pretty - simple - just grow the output buffer, update avail_out and call - inflate() again. - - The comp_method_zlib_decomp() function does not handle the case when - inflate() returns Z_BUF_ERROR. It treats it as a non-recoverable error - and basically aborts the session. - - Fixes #240 - -Guenter Knauf (12 Jun 2012) -- MinGW makefile tweaks. - - Use GNU tools when compiling on Linux. - Fixed dist and dev targets. - -- NetWare makefile tweaks. - - Changed to use Windows commandline tools instead of - GNU tools when compiling on Windows. Fixed dist and - dev targets. Enabled nlmconv error for unresolved - symbols. - -Daniel Stenberg (11 Jun 2012) -- Revert "config.rpath: generated file, no need to keep in git" - - This reverts commit 1ac7bd09cc685755577fb2c8829adcd081e7ab3c. - - This file still used by lib/*m4 functions so we need to keep the file - around. - -- BINDINGS: added PySsh2, a Python-ctypes binding - -Guenter Knauf (8 Jun 2012) -- Fixed MinGW debug build. - -Daniel Stenberg (5 Jun 2012) -- BINDINGS: Added the Cocoa/Objective-C one - - ... and sorted the bindings after the languages, alphabetically - - Reported by: Mike Abdullah - -- BINDINGS: document the bindings we know of - -Guenter Knauf (4 Jun 2012) -- Fixed LIBSSH2_INT64_T_FORMAT macro. - - Usually a format macro should hold the whole format, otherwise - it should be named a prefix. Also fixed usage of this macro in - scp.c for a signed var where it was used as prefix for unsigned. - -- Removed obsolete define from makefiles. - -- Renamed NetWare makefiles. - -- Renamed NetWare makefiles. - -- Synced MinGW makefiles with 56c64a6..39e438f. - - Also synced MinGW test makefile with b092696..f8cb874. - -Peter Stuge (30 May 2012) -- Revert "sftp: Don't send attrs.permissions on read-only SSH_FXP_OPEN" - - This reverts commit 04e79e0c798674a0796be8a55f63dd92e6877790. - -- sftp: Don't send attrs.permissions on read-only SSH_FXP_OPEN - - This works around a protocol violation in the ProFTPD 1.3.4 mod_sftp - server, as reported by Will Cosgrove in: - - http://libssh2.org/mail/libssh2-devel-archive-2012-05/0079.shtml - - Based on a suggested fix by TJ Saunders in: - - http://libssh2.org/mail/libssh2-devel-archive-2012-05/0104.shtml - -Guenter Knauf (28 May 2012) -- Try to detect OpenSSL build type automatically. - - Also fixed recently added libgdi32 linkage which is only - required when OpenSSL libs are linked statically. - -Daniel Stenberg (25 May 2012) -- config.rpath: generated file, no need to keep in git - -Guenter Knauf (22 May 2012) -- Updated dependency libary versions. - -Daniel Stenberg (18 May 2012) -- 1.4.3: towards the future - -Version 1.4.2 (18 May 2012) - -Daniel Stenberg (18 May 2012) -- RELEASE-NOTES: synced with 92a9f952794 - -Alexander Lamaison (15 May 2012) -- win32/libssh2_config.h: Remove hardcoded #define LIBSSH2_HAVE_ZLIB. - - Rationale: Everything else in this file states a fact about the win32 - platform that is unconditional for that platform. There is nothing - unconditional about the presence of zlib. It is neither included with - Windows nor with the platform SDK. Therefore, this is not an appropriate - place to assert its presence. Especially as, once asserted, it cannot be - overridden using a compiler flag. - - In contrast, if it is omitted, then it can easily be reasserted by adding - a compiler flag defining LIBSSH2_HAVE_ZLIB. - -Daniel Stenberg (14 May 2012) -- RELEASE-NOTES: synced with 69a3354467c - -- _libssh2_packet_add: SSH_MSG_CHANNEL_REQUEST default to want_reply - - RFC4254 says the default 'want_reply' is TRUE but the code defaulted to - FALSE. Now changed. - - Fixes #233 - -- gettimeofday: no need for a replacement under cygwin - - Fixes #224 - -Alexander Lamaison (13 May 2012) -- Prevent sftp_packet_read accessing freed memory. - - sftp_packet_add takes ownership of the packet passed to it and (now that we - handle zombies) might free the packet. sftp_packet_read uses the packet type - byte as its return code but by this point sftp_packet_add might have freed - it. This change fixes the problem by caching the packet type before calling - sftp_packet_add. - - I don't understand why sftp_packet_read uses the packet type as its return - code. A future change might get rid of this entirely. - -Daniel Stenberg (12 May 2012) -- sftp_packet_flush: flush zombies too - - As this function is called when the SFTP session is closed, it needs to - also kill all zombies left in the SFTP session to avoid leaking memory - just in case some zombie would still be in there. - -- sftp_packetlist_flush: zombies must not have responses already - - When flushing the packetlist, we must only add the request as a zombie - if no response has already been received. Otherwise we could wrongly - make it a zombie even though the response was already received and then - we'd get a zombie stuck there "forever"... - -- sftp_read: on EOF remove packet before flush - - Since the sftp_packetlist_flush() function will move all the existing - FXP_READ requests in this handle to the zombie list we must first remove - this just received packet as it is clearly not a zombie. - -- sftp_packet_require: sftp_packet_read() returning 0 is not an error - - Exactly as the comment in the code said, checking the return code from - sftp_packet_read() with <= was wrong and it should be < 0. With the new - filtering on incoming packets that are "zombies" we can now see this - getting zero returned. - -- sftp_packetlist_flush: only make it zombie if it was sent - - The list of outgoing packets may also contain packets that never were - sent off and we better not make them zombies too. - -- [Alexander Lamaison brought this change] - - Mark outstanding read requests after EOF as zombies. - - In order to be fast, sftp_read sends many read requests at once. With a small - file, this can mean that when EOF is received back, many of these requests are - still outstanding. Responses arriving after we close the file and abandon the - file handle are queued in the SFTP packet queue and never collected. This - causes transfer speed to drop as a progressively longer queue must be searched - for every packet. - - This change introduces a zombie request-ID list in the SFTP session that is - used to recognise these outstanding requests and prevent them being added to - the queue. - -Peter Stuge (23 Apr 2012) -- [Rafael Kitover brought this change] - - Update win32/GNUmakefile to use OpenSSL 1.0.1a - - libcrypto on win32 now depends on gdi32.dll, so move the OpenSSL LDLIBS - block to before the compiler definitions, so that libcrypto gets added - first, and then add -lgdi32 into the following common LDLIBS for gcc. - -Guenter Knauf (23 Apr 2012) -- Changed 'Requires' to 'Requires.private'. - - Only static builds need to link against the crypto libs. - -- Fixed 'Requires:' names. - - The 'Requires:' line lists the names of the .pc files. - -- Added 'Requires:' line to libssh2.pc. - - This is necessary so that other libs which lookup libssh2 info - via pkg-config can add the right crypto lib dependencies. - -- Updated dependency lib versions. - -Peter Stuge (18 Apr 2012) -- configure.ac: Add option to disable build of the example applications - - Examples are built by default. Any of the following options on the - configure command line will skip building them: - - --disable-examples-build - --enable-examples-build=no - --enable-examples-build=false - -- userauth.c: fread() from public key file to correctly detect any errors - - If the filename parameter for file_read_publickey() was the name of a - directory instead of a file then libssh2 would spin trying to fgetc() - from the FILE * for the opened directory when trying to determine the - length of the encoded public key, since fgetc() can't report errors. - - Use fread() instead to correctly detect this error condition along - with many others. - - This fixes the problem reported in - http://www.libssh2.org/mail/libssh2-devel-archive-2012-04/0021.shtml - - Reported-by: Oleksiy Zagorskyi - -- Return LIBSSH2_ERROR_SOCKET_DISCONNECT on EOF when reading banner - -Guenter Knauf (17 Apr 2012) -- Fixed copyright year. - -- Updated dependency lib versions in static makefiles. - -Daniel Stenberg (6 Apr 2012) -- version: bump to 1.4.2 - - We're on the 1.4.2 track now (at least) - -Version 1.4.1 (4 Apr 2012) - -Daniel Stenberg (4 Apr 2012) -- RELEASE-NOTES: updated for 1.4.1 release - -- always do "forced" window updates - - When calling _libssh2_channel_receive_window_adjust() internally, we now - always use the 'force' option to prevent libssh2 to avoid sending the - update if the update isn't big enough. - - It isn't fully analyzed but we have seen corner cases which made a - necessary window update not get send due to this and then the other side - doesn't send data our side then sits waiting for forever. - -- channel_read: force window adjusts! - - if there's not enough room to receive the data that's being requested, - the window adjustment needs to be sent to the remote and thus the force - option has to be used. _libssh2_channel_receive_window_adjust() would - otherwise "queue" small window adjustments for a later packet but that - is really terribly for the small buffer read that for example is the - final little piece of a very large file as then there is no logical next - packet! - - Reported by: Armen Babakhanian - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2012-03/0130.shtml - -- [Paul Howarth brought this change] - - aes: the init function fails when OpenSSL has AES support - - The internal init function only worked fine when the configure script - didn't detect the OpenSSL AES_CTR function! - - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2012-03/0111.shtml - Reported by: Paul Howarth - -- [Matthew Booth brought this change] - - transport_send: Finish in-progress key exchange before sending data - - _libssh2_channel_write() first reads outstanding packets before writing - new data. If it reads a key exchange request, it will immediately start - key re-exchange, which will require sending a response. If the output - socket is full, this will result in a return from - _libssh2_transport_read() of LIBSSH2_ERROR_EAGAIN. In order not to block - a write because there is no data to read, this error is explicitly - ignored and the code continues marshalling a packet for sending. When it - is sent, the remote end immediately drops the connection because it was - expecting a continuation of the key exchange, but got a data packet. - - This change adds the same check for key exchange to - _libssh2_transport_send() that is in _libssh2_transport_read(). This - ensures that key exchange is completed before any data packet is sent. - -- channel_write: acknowledge transport errors - - When draining data off the socket with _libssh2_transport_read() (which - in turn has to be done so that we can be sure to have read any possible - window-increasing packets), this code previously ignored errors which - could lead to nasty loops. Now all error codes except EAGAIN will cause - the error to be returned at once. - - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2012-03/0068.shtml - Reported by: Matthew Booth - -- [Steven Dake brought this change] - - In examples/x11.c, Make sure sizeof passed to read operation is correct - - sizeof(buf) expands to 8 or 4 (since its a pointer). This variable may - have been static in the past, leading to this error. - - Signed-off-by: Steven Dake - -- [Steven Dake brought this change] - - Fix suspicious sizeof usage in examples/x11.c - - In the x11 example, sizeof(buf) = 8UL (on x86_64), when this should - probably represent the buffer size available. I am not sure how to - test that this change is actually correct, however. - - Signed-off-by: Steven Dake - -- sftp_packet_read: follow-up fix for EAGAIN/window adjust - - The commit in 7194a9bd7ba45 wasn't complete. This change makes sure - variables are initialized properly before used in the EAGAIN and window - adjust cases. - -- sftp_packet_add: use named error code instead of number - -- sftp_packet_add: verify the packet before accepting it - - In order to bail out as quickly as possible when things are wrong and - out of sync, make sure the SFTP message is one we understand. - -- SFTP: preserve the original error code more - - Lots of places in the code translated the original error into the more - generic LIBSSH2_ERROR_SOCKET_TIMEOUT but this turns out to distort the - original error reason a lot and makes tracking down the real origin of a - problem really hard. This change makes the original error code be - preserved to a larger extent when return up to the parent function. - -- sftp_packet_read: adjust window size as necessary - - Commit 03ca9020756 tried to simplify the window sizing logic but broke - SFTP readdir as there was no window sizing code left there so large - directory listings no longer worked. - - This change introduces window sizing logic to the sftp_packet_read() - function so that it now tells the remote about the local size having a - window size that suffice when it is about to ask for directory data. - - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2012-03/0069.shtml - Reported by: Eric - -- [Steven Dake brought this change] - - Tell C compiler we don't care about return code of libssh2_init - - The call of libssh2_init returns a return code, but nothing could be done - within the _libssh2_init_if_needed execution path. - - Signed-off-by: Steven Dake - -- [Steven Dake brought this change] - - Add comment indicating a resource leak is not really a resource leak - - While possibly obvious to those investigating the code, coverity complains - about this out of scope leak. - - Signed-off-by: Steven Dake - -- [Steven Dake brought this change] - - Use safer snprintf rather then sprintf in scp_send() - - Signed-off-by: Steven Dake - -- [Steven Dake brought this change] - - Use safer snprintf rather then sprintf in scp_recv() - - While the buffer is indeed allocated to a safe length, better safe then sorry. - - Signed-off-by: Steven Dake - -- [Steven Dake brought this change] - - use snprintf in knownhost_writeline() rather then sprintf - - Although the function checks the length, if the code was in error, there - could potentially be a buffer overrun with the use of sprintf. Instead replace - with snprintf. - - Signed-off-by: Steven Dake - -- [Steven Dake brought this change] - - Add tracing to print packets left on session at libssh2_session_free - - Signed-off-by: Steven Dake - -Peter Stuge (2 Mar 2012) -- Define and use LIBSSH2_INVALID_SOCKET instead of INVALID_SOCKET - - INVALID_SOCKET is a special value in Windows representing a - non-valid socket identifier. We were #defining this to -1 on - non-Windows platforms, causing unneccessary namespace pollution. - Let's have our own identifier instead. - - Thanks to Matt Lawson for pointing this out. - -- nw/Makefile.netware: Fix project name typo to avoid needless confusion - -- example/x11: Set raw terminal mode manually instead of with cfmakeraw() - - OpenSolaris has no cfmakeraw() so to make the example more portable - we simply do the equivalent operations on struct termios ourselves. - - Thanks to Tom Weber for reporting this problem, and finding a solution. - -Daniel Stenberg (17 Feb 2012) -- sftp_write: cannot return acked data *and* EAGAIN - - Whenever we have acked data and is about to call a function that *MAY* - return EAGAIN we must return the number now and wait to get called - again. Our API only allows data *or* EAGAIN and we must never try to get - both. - -Peter Stuge (13 Feb 2012) -- example/x11: Build only when sys/un.h is found by configure - - The example can't be built on systems without AF_UNIX sockets. - -Daniel Stenberg (10 Feb 2012) -- [Alexander Lamaison brought this change] - - Simplified sftp_read. - - Removed the total_read variable that originally must have tracked how - much data had been written to the buffer. With non-blocking reads, we - must return straight away once we have read data into the buffer so this - variable served not purpose. - - I think it was still hanging around in case the initial processing of - 'leftover' data meant we wrote to the buffer but this case, like the - others, must return immediately. Now that it does, the last remaining - need for the variable is gone. - -- [Alexander Lamaison brought this change] - - Cleaned up sftp_read and added more explanation. - - Replaced the gotos which were implementing the state machine with - a switch statement which makes the states more explicit. - -- sftp_read: avoid data *and* EAGAIN - - Whenever we have data and is about to call a function that *MAY* return - EAGAIN we must return the data now and wait to get called again. Our API - only allows data *or* EAGAIN and we must never try to get both. - -Peter Stuge (2 Feb 2012) -- Add a tcpip-forward example which demonstrates remote port forwarding - -- libssh2.h: Add missing prototype for libssh2_session_banner_set() - -- example/subsystem_netconf.c: Return error when read buffer is too small - - Also remove a little redundancy in the read loop condition. - -- example/subsystem_netconf.c: Add a missing newline in an error message - -- Fix undefined reference to _libssh_error in libgcrypt backend - - Commit 209de22299b4b58e582891dfba70f57e1e0492db introduced a function - call to a non-existing function, and since then the libgcrypt backend - has not been buildable. - -Version 1.4.0 (31 Jan 2012) - -Daniel Stenberg (31 Jan 2012) -- RELEASE-NOTES: synced with 6bd584d29 for 1.4.0 - -- s/1.3.1/1.4.0 - - We're bumping the minor number - -- [Jernej Kovacic brought this change] - - libssh2_session_supported_algs: fix compiler warning - -- [Jernej Kovacic brought this change] - - session_supported_algs docs: added an example - -- [Gellule Xg brought this change] - - sftp-seek: clear EOF flag - - Set the EOF flag to False when calling seek64 to be able to get some - data back on a following read - -- [Peter Krempa brought this change] - - userauth: Provide more informations if ssh pub key extraction fails - - If the function that extracts/computes the public key from a private key - fails the errors it reports were masked by the function calling it. This - patch modifies the key extraction function to return errors using - _libssh_error() function. The error messages are tweaked to contain - reference to the failed operaton in addition to the reason. - - * AUTHORS: - add my name - * libgcrypt.c: _libssh2_pub_priv_keyfile(): - return a more verbose - error using - _libssh2_error() func. - * openssl.c: - modify call graph of _libssh2_pub_priv_keyfile() to use - _libssh2_error for error reporting(); - * userauth.c: - tweak functions calling _libssh2_pub_priv_keyfile() not - to shadow error messages - -- TODO: remove issues we (sort of) did already - -- ssh2_exec: skip error outputs for EAGAIN - - Since the example uses non-blocking mode, it will just flood the output - with this "nonsense" error. - -Guenter Knauf (30 Nov 2011) -- Some NetWare makefile tweaks. - -Daniel Stenberg (18 Nov 2011) -- LIBSSH2_SFTP_PACKET_MAXLEN: increase to 80000 - - Some SFTP servers send SFTP packets larger than 40000. Since the limit - is only present to avoid insane sizes anyway, we can easily bump it. - - The define was formerly in the public header libssh2_sftp.h but served - no external purpose and was moved into the source dir. - - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2011-11/0004.shtml - Reported by: Michael Harris - -Alexander Lamaison (18 Nov 2011) -- [Peter Krempa brought this change] - - knownhost_check(): Don't dereference ext if NULL is passed - - Documentation for libssh2_knownhost_checkp() and related functions - states that the last argument is filled with data if non-NULL. - - "knownhost if set to non-NULL, it must be a pointer to a 'struct - libssh2_knownhost' pointer that gets filled in to point to info about a - known host that matches or partially matches." - - In this function ext is dereferenced even if set to NULL, causing - segfault in applications not needing the extra data. - -Daniel Stenberg (11 Nov 2011) -- [Peter Krempa brought this change] - - knownhost_add: Avoid dereferencing uninitialized memory on error path. - - In function knownhost_add, memory is alocated for a new entry. If normal - alocation is used, memory is not initialized to 0 right after, but a - check is done to verify if correct key type is passed. This test is done - BEFORE setting the memory to null, and on the error path function - free_host() is called, that tries to dereference unititialized memory, - resulting into a glibc abort(). - - * knownhost.c - knownhost_add(): - move typemask check before alloc - -- windows build: add define to avoid compiler warning - - A recent mingw compiler has started to complain on "#warning Please - include winsock2.h before windows.h" unless the magic define is set - first. - - Reported by: Vincent Torri - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2011-10/0064.shtml - -Henrik Nordstrom (31 Oct 2011) -- [Vincent Torri brought this change] - - Correct Windows include file name case, simplifying cross-compilation - - When cross compiling to Windows, libssh2.h include Windows header files - with upper case filenames : BaseTsd.h and WinSock2.h. - - These files have lowercase names with mingw-w64 (iirc, it's the same with - mingw). And as on Windows, being lowercase or uppercase does not matter. - -Daniel Stenberg (25 Oct 2011) -- [Jernej Kovacic brought this change] - - libssh2_session_supported_algs: added - -- [Kamil Dudka brought this change] - - example/sftp_RW_nonblock: do not ignore LIBSSH2_ERROR_EAGAIN - - Bug: https://bugzilla.redhat.com/745420 - -Peter Stuge (5 Oct 2011) -- example/ssh2_agent: Print host key fingerprint before authentication - - Also moves the comment about not being authenticated to before the - agent authentication takes place, so that it better matches the code. - -Daniel Stenberg (29 Sep 2011) -- OpenSSL EVP: fix threaded use of structs - - Make sure we don't clear or reset static structs after first init so - that they work fine even when used from multiple threads. Init the - structs in the global init. - - Help and assistance by: John Engstrom - - Fixes #229 (again) - -- openssl: don't init static structs differently - - make_ctr_evp() is changed to take a struct pointer, and then each - _libssh2_EVP_aes_[keylen]_ctr function is made to pass in their own - static struct - - Reported by: John Engstrom - Fixes #229 - -Guenter Knauf (27 Sep 2011) -- Removed obsolete include path. - -Daniel Stenberg (21 Sep 2011) -- read_state: clear the state variable better - - Set read_state back to idle before trying to send anything so that if - the state somehow is wrongly set. - - Also, avoid such a case of confusion by resetting the read_state when an - sftp handle is closed. - -- sftp_read: remove leftover fprintf - - Reported by: Alexander Lamaison - -- sftp.h: fix the #ifdef to prevent multiple inclusions - -- sftp_read: use a state variable to avoid bad writes - - When a channel_write call has gotten an EAGAIN back, we try harder to - continue the same write in the subsequent invoke. - -- window_size: explicit adjustments only - - Removed the automatic window_size adjustments from - _libssh2_channel_read() and instead all channel readers must now make - sure to enlarge the window sizes properly themselves. - - libssh2_channel_read_ex() - the public function, now grows the window - size according to the requested buffer size. Applications can still opt - to grow the window more on demand. Larger windows tend to give higher - performance. - - sftp_read() now uses the read-ahead logic to figure out a window_size. - -- libssh2.h: bump the default window size to 256K - -- libssh2_userauth_keyboard_interactive.3: fix man warning - - It seemed to occur due to the excessive line length - -- [Mikhail Gusarov brought this change] - - Add missing .gitignore entries - -- [Mikhail Gusarov brought this change] - - Add manpage syntax checker to 'check' target - - In virtually every libssh2 release Debian's lintian catches syntax errors in - manpages. Prevent it by checking manpages as a part of testsuite. - -- libssh2_banner_set.3: fix nroff syntax mistake - -Guenter Knauf (10 Sep 2011) -- Use predefined resource compiler macro. - -- Added casts to silent compiler warnings. - -- Fixed uint64_t printf. - -- Fixed macro function signatures. - -- NetWare makefile tweaks. - -- Removed unused var. - -- Added 2 samples not mentioned. - -- Dont build x11 sample with MinGW. - -- Fixed executable file description. - -- Removed unused var. - -- Kill stupid gcc 3.x uninitialized warning. - -- Build all examples. - -- More MinGW makefile tweaks. - - Renamed *.mingw makefiles to GNUmakefile since GNU make picks these - up automatically, and therefore win32/Makefile removed. - -- Removed forgotten WINSOCK_VERSION defines. - -Daniel Stenberg (9 Sep 2011) -- libssh2_session_startup(3) => libssh2_session_handshake(3) - - Propagate for the current function in docs and examples. - libssh2_session_startup() is deprecated. - -- libssh2_banner_set => libssh2_session_banner_get - - Marked the old function as deprecated. Added the new name in the correct - name space with the same arguments and functionality. - -- new function: libssh2_session_banner_get - - Returns the banner from the server handshake - - Fixes #226 - -- libssh2.h: bump version to 1.4.0 for new function(s) - -- remove embedded CVS/svn tags - -- [liuzl brought this change] - - API add:libssh2_sftp_get_channel - - Return the channel of sftp, then caller can - control the channel's behavior. - - Signed-off-by: liuzl - -- _libssh2_channel_read: react on errors from receive_window_adjust - - Previously the function would ignore all errors except for EAGAIN. - -- sftp_read: extend and clarify the documentation - -- sftp_read: cap the read ahead maximum amount - - Now we only go up to LIBSSH2_CHANNEL_WINDOW_DEFAULT*30 bytes SFTP read - ahead, which currently equals 64K*30 == 1966080 bytes. - -- _libssh2_channel_read: fix non-blocking window adjusting - - If EAGAIN is returned when adjusting the receive window, we must not - read from the transport directly until we've finished the adjusting. - -Guenter Knauf (8 Sep 2011) -- Fix for systems which need sys/select.h. - -- The files were not gone but renamed ... - -Daniel Stenberg (6 Sep 2011) -- sftp_read: added documenting comment - - Taken from some recent email conversations I added some descriptions of - the logic in sftp_read() to aid readers. - -- 1.3.1: start the work - -Version 1.3.0 (6 Sep 2011) - -Daniel Stenberg (6 Sep 2011) -- Makefile.am: the Makefile.win32 files are gone - -- RELEASE-NOTES: updated for 1.3.0 - -- sftp_read: a short read is not end of file - - A returned READ packet that is short will now only reduce the - offset. - - This is a temporary fix as it is slightly better than the previous - approach but still not very good. - -- [liuzl brought this change] - - _libssh2_packet_add: adjust window size when truncating - - When receiving more data than what the window size allows on a - particular channel, make sure that the window size is adjusted in that - case too. Previously it would only adjust the window in the non-error - case. - -Guenter Knauf (29 Aug 2011) -- Silent compiler warning with MinGW64. - -- Fixed link to native Win32 awk tool. - -- Renamed MinGW makefiles. - -- Some MinGW makefile tweaks. - - Enable build without GNU tools and with MinGW64 compiler. - -- Fixed aes_ctr_do_cipher() signature. - -Daniel Stenberg (26 Aug 2011) -- [liuzl brought this change] - - libssh2_sftp_seek64: flush packetlist and buffered data - - When seeking to a new position, flush the packetlist and buffered data - to prevent already received or pending data to wrongly get used when - sftp-reading from the new offset within the file. - -- sftp_read: advance offset correctly for buffered copies - - In the case where a read packet has been received from the server, but - the entire contents couldn't be copied to the user-buffer, the data is - instead buffered and copied to the user's buffer in the next invocation - of sftp_read(). When that "extra" copy is made, the 'offset' pointer was - not advanced accordingly. - - The biggest impact of this flaw was that the 'already' variable at the - top of the function that figures out how much data "ahead" that has - already been asked for would slowly go more and more out of sync, which - could lead to the file not being read all the way to the end. - - This problem was most noticable in cases where the application would - only try to read the exact file size amount, like curl does. In the - examples libssh2 provides the sftp read function is most often called - with a fixed size large buffer and then the bug would not appear as - easily. - - This bug was introduced in the SFTP rewrite in 1.2.8. - - Bug: http://curl.haxx.se/mail/lib-2011-08/0305.html - http://www.libssh2.org/mail/libssh2-devel-archive-2011-08/0085.shtml - -- wrap some long lines < 80 columns - -- LIBSSH2_RECV: fix typo, use the RECV_FD macro - -- subsystem_netconf.c: fix compiler warnings - -- [Henrik Nordstrom brought this change] - - Custom callbacks for performing low level socket I/O - -- version bump: start working towards 1.3.0 - -Version 1.2.9 (16 Aug 2011) - -Daniel Stenberg (16 Aug 2011) -- RELEASE-NOTES: synced with 95d69d3a81261 - -- [Henrik Nordstrom brought this change] - - Document prototypes for macro defined functions - -- [Henrik Nordstrom brought this change] - - Avoid reuse after free when closing X11 channels - -- _libssh2_channel_write: handle window_size == 0 better - - When about to send data on the channel and the window size is 0, we must - not just return 0 if the transport_read() function returned EAGAIN as it - then causes a busy-loop. - - Bug: http://libssh2.org/mail/libssh2-devel-archive-2011-08/0011.shtml - -- gettimeofday: fix name space pollution - - For systems without its own gettimeofday() implementation, we still must - not provide one outside our namespace. - - Reported by: Bill Segall - -Dan Fandrich (5 Aug 2011) -- libssh2.pc.in: Fixed spelling in pkgconfig file - -Peter Stuge (17 Jul 2011) -- example/subsystem_netconf.c: Add missing #include - -- example/subsystem_netconf.c: Discard ]]>]]> and return only XML response - -- example/subsystem_netconf.c: Fix uninitialized variable bug - -- example: Add subsystem_netconf.c - - This example demonstrates how to use libssh2 to send a request to - the NETCONF subsystem available e.g. in JunOS. - - See also http://tools.ietf.org/html/draft-ietf-netconf-ssh-06 - -Daniel Stenberg (16 Jul 2011) -- man page cleanups: non-existing functions need no man pages - -- libssh2_new_host_entry.3: removed - - This is just junk leftovers. - -- userauth_keyboard_interactive: fix buffer overflow - - Partly reverse 566894494b4972ae12 which was simplifying the code far too - much and ended up overflowing a buffer within the LIBSSH2_SESSION - struct. Back to allocating the buffer properly like it used to do. - - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2011-06/0032.shtml - Reported by: Alfred Gebert - -- keyboard-interactive man page: cleaned up - -- [Alfred Gebert brought this change] - - _libssh2_recv(): handle ENOENT error as EAGAIN - - A sftp session failed with error "failure establishing ssh session" on - Solaris and HP-UX. Sometimes the first recv() function call sets errno - to ENOENT. In the man pages for recv of Solaris and HP-UX the error - ENOENT is not documented. - - I tested Solaris SPARC and x86, HP-UX i64, AIX, Windows and Linux. - -- agent_list_identities: fix out of scope access - - An auto variable out of scope was being referenced and used. - - fixes #220 - -- _libssh2_wait_socket: fix timeouts for poll() uses - -- windows: inclusion fix - - include winsock2.h for all windows compilers - -- keyb-interactive: add the fixed buffer - - Belongs to commit 5668944 - -- code cleanup: don't use C99/c++ comments - - We aim for C89 compliance - -- keyb-interactive: allow zero length fields - - Allow zero length fields so they don't cause malloc(0) calls - - Avoid free()ing NULL pointers - - Avoid a malloc of a fixed 5 byte buffer. - -- libssh2_channel_process_startup.3: clean up - - Remove the references to the macro-fied shortcuts as they have their own - individual man pages. - - Made the prototype different and more readable. - -- man page: fix .BR lines - - We don't use \fI etc on .BR lines - -- userauth_keyboard_interactive: skip code on zero length auth - -- libssh2_channel_forward_accept.3: mention how to get error - - Since this returns a pointer, libssh2_session_last_errno() must be used - to get the actual error code and it wasn't that clear before. - -- timeout docs: mention they're added in 1.2.9 - -- sftp_write_sliding.c: indent fix - - Use the standard indenting and removed CVS leftover comment - -- [zl liu brought this change] - - sftp_write_sliding: send the complete file - - When reaching the end of file there can still be data left not sent. - -- [Douglas Masterson brought this change] - - session_startup: init state properly - - libssh2_session_startup() didn't set the state correctly so it could get - confused. - - Fixes #218 - -- timeout: added man pages - -- BLOCK_ADJUST_ERRNO: move rc to right level - - We can't declare the variable within the block and use it in the final - do-while() expression to be properly portable C89. - -- [Matt Lilley brought this change] - - adds a timeout to blocking calls - - Fixes bug #160 as per Daniel's suggestion - - Adds libssh2_session_set_timeout() and libssh2_session_get_timeout() - -- SCP: fix incorrect error code - - After an error occurs in libssh2_scp_recv() or libssh2_scp_send(), the - function libssh2_session_last_error() would return - LIBSSH2_ERROR_SOCKET_NONE on error. - - Bug: http://trac.libssh2.org/ticket/216 - Patch by: "littlesavage" - - Fixes #216 - -Guenter Knauf (19 Apr 2011) -- Updated default (recommended) dependency versions. - -Daniel Stenberg (17 Apr 2011) -- libssh2_session_block_directions: fix mistake - - The last LIBSSH2_SESSION_BLOCK_INBOUND should be - LIBSSH2_SESSION_BLOCK_OUTBOUND - - And I shortened the short description - - Reported by: "drswinghead" - -- msvcproj: added libs and debug stuff - - Added libraries needed to link whether using openssl dynamically or - statically - - Added LIBSSH2DEBUG define to debug versions to enable tracing - - URL: http://trac.libssh2.org/ticket/215 - Patch by: Mark Smith - -- sftp_write: clean offsets on error - - When an error has occurred on FXP_WRITE, we must make sure that the - offset, sent offset and acked counter are reset properly. - -- example/.gitignore: ignore built binaries - -- sftp_write: flush the packetlist on error - - When an error occurs during write, flush the entire list of pending - outgoing SFTP packets. - -- keepalive: add first basic man pages - - Someone on IRC pointed out that we don't have these documented so I - wrote up a first set based on the information in the wiki: - http://trac.libssh2.org/wiki/KeepAlive - -- scp_write_nonblock.c: remove pointless check - - libssh2_channel_write() cannot return a value that is larger than the - input length value - -Mikhail Gusarov (9 Apr 2011) -- s/\.NF/.nf/ to fix wrong macro name caught by man --warnings - -Daniel Stenberg (6 Apr 2011) -- version: bump to 1.2.9_dev - - Also update the copyright year range to include 2011 - -- configure: fix $VERSION - - Stop using the $VERSION variable as it seems to be magically used by - autoconfig itself and thus gets set to the value set in AC_INIT() - without us wanting that. $LIBSSH2VER is now the libssh2 version as - detected. - - Reported by: Paul Howarth - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2011-04/0008.shtml - -- maketgz: use git2news.pl by the correct name - -Version 1.2.8 (4 Apr 2011) - -Daniel Stenberg (4 Apr 2011) -- RELEASE-NOTES: synced with fabf1a45ee - -- NEWS: auto-generated from git - - Starting now, the NEWS file is generated from git using the git2news.pl - script. This makes it always accurate and up-to-date, even for daily - snapshots etc. - -- sftp_write: handle FXP_WRITE errors - - When an sftp server returns an error back on write, make sure the - function bails out and returns the proper error. - -- configure: stop using the deprecated AM_INIT_AUTOMAKE syntax - -Alexander Lamaison (13 Mar 2011) -- Support unlimited number of host names in a single line of the known_hosts file. - - Previously the code assumed either a single host name or a hostname,ip-address pair. However, according to the spec [1], there can be any number of comma separated host names or IP addresses. - - [1] http://www.openbsd.org/cgi-bin/man.cgi?query=sshd&sektion=8 - -Daniel Stenberg (26 Feb 2011) -- libssh2_knownhost_readfile.3: clarify return value - - This function returns the number of parsed hosts on success, not just - zero as previously documented. - -Peter Stuge (26 Feb 2011) -- Don't save allocated packet size until it has actually been allocated - - The allocated packet size is internal state which needs to match reality - in order to avoid problems. This commit fixes #211. - -Daniel Stenberg (21 Feb 2011) -- [Alfred Gebert brought this change] - - session_startup: manage server data before server identification - - Fix the bug that libssh2 could not connect if the sftp server - sends data before sending the version string. - - http://tools.ietf.org/html/rfc4253#section-4.2 - - "The server MAY send other lines of data before sending the version - string. Each line SHOULD be terminated by a Carriage Return and Line - Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded - in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients - MUST be able to process such lines." - -- [Alfred Gebert brought this change] - - fullpacket: decompression only after init - - The buffer for the decompression (remote.comp_abstract) is initialised - in time when it is needed. With this fix decompression is disabled when - the buffer (remote.comp_abstract) is not initialised. - - Bug: http://trac.libssh2.org/ticket/200 - -- _libssh2_channel_read: store last error - - When the transport layer returns EAGAIN this function didn't call - _libssh2_error() which made the last_error not get set. - -- sftp_write: clarified the comment header - -- sftp_read: avoid wrapping counter to insanity - - As pointed out in bug #206, if a second invoke of libssh2_sftp_read() - would shrink the buffer size, libssh2 would go nuts and send out read - requests like crazy. This was due to an unsigned variable turning - "negative" by some wrong math, and that value would be the amount of - data attempt to pre-buffer! - - Bug: http://trac.libssh2.org/ticket/206 - -- sftp_packet_read: use 32bit variables for 32bit data - -- libssh2_sftp_stat_ex.3: cleaned up, extended - - Removed the macros from it as they have their own man pages. - - Added the LIBSSH2_SFTP_ATTRIBUTES struct in here for easier reference. - -- sftp_readdir: return error if buffer is too small - - If asked to read data into a buffer and the buffer is too small to hold - the data, this function now returns an error instead of as previously - just copy as much as fits. - -- sftp_symlink: return error if receive buffer too small - - and clean up some variable type mismatches - - Discussion: http://www.libssh2.org/mail/libssh2-devel-archive-2011-01/0001.shtml - -- docs: clarify what happens with a too small buffer - - This flaw is subject to change, but I figured it might be valuable to - users of existing code to know how it works. - -- channel_request_pty_size: fix reqPTY_state - - The state variable isn't properly set so every other call to the - function fails! - - Bug: http://libssh2.org/mail/libssh2-devel-archive-2010-12/0096.shtml - Reported by: Steve Legg - -- data size: cleanup - - Fix 64bit warnings by using (s)size_t and dedicated uint32_t types more. - -- [Pierre Joye brought this change] - - ssize_t: proper typedef with MSVC compilers - - As discussed on the mailing list, it was wrong for win64 and using the - VC-provided type is the safest approach instead of second- guessing - which one it should be. - -Guenter Knauf (22 Dec 2010) -- Updated OpenSSL version. - -- Expanded tabs to spaces. - -Peter Stuge (21 Dec 2010) -- [Joey Degges brought this change] - - _libssh2_ntohu64: fix conversion from network bytes to uint64 - - Cast individual bytes to uint64 to avoid overflow in arithmetic. - -Daniel Stenberg (20 Dec 2010) -- libssh2_userauth_list: language fix - - "faily" is not a good English word, and I also cleaned up some other minor - mistakes - -- crypto: unify the generic functions - - Added crypto.h that is the unified header to include when using crypto - functionality. It should be the only header that needs to adapt to the - underlying crypto library in use. It provides the set of prototypes that - are library agnostic. - -- [Mark Smith brought this change] - - userauth: derive publickey from private - - Pass a NULL pointer for the publickey parameter of - libssh2_userauth_publickey_fromfile and - libssh2_userauth_hostbased_fromfile functions. In this case, the - functions recompute the public key from the private key file data. - - This is work done by Jean-Louis CHARTON - , then adapted by Mark Smith and - slightly edited further by me Daniel. - - WARNING: this does leave the feature NOT WORKING when libssh2 is built - to use libgcrypt instead of OpenSSL simply due to lack of - implementation. - -- ssh2_echo: Value stored to 'exitcode' is never read - -- _libssh2_packet_add: fix SSH_MSG_DEBUG weirdness - - I believe I may have caused this weird typo style error when I cleaned - up this function a while ago. Corrected now. - -- uint32: more longs converted to proper types - - I also moved the MAC struct over to the mac.h header file and made sure - that the users of that struct include that file. - -- SFTP: more types to uint32_t - - The 'num_names' field in the SSH_FXP_NAME response is an unsigned 32bit - value so we make sure to treat it like that. - -- SFTP: request_ids are uint32_t - - I went over the code and made sure we use uint32_t all over for the - request_id data. It is an unsigned 32bit value on the wire. - -- SFTP: store request_id separately in packets - - By using a new separate struct for incoming SFTP packets and not sharing - the generic packet struct, we can get rid of an unused field and add a - new one dedicated for holding the request_id for the incoming - package. As sftp_packet_ask() is called fairly often, a "mere" integer - comparison is MUCH faster than the previous memcmp() of (typically) 5 - bytes. - -- libssh2_sftp_open_ex: man page extended and cleaned up - - I added the missing documentation for the 'flags' argument. - -- SFTP: unify the READ/WRITE chunk structs - -- SFTP: fix memory leaks - - Make sure that we cleanup remainders when the handle is closed and when - the subsystem is shutdown. - - Existing flaw: if a single handle sends packets that haven't been - replied to yet at the time when the handle is closed, those packets will - arrive later and end up in the generic packet brigade queue and they - will remain in there until flushed. They will use unnecessary memory, - make things slower and they will ruin the SFTP handling if the - request_id counter ever wraps (highly unlikely to every happen). - -- sftp_close_handle: packet list is generic - - Fix comment, simplify the loop logic - -- sftp_read: pipeline reads - - The SFTP read function now does transfers the same way the SFTP write - function was made to recently: it creates a list of many outgoing - FXP_READ packets that each asks for a small data chunk. The code then - tries to keep sending read request while collecting the acks for the - previous requests and returns the received data. - -- sftp_write: removed unused variable - -- _libssh2_channel_close: don't call transport read if disconnected - - The loop that waits for remote.close to get set may end up looping - forever since session->socket_state gets set to - LIBSSH2_SOCKET_DISCONNECTED by the packet_add() function called from the - transport_read() function and after having been set to - LIBSSH2_SOCKET_DISCONNECTED, the transport_read() function will only - return 0. - - Bug: http://trac.libssh2.org/ticket/198 - -- libssh2_sftp_seek64: new man page - - Split off libssh2_sftp_seek64 from the libssh2_sftp_seek man page, and - mentioned that we consider the latter deprecated. Also added a mention - about the dangers of doing seek during writing or reading. - -- sftp_seek: fix - - The new SFTP write code caused a regression as the seek function no - longer worked as it didn't set the write position properly. - - It should be noted that seeking is STRONGLY PROHIBITED during upload, as - the upload magic uses two different offset positions and the multiple - outstanding packets etc make them sensitive to change in the midst of - operations. - - This functionality was just verified with the new example code - sftp_append. This bug was filed as bug #202: - - Bug: http://trac.libssh2.org/ticket/202 - -- sftp_append: new example doing SFTP append - -- MAX_SFTP_OUTGOING_SIZE: 30000 - - I ran SFTP upload tests against localhost. It showed that to make the - app reach really good speeds, I needed to do a little code tweak and - change MAX_SFTP_OUTGOING_SIZE from 4000 to 30000. The tests I did before - with the high latency tests didn't show any real difference whatever I - had that size set to. - - This number is the size in bytes that libssh2 cuts off the large input - buffer and sends off as an individual sftp packet. - -- sftp_write_sliding.c: new example - - This is an example that is very similar to sftp_write_nonblock.c, with - the exception that this uses - - 1 - a larger upload buffer - - 2 - a sliding buffer mechnism to allow the app to keep sending lots of - data to libssh2 without having to first drain the buffer. - - These are two key issues to make libssh2 SFTP uploads really perform - well at this point in time. - -- cpp: s/#elsif/#elif - - This looks like a typo as #elsif is not really C... - -- _libssh2_channel_write: revert channel_write() use - - The attempts made to have _libssh2_channel_write() accept larger pieces - of data and split up the data by itself into 32700 byte chunks and pass - them on to channel_write() in a loop as a way to do faster operations on - larger data blocks was a failed attempt. - - The reason why it is difficult: - - The API only allows EAGAIN or a length to be returned. When looping over - multiple blocks to get sent, one block can get sent and the next might - not. And yet: when transport_send() has returned EAGAIN we must not call - it again with new data until it has returned OK on the existing data it - is still working on. This makes it a mess and we do get a much easier - job by simply returning the bytes or EAGAIN at once, as in the EAGAIN - case we can assume that we will be called with the same arguments again - and transport_send() will be happy. - - Unfortunately, I think we take a small performance hit by not being able - to do this. - -- ssh2_echo: new example - - This is a new example snippet. The code is largely based on ssh2_exec, - and is written by Tommy Lindgren. I edited it into C90 compliance and to - conform to libssh2 indent style and some more. - -- send_existing: return after send_existing - - When a piece of data is sent from the send_existing() function we must - make the parent function return afterwards. Otherwise we risk that the - parent function tries to send more data and ends up getting an EGAIN for - that more data and since it can only return one return code it doesn't - return info for the successfully sent data. - - As this change is a regression I now added a larger comment explaining - why it has to work like this. - -- _libssh2_channel_write: count resent data as written - - In the logic that resends data that was kept for that purpose due to a - previous EAGAIN, the data was not counted as sent causing badness. - -Peter Stuge (13 Nov 2010) -- Use fprintf(stderr, ) instead of write(2, ) for debugging - -- session/transport: Correctly handle when _libssh2_send() returns -EAGAIN - -- src/agent.c: Simplify _libssh2_send() error checking ever so slightly - -Daniel Stenberg (12 Nov 2010) -- send/recv: use _libssh2_recv and _libssh2_send now - - Starting now, we unconditionally use the internal replacement functions - for send() and recv() - creatively named _libssh2_recv() and - _libssh2_send(). - - On errors, these functions return the negative 'errno' value instead of - the traditional -1. This design allows systems that have no "natural" - errno support to not have to invent it. It also means that no code - outside of these two transfer functions should use the errno variable. - -- channel_write: move some logic to _libssh2_channel_write - - Some checks are better done in _libssh2_channel_write just once per - write instead of in channel_write() since the looping will call the - latter function multiple times per _libssh2_channel_write() invoke. - -- sftp_write: handle "left over" acked data - - The SFTP handle struct now buffers number of acked bytes that haven't - yet been returned. The way this is used is as following: - - 1. sftp_write() gets called with a buffer of let say size 32000. We - split 32000 into 8 smaller packets and send them off one by one. One of - them gets acked before the function returns so 4000 is returned. - - 2. sftp_write() gets called again a short while after the previous one, - now with a much smaller size passed in to the function. Lets say 8000. - In the mean-time, all of the remaining packets from the previous call - have been acked (7*4000 = 28000). This function then returns 8000 as all - data passed in are already sent and it can't return any more than what - it got passed in. But we have 28000 bytes acked. We now store the - remaining 20000 in the handle->u.file.acked struct field to add up in - the next call. - - 3. sftp_write() gets called again, and now there's a backlogged 20000 - bytes to return as fine and that will get skipped from the beginning - of the buffer that is passed in. - -- sftp_write: polished and simplified - - Removed unnecessary struct fields and state changes within the function. - - Made the loop that checks for ACKs only check chunks that were fully - sent. - -- SCP: on failure, show the numerical error reason - - By calling libssh2_session_last_errno() - -- SFTP: provide the numerical error reason on failure - -- SCP: clean up failure treatment - - When SCP send or recv fails, it gets a special message from the server - with a warning or error message included. We have no current API to - expose that message but the foundation is there. Removed unnecessary use - of session struct fields. - -- sftp_write: enlarge buffer to perform better - -- packets: code cleanup - - I added size checks in several places. I fixed the code flow to be easier - to read in some places. - - I removed unnecessary zeroing of structs. I removed unused struct fields. - -- LIBSSH2_CALLBACK_MACERROR: clarify return code use - -- _libssh2_userauth_publickey: avoid shadowing - -- packet: avoid shadowing global symbols - -- sftp_readdir: avoid shadowing - -- shadowing: don't shadow the global compress - -- _libssh2_packet_add: turn ifs into a single switch - -- _libssh2_packet_add: check SSH_MSG_GLOBAL_REQUEST packet - -- _libssh2_packet_add: SSH_MSG_DEBUG length checks - - Verify lengths before using them. Read always_display from the correct - index. Don't copy stuff around just to provide zero-termination of the - strings. - -- _libssh2_packet_add: SSH_MSG_IGNORE skip memmove - - There's no promise of a zero termination of the data in the callback so - no longer perform ugly operation in order to provide it. - -- _libssh2_packet_add: SSH_MSG_DISCONNECT length checks - - Verify lengths before trying to read data. - -- indent: break lines at 80 columns - -- SSH_MSG_CHANNEL_OPEN_FAILURE: used defined values - - We don't like magic numbers in the code. Now the acceptable failure - codes sent in the SSH_MSG_CHANNEL_OPEN_FAILURE message are added as - defined values in the private header file. - -- sftp_write: don't return EAGAIN if no EAGAIN was received - - This function now only returns EAGAIN if a lower layer actually returned - EAGAIN to it. If nothing was acked and no EAGAIN was received, it will - now instead return 0. - -- _libssh2_wait_socket: detect nothing-to-wait-for - - If _libssh2_wait_socket() gets called but there's no direction set to - wait for, this causes a "hang". This code now detects this situation, - set a 1 second timeout instead and outputs a debug output about it. - -- decomp: remove the free_dest argument - - Since the decompress function ALWAYS returns allocated memory we get a - lot simpler code by removing the ability to return data unallocated. - -- decomp: cleaned off old compression stuff - - I cleared off legacy code from when the compression and decompression - functions were a single unified function. Makes the code easier to read - too. - -- [TJ Saunders brought this change] - - decomp: increase decompression buffer sizes - -- [TJ Saunders brought this change] - - zlib: Add debug tracing of zlib errors - -- sftp_packet_read: handle partial reads of the length field - - SFTP packets come as [32 bit length][payload] and the code didn't - previously handle that the initial 32 bit field was read only partially - when it was read. - -- [Jasmeet Bagga brought this change] - - kex_agree_hostkey: fix NULL pointer derefence - - While setting up the session, ssh tries to determine the type of - encryption method it can use for the session. This requires looking at - the keys offered by the remote host and comparing these with the methods - supported by libssh2 (rsa & dss). To do this there is an iteration over - the array containing the methods supported by libssh2. - - If there is no agreement on the type of encryption we come to the 3rd - entry of the hostkeyp array. Here hostkeyp is valid but *hostkep is - NULL. Thus when we dereference that in (*hostkeyp)->name there is a - crash - -- _libssh2_transport_send: remove dead assignment - - 'data' isn't accessed beyond this point so there's no need to assign it. - -- scp_recv: remove dead assignment - - Instead of assigning a variable we won't read, we now use the more - explicit (void) prefix. - -- sftp_write: removed superfluous assignment - -- bugfix: avoid use of uninitialized value - -- sftp_packet_require: propagate error codes better - - There were some chances that they would cause -1 to get returned by - public functions and as we're hunting down all such occurances and since - the underlying functions do return valuable information the code now - passes back proper return codes better. - -- [Alfred Gebert brought this change] - - fix memory leaks (two times cipher_data) for each sftp session - -- libssh2_userauth_authenticated: make it work as documented - - The man page clearly says it returns 1 for "already authenticated" but - the code said non-zero. I changed the code to use 1 now, as that is also - non-zero but it gets the benefit that it now matches the documentation. - - Using 1 instead of non-zero is better for two reasons: - - 1. We have the opportunity to introduce other return codes in the future for - things like error and what not. - 2. We don't expose the internal bitmask variable value. - -- userauth_keyboard_interactive: fix indent - -- [Alfred Gebert brought this change] - - fix memory leak in userauth_keyboard_interactive() - - First I wanted to free the memory in session_free() but then - I had still memory leaks because in my test case the function - userauth_keyboard_interactive() is called twice. It is called - twice perhaps because the server has this authentication - methods available: publickey,gssapi-with-mic,keyboard-interactive - The keyboard-interactive method is successful. - -- dist: include sftp.h in dist archives - -Simon Josefsson (27 Oct 2010) -- Update header to match new function prototype, see c48840ba88. - -Daniel Stenberg (26 Oct 2010) -- bugfixes: the transport rearrange left some subtle flaws now gone - -- libssh2_userauth_publickey_fromfile_ex.3: cleaned up looks - -- libssh2_userauth_publickey: add man page - - I found an undocumented public function and we can't have it like - that. The description here is incomplete, but should serve as a template - to allow filling in... - -- libssh2_sftp_write.3: added blurb about the "write ahead" - - Documented the new SFTP write concept - -- sftp_close_handle: free any trailing write chunks - -- _libssh2_channel_write: fix warnings - -- SFTP: bufgix, move more sftp stuff to sftp.h - - The sftp_write function shouldn't assume that the buffer pointer will be - the same in subsequent calls, even if it assumes that the data already - passed in before haven't changed. - - The sftp structs are now moved to sftp.h (which I forgot to add before) - -- SFTP: use multiple outgoing packets when writing - - sftp_write was rewritten to split up outgoing data into multiple packets - and deal with the acks in a more asynchronous manner. This is meant to - help overcome latency and round-trip problems with the SFTP protocol. - -- TODO: implemented a lot of the ideas now - -- _libssh2_channel_write: removed 32500 size limit - - Neither _libssh2_channel_write nor sftp_write now have the 32500 size - limit anymore and instead the channel writing function now has its own - logic to send data in multiple calls until everything is sent. - -- send_existing: don't tell parent to return when drained - - That will just cause unnecessary code execution. - -- _libssh2_channel_write: general code cleanup - - simplified the function and removed some unused struct fields - -- _libssh2_transport_send: replaces _libssh2_transport_write - - The new function takes two data areas, combines them and sends them as a - single SSH packet. This allows several functions to allocate and copy - less data. - - I also found and fixed a mixed up use of the compression function - arguments that I introduced in my rewrite in a recent commit. - -- scp_write_nonblock: use select() instead of busyloop - - Make this example nicer by not busylooping. - -- send_existing: clear olen when the data is sent off - -- _libssh2_transport_write: allow 256 extra bytes around the packet - -- _libssh2_transport_write: remade to send without malloc - -- compress: compression disabled by default - - We now allow libssh2_session_flag() to enable compression with a new - flag and I added documentation for the previous LIBSSH2_FLAG_SIGPIPE - flag which I wasn't really aware of! - -- comp: split the compress function - - It is now made into two separate compress and decompress functions. In - preparation for upcoming further modficications. - -Dan Fandrich (20 Oct 2010) -- Added header file to allow compiling in older environments - -Daniel Stenberg (20 Oct 2010) -- TODO: add a possible new API for SFTP transfers - -- TODO: "New Transport API" added - -- TODO: add buffering plans - -Simon Josefsson (13 Oct 2010) -- Mention libssh2_channel_get_exit_signal and give kudos. - -- [Tommy Lindgren brought this change] - - Add libssh2_channel_get_exit_signal man page. - - Signed-off-by: Simon Josefsson - -- [Tommy Lindgren brought this change] - - Add libssh2_channel_get_exit_signal. - - Signed-off-by: Simon Josefsson - -- Add libssh2_free man page and fix typo. - -- Add libssh2_free. - -Daniel Stenberg (11 Oct 2010) -- scp_recv: improved treatment of channel_read() returning zero - - As a zero return code from channel_read() is not an error we must make - sure that the SCP functions deal with that properly. channel_read() - always returns 0 if the channel is EOFed already so we check for EOF - after 0-reads to be able to return error properly. - -- libssh2_session_methods.3: detail what can be asked for - -- compression: send zlib before none - - As the list of algorithms in a preferred order we should send zlib - before none to increase the chances that the server will let us do - compression. - -- compress: faster check, better return codes - - In the transport functions we avoid a strcmp() now and just check a - boolean instead. - - The compress/decompress function's return code is now acknowledged and - used as actual return code in case of failures. - -- libssh2_session_handshake: replaces libssh2_session_startup() - - The function libssh2_session_startup() is now considered deprecated due - to the portability issue with the socket argument. - libssh2_session_handshake() is the name of the replacement. - -- libssh2_socket_t: now externally visible - - In preparation for upcominig changes, the libssh2_socket_t type is now - typedef'ed in the public header. - -- _libssh2_transport_drain: removed - - This function proved not to be used nor useful. - -- _libssh2_channel_write: don't iterate over transport writes - - When a call to _libssh2_transport_write() succeeds, we must return from - _libssh2_channel_write() to allow the caller to provide the next chunk - of data. - - We cannot move on to send the next piece of data that may already have - been provided in this same function call, as we risk getting EAGAIN for - that and we can't return information both about sent data as well as - EAGAIN. So, by returning short now, the caller will call this function - again with new data to send. - -- _libssh2_transport_write: updated documentation blurb - -- _libssh2_transport_write: remove fprintf remainder - - Mistake from previous debugging - -- session: improved errors - - Replaced -1/SOCKET_NONE errors with appropriate error defines instead. - - Made the verbose trace output during banner receiving less annoying for - non-blocking sessions. - -- crypt_init: use correct error define - -- _libssh2_error: hide EAGAIN for non-blocking sessions - - In an attempt to make the trace output less cluttered for non-blocking - sessions the error function now avoids calling the debug function if the - error is the EAGAIN and the session is non-blocking. - -- agent: use better error defines - -- comp_method_zlib_init: use correct error defines - -- transport: better error codes - - LIBSSH2_SOCKET_NONE (-1) should no longer be used as error code as it is - (too) generic and we should instead use specific and dedicated error - codes to better describe the error. - -- channel: return code and _libssh2_error cleanup - - Made sure that all transport_write() call failures get _libssh2_error - called. - -- _libssh2_channel_write: limit to 32700 bytes - - The well known and used ssh server Dropbear has a maximum SSH packet - length at 32768 by default. Since the libssh2 design current have a - fixed one-to-one mapping from channel_write() to the packet size created - by transport_write() the previous limit of 32768 in the channel layer - caused the transport layer to create larger packets than 32768 at times - which Dropbear rejected forcibly (by closing the connection). - - The long term fix is of course to remove the hard relation between the - outgoing SSH packet size and what the input length argument is in the - transport_write() function call. - -- libssh.h: add more dedicated error codes - -- SCP: allow file names with bytes > 126 - - When parsing the SCP protocol and verifying that the data looks like a - valid file name, byte values over 126 must not be consider illegal since - UTF-8 file names will use such codes. - - Reported by: Uli Zappe - Bug: http://www.libssh2.org/mail/libssh2-devel-archive-2010-08/0112.shtml - -Dan Fandrich (25 Aug 2010) -- Document the three sftp stat constants - -Guenter Knauf (18 Aug 2010) -- Fixed Win32 makefile which was now broken at resource build. - -- It is sufficient to pipe stderr to NUL to get rid of the nasty messages. - -- [Author: Guenter Knauf brought this change] - - Removed Win32 ifdef completely for sys/uio.h. - - No idea why we had this ifdef at all but MSVC, MingW32, Watcom - and Borland all have no sys/uio.h header; so if there's another - Win32 compiler which needs it then it should be added explicitely - instead of this negative list. - -- New files should also be added to Makefile.am. - - Otherwise they will never be included with release and snapshot tarballs ... - -Daniel Stenberg (18 Aug 2010) -- version: bump to 1.2.8_DEV - -Version 1.2.7 (17 Aug 2010) - -Daniel Stenberg (17 Aug 2010) -- release: updated to hold 1.2.7 info - -Guenter Knauf (17 Aug 2010) -- Use the new libssh2.rc file. - -- Added resource file for libssh2.dll (shamelessly stolen from libcurl). - -- Updated Win32 MSVC dependencies versions. - -- Added include for sys/select.h to get fd.set on some platforms. - -- Added Watcom makefile borrowed from libcurl. - - This makefile compiles already all files fine for static lib, but needs - final touch when I have OpenSSL fully working with shared libs and Watcom. - -- Added copyright define to libssh2.h and use it for binary builds. - -- Moved version defines up in order to include from .rc file. - - Blocked rest of header with ifndef so its possible to let - the rc compiler only use the version defines. - -- Some minor makefile tweaks. - -Daniel Stenberg (2 Aug 2010) -- example: treat the libssh2_channel_read() return code properly - - A short read is not an error. Only negative values are errors! - -- libssh2_wait_socket: reset error code to "leak" EAGAIN less - - Since libssh2 often sets LIBSSH2_ERROR_EAGAIN internally before - _libssh2_wait_socket is called, we can decrease some amount of - confusion in user programs by resetting the error code in this function - to reduce the risk of EAGAIN being stored as error when a blocking - function returns. - -- _libssh2_wait_socket: poll needs milliseconds - - As reported on the mailing list, the code path using poll() should - multiple seconds with 1000 to get milliseconds, not divide! - - Reported by: Jan Van Boghout - -- typedef: make ssize_t get typedef without LIBSSH2_WIN32 - - The condition around the ssize_t typedef depended on both LIBSSH2_WIN32 - *and* _MSC_VER being defined when it should be enough to depend on - _MSC_VER only. It also makes it nicer so libssh2-using code builds fine - without having custom defines. - -- [John Little brought this change] - - session_free: free more data to avoid memory leaks - -- channel_free: ignore problems with channel_close() - - As was pointed out in bug #182, we must not return failure from - _libssh2_channel_free() when _libssh2_channel_close() returns an error - that isn't EAGAIN. It can effectively cause the function to never go - through, like it did now in the case where the socket was actually - closed but socket_state still said LIBSSH2_SOCKET_CONNECTED. - - I consider this fix the right thing as it now also survives other - errors, even if making sure socket_state isn't lying is also a good - idea. - -- publickey_list_free: no return value from a void function - - Fixed a compiler warning I introduced previously when checking input - arguments more. I also added a check for the other pointer to avoid NULL - pointer dereferences. - -- [Lars Nordin brought this change] - - openssl: make use of the EVP interface - - Make use of the EVP interface for the AES-funktion. Using this method - supports the use of different ENGINES in OpenSSL for the AES function - (and the direct call to the AES_encrypt should not be used according to - openssl.org) - -Peter Stuge (23 Jun 2010) -- [Tor Arntsen brought this change] - - Don't overflow MD5 server hostkey - - Use SHA_DIGEST_LENGTH and MD5_DIGEST_LENGTH in memcpy instead of hardcoded - values. An incorrect value was used for MD5. - -- Fix message length bugs in libssh2_debug() - - There was a buffer overflow waiting to happen when a debug message was - longer than 1536 bytes. - - Thanks to Daniel who spotted that there was a problem with the message - length passed to a trace handler also after commit - 0f0652a3093111fc7dac0205fdcf8d02bf16e89f. - -- Make libssh2_debug() create a correctly terminated string - - Also use FILE *stderr rather than fd 2, which can very well be something - completely different. - -Daniel Stenberg (23 Jun 2010) -- [TJ Saunders brought this change] - - handshake: Compression enabled at the wrong time - - In KEXINIT messages, the client and server agree on, among other - things, whether to use compression. This method agreement occurs - in src/kex.c's kex_agree_methods() function. However, if - compression is enabled (either client->server, server->client, or - both), then the compression layer is initialized in - kex_agree_methods() -- before NEWKEYS has been received. - - Instead, the initialization of the compression layer should - happen after NEWKEYS has been received. This looks to occur - insrc/kex.c's diffie_hellman_sha1(), which even has the comment: - - /* The first key exchange has been performed, - - switch to active crypt/comp/mac mode */ - - There, after NEWKEYS is received, the cipher and mac algorithms - are initialized, and that is where the compression should be - initialized as well. - - The current implementation fails if server->client compression is - enabled because most server implementations follow OpenSSH's - lead, where compression is initialized after NEWKEYS. Since the - server initializes compression after NEWKEYS, but libssh2 - initializes compression after KEXINIT (i.e. before NEWKEYS), they - are out of sync. - - Reported in bug report #180 - -- [TJ Saunders brought this change] - - userauth_hostbased_fromfile: packet length too short - - The packet length calculated in src/userauth.c's - userauth_hostbased_fromfile() function is too short by 4 bytes; - it forgets to add four bytes for the length of the hostname. - This causes hostbased authentication to fail, since the server - will read junk data. - - verified against proftpd's mod_sftp module - -- _libssh2_userauth_publickey: reject method names longer than the data - - This functions get the method length by looking at the first 32 - bit of data, and I now made it not accept method lengths that are - longer than the whole data set is, as given in the dedicated - function argument. - - This was detected when the function was given bogus public key - data as an ascii string, which caused the first 32bits to create - a HUGE number. - -- NULL resistance: make more public functions survive NULL pointer input - - Sending in NULL as the primary pointer is now dealt with by more - public functions. I also narrowed the userauth.c code somewhat to - stay within 80 columns better. - -- agent: make libssh2_agent_userauth() work blocking properly - - previously it would always work in a non-blocking manner - -Peter Stuge (17 Jun 2010) -- Fix underscore typo for 64-bit printf format specifiers on Windows - - Commit 49ddf447ff4bd80285f926eac0115f4e595f9425 was missing underscores. - -Daniel Stenberg (16 Jun 2010) -- libssh2_session_callback_set: extended the man page diff --git a/uppsrc/Core/SSH/libssh2/NMakefile b/uppsrc/Core/SSH/libssh2/NMakefile deleted file mode 100644 index 0c4853f1d..000000000 --- a/uppsrc/Core/SSH/libssh2/NMakefile +++ /dev/null @@ -1,30 +0,0 @@ -!include "win32/config.mk" - -!include "win32/objects.mk" - -CFLAGS=$(CFLAGS) - -AR = lib -ARFLAGS = -nologo /LTCG - -RESOURCE=$(INTDIR)\libssh2.res -DLL=libssh2$(SUFFIX).dll -STATICLIB=$(INTDIR)\libssh2.lib - -!if "$(BUILD_STATIC_LIB)" == "" -all: $(DLL) -!else -all: $(STATICLIB) -!endif - -$(DLL): $(OBJECTS) $(RESOURCE) - $(CC) -o $(DLL) $(DLLFLAGS) $(OBJECTS) $(RESOURCE) $(LIBS) - -$(STATICLIB): $(OBJECTS) - $(AR) $(ARFLAGS) -out:$@ $(OBJECTS) - -$(RESOURCE): win32\libssh2.rc - $(RC) $(RCFLAGS) /Fo"$@" $? - -!include "win32/rules.mk" - diff --git a/uppsrc/Core/SSH/libssh2/README b/uppsrc/Core/SSH/libssh2/README index 8a148568c..fca539dbb 100644 --- a/uppsrc/Core/SSH/libssh2/README +++ b/uppsrc/Core/SSH/libssh2/README @@ -4,9 +4,9 @@ libssh2 - SSH2 library libssh2 is a library implementing the SSH2 protocol, available under the revised BSD license. -Web site: https://www.libssh2.org/ +Web site: https://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/uppsrc/Core/SSH/libssh2/RELEASE-NOTES b/uppsrc/Core/SSH/libssh2/RELEASE-NOTES index 62064a9fe..d9af1689d 100644 --- a/uppsrc/Core/SSH/libssh2/RELEASE-NOTES +++ b/uppsrc/Core/SSH/libssh2/RELEASE-NOTES @@ -1,62 +1,325 @@ -libssh2 1.10 +libssh2 1.11.1 + +Deprecation notices: + +- Starting October 2024, the following algos go deprecated and will be + disabled in default builds (with an option to enable them): + + - DSA: `ssh-dss` hostkeys. + You can enable it now with `-DLIBSSH2_DSA_ENABLE`. + Disabled by default in OpenSSH 7.0 (2015-08-11). + Support to be removed by early 2025 from OpenSSH. + - MD5-based MACs and hashes: `hmac-md5`, `hmac-md5-96`, + `LIBSSH2_HOSTKEY_HASH_MD5` + You can disable it now with `-DLIBSSH2_NO_MD5`. + Disabled by default since OpenSSH 7.2 (2016-02-29). + - 3DES cipher: `3des-cbc` + You can disable it now with `-DLIBSSH2_NO_3DES`. + Disabled by default since OpenSSH 7.4 (2016-12-19). + - RIPEMD-160 MACs: `hmac-ripemd160`, `hmac-ripemd160@openssh.com` + You can disable it now with `-DLIBSSH2_NO_HMAC_RIPEMD`. + Removed in OpenSSH 7.6 (2017-10-03). + - Blowfish cipher: `blowfish-cbc` + You can disable it now with `-DLIBSSH2_NO_BLOWFISH`. + Removed in OpenSSH 7.6 (2017-10-03). + - RC4 ciphers: `arcfour`, `arcfour128` + You can disable it now with `-DLIBSSH2_NO_RC4`. + Removed in OpenSSH 7.6 (2017-10-03). + - CAST cipher: `cast128-cbc` + You can disable it now with `-DLIBSSH2_NO_CAST`. + Removed in OpenSSH 7.6 (2017-10-03). + +- Starting April 2025, above options will be deleted from the + libssh2 codebase. + + - Default builds will also disable support for old-style, MD5-based + encrypted private keys. + You can disable it now with `-DLIBSSH2_NO_MD5_PEM`. This release includes the following enhancements and bugfixes: - 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 +- autotools: fix to update `LDFLAGS` for each detected dependency (d19b6190 #1384 #1381 #1377) +- autotools: delete `--disable-tests` option, fix CI tests (e051ae34 #1271 #715 revert: 7483edfa) +- autotools: show the default for `hidden-symbols` option (a3f5594a #1269) +- autotools: enable `-Wunused-macros` with gcc (ecdf5199 #1262 #1227 #1224) +- autotools: fix dotless gcc and Apple clang version detections (89ccc83c #1232 #1187) +- autotools: show more clang/gcc version details (fb580161 #1230) +- autotools: avoid warnings in libtool stub code (96682bd5 #1227 #1224) +- autotools: sync warning enabler code with curl (5996fefe #1223) +- autotools: rename variable (ce5f208a #1222) +- autotools: picky warning options tidy-up (cdca8cff #1221) +- autotools: fix `cp` to preserve attributes and timestamp in `Makefile.am` (f64e6318) +- autotools: fix selecting WinCNG in cross-builds (and more) (00a3b88c #1187 #1186) +- autotools: use comma separator in `Requires.private` of `libssh2.pc` (7f83de14 #1124) +- autotools: remove `AB_INIT` from `configure.ac` (f4f52ccc) +- autotools: improve libz position (c89174a7 #1077 #941 #1075 #1013 regr: 4f0f4bff) +- autotools: skip tests requiring static lib if `--disable-static` (572c57c9 #1072 #663 #1056 regr: 83853f8a) +- build: stop detecting `sys/param.h` header (2677d3b0 #1418 #1415) +- build: silence warnings inside `FD_SET()`/`FD_ISSET()` macros (323a14b2 #1379) +- build: drop `-Wformat-nonliteral` warning suppressions (c452c5cc #1342) +- build: enable `-pedantic-errors` (3ec53f3e #1286) +- build: add mingw-w64 support to `LIBSSH2_PRINTF()` attribute (f8c45794 #1287) +- build: add `LIBSSH2_NO_DEPRECATED` option (b1414503 #1267 #1266 #1260 #1259) +- build: enable missing OpenSSF-recommended warnings, with fixes (afa6b865 #1257) +- build: enable more compiler warnings and fix them (7ecc309c #1224) +- build: picky warning updates (328a96b3 #1219) +- build: revert: respect autotools `DLL_EXPORT` in `libssh2.h` (481be044 #1141 #917 revert: fb1195cf) +- build: stop requiring libssl from openssl (c84745e3 #1128) +- build: tidy-up `libssh2.pc.in` variable names (5720dd9f #1125) +- build: add/fix `Requires.private` packages in `libssh2.pc` (ef538069 #1123) +- buildconf: drop (814a850c #1441 follow: fc5d7788) +- checksrc: update, check all sources, fix fallouts (1117b677 #1457) +- checksrc: sync with curl (8cd473c9 #1272) +- checksrc: fix spelling in comment (a95d401f) +- checksrc: modernise Perl file open (3d309f9b) +- checksrc: switch to dot file (d67a91aa #1052) +- ci: use Ninja with cmake (20ad047d #1458) +- ci: disable dependency tracking in autotools builds (e44f0418 #1396) +- ci: fix mbedtls runners on macOS (84411539 #1381) +- ci: enable Unity mode for most CMake builds (1bfae57b #1367 #1034) +- ci: add shellcheck job and script (d88b9bcd) +- ci: verify build and install from tarball (a86e27e8 #1362) +- ci: add reproducibility test for `maketgz` (2d765e45 #1360) +- ci: use Linux runner for BSDs, add arm64 FreeBSD 14 job (6f86b196 #1343) +- ci: do not parallelize `distcheck` job (5e65dd87 #1339) +- ci: add FreeBSD 14 job, fix issues (46333adf #1277) +- ci: add OmniOS job, fix issues (5e0ec991) +- ci: show compiler in cross/cygwin job names (c9124088) +- ci: add OpenBSD (v7.4) job + fix build error in example (0c9a8e35 #1250) +- ci: add NetBSD (v9.3) job (65c7a7a5) +- ci: update and speed up FreeBSD job (eee4e805) +- ci: use absolute path in `CMAKE_INSTALL_PREFIX` (74948816 #1247) +- ci: boost mbedTLS build speed (236e79a1 #1245) +- ci: add BoringSSL job (cmake, gcc, amd64) (c9dd3566 #1233) +- ci: fixup FreeBSD version, bump mbedTLS (fea6664e #1217) +- ci: add FreeBSD 13.2 job (a7d2a573 #1215) +- ci: mbedTLS 3.5.0 (5e190442 #1202) +- ci: update actions, use shallow clones with appveyor (d468a33f #1199) +- ci: replace `mv` + `chmod` with `install` in `Dockerfile` (5754fed6 #1175) +- ci: set file mode early in `appveyor_docker.yml` (633db55f) +- ci: add spellcheck (codespell) (a79218d3) +- ci: add MSYS builds (autotools and cmake) (d43b8d9b #1162) +- ci: add Cygwin builds (autotools and cmake) (f1e96e73 #1161) +- ci: add mingw-w64 UWP build (1215aa5f #1155 #1147) +- ci: add missing timeout to 'autotools distcheck' step (6265ffdb) +- ci: add non-static autotools i386 build, ignore GHA updates on AppVeyor (c6e137f7 #1074 #1072) +- ci: prefer `=` operator in shell snippets (e5c03043 #1073) +- ci: drop redundant/unused vars, sync var names (ab8e95bc #1059) +- ci: add i386 Linux build (with mbedTLS) (abdf40c7 #1057 #1053) +- ci/appveyor: reduce test runs (workaround for infrastructure permafails) (b5e68bdc #1461) +- ci/appveyor: increase wait for SSH server on GHA (bf3af90b) +- ci/appveyor: bump to OpenSSL 3.2.1 (53d9c1a6 #1363 #1348) +- ci/appveyor: re-enable parallel mode (e190e5b2 #1294 #884 #867) +- ci/appveyor: delete UWP job broken since Visual Studio upgrade (d0a7f1da #1275) +- ci/appveyor: YAML/PowerShell formatting, shorten variable name (06fd721f #1200) +- ci/appveyor: move to pure PowerShell (8a081fd9 #1197) +- ci/GHA: revert concurrency and improve permissions (e4c042f6) +- ci/GHA: FreeBSD 14.1, actions bump (ae04b1b9 #1424) +- ci/GHA: fix wolfSSL-from-source AES-GCM tests (1c0b07a7 #1409 #1408) +- ci/GHA: add Linux job with latest wolfSSL built from source (d4cea53f #1408 #1299 #1020) +- ci/GHA: tidy up build-from-source steps (2c633033) +- ci/GHA: show configure logs on failure and other tidy-ups (dab48398 #1403) +- ci/GHA: bump parallel jobs to nproc+1 (6f3d3bc8 #1402) +- ci/GHA: show test logs on failure (b8ffa7a5 #1401) +- ci/GHA: fix `Dockerfile` failing after Ubuntu package update (839bb84e #1400) +- ci/GHA: use ubuntu-latest with OmniOS job (50143d58) +- ci/GHA: shell syntax tidy-up (3b23e039 #1390) +- ci/GHA: bump NetBSD/OpenBSD, add NetBSD arm64 job (e980af72 #1388) +- ci/GHA: tidy up wolfSSL autotools config on macOS (5953c1f1 #1383) +- ci/GHA: shorter mbedTLS autotools workaround (736e3d7d #1382 #1381) +- ci/GHA: fix gcrypt with autotools/macOS/Homebrew/ARM64 (ae2770de #1377) +- ci/GHA: fix verbose option for autotools jobs (499b27ae #1376) +- ci/GHA: dump `config.log` on failure for macOS autotools jobs (4fa69214 #1375) +- ci/GHA: fix `autoreconf` failure on macOS/Homebrew (0b64b30b #1374) +- ci/GHA: fixup Homebrew location (for ARM runners) (6128aee0 #1373) +- ci/GHA: review/fixup auto-cancel settings (b08cfbc9 #1292) +- ci/GHA: restore curly braces in `if` (36748270 #1145) +- ci/GHA: simplify `if` strings (cab3db58 #1140) +- cmake: sync and improve Find modules, add `pkg-config` native detection (45064137 #1445 #1420) +- cmake: generate `LIBSSH2_PC_LIBS_PRIVATE` dynamically (c87f1296 #1466) +- cmake: add comment about `ibssh2.pc.in` variables (14b1b9d0) +- cmake: support absolute `CMAKE_INSTALL_INCLUDEDIR`/`CMAKE_INSTALL_LIBDIR` (d70cee36 #1465) +- cmake: rename two variables and initialize them (0fce9dcc #1464) +- cmake: prefer `find_dependency()` in `libssh2-config.cmake` (d9c2e550 #1460) +- cmake: tidy up syntax, minor improvements (9d9ee780 #1446) +- cmake: rename mbedTLS and wolfSSL Find modules (570de0f2) +- cmake: fixup version detection in mbedTLS Find module (8e3c40b2 #1444) +- cmake: mbedTLS detection tidy-ups (6d1d13c2 #1438) +- cmake: add quotes, delete ending dirseps (2bb46d44 #1437 #1166) +- cmake: sync formatting in `cmake/Find*` modules (a0310699) +- cmake: tidy up function name casing in `CopyRuntimeDependencies.cmake` (03547cb8) +- cmake: use the imported target of FindOpenSSL module (82b09f9b #1322) +- cmake: rename picky warnings script (64d6789f #1225) +- cmake: fix multiple include of libssh2 package (932d6a32 #1216) +- cmake: show crypto backend in feature summary (20387285 #1211) +- cmake: simplify showing CMake version (fc00bdd7 #1203) +- cmake: cleanup mbedTLS version detection more (4c241d5c #1196 #1192) +- cmake: delete duplicate `include()` (30eef0a6) +- cmake: improve/fix mbedTLS detection (41594675 #1192 #1191) +- cmake: tidy-up `foreach()` syntax (4a64ca14 #1180) +- cmake: verify `libssh2_VERSION` in integration tests (a20572e9) +- cmake: show cmake versions in ci (87f5769b) +- cmake: quote more strings (e9c7d3af #1173) +- cmake: add `ExternalProject` integration test (aeaefaf6 #1171) +- cmake: add integration tests (8715c3d5 #1170) +- cmake: (re-)add aliases for `add_subdirectory()` builds (4ff64ae3 #1169) +- cmake: style tidy-up (3fa5282d #1166) +- cmake: add `LIB_NAME` variable (5453fc80 #1159) +- cmake: tidy-up concatenation in `CMAKE_MODULE_PATH` (ae7d5108 #1157) +- cmake: replace `libssh2` literals with `PROJECT_NAME` variable (72fd2595 #1152) +- cmake: fix `STREQUAL` check in error branch (42d3bf13 #1151) +- cmake: cache more config values on Windows (11a03690 #1142) +- cmake: streamline invocation (f58f77b5 #1138) +- cmake: merge `set_target_properties()` calls (a9091007 #1132) +- cmake: (re-)add zlib to `Libs.private` in `libssh2.pc` (64643018 #1131) +- cmake: use `wolfssl/options.h` for detection, like autotools (c5ec6c49 #1130) +- cmake: add openssl libs to `Libs.private` in `libssh2.pc` (5cfa59d3 #1127) +- cmake: bump minimum CMake version to v3.7.0 (9cd18f45 #1126) +- cmake: CMAKE_SOURCE_DIR -> PROJECT_SOURCE_DIR (0f396aa9 #1121) +- cmake: tidy-ups (2fc36790 #1122) +- cmake: re-add `Libssh2:libssh2` for compatibility + lowercase namespace (2da13c13 #1104 #731 #1103) +- copyright: remove years from copyright headers (187d89bb #1082) +- disable DSA by default (b7ab0faa #1435 #1433) +- docs: update `INSTALL_AUTOTOOLS` (2f0efde3 #1316) +- docs: replace SHA1 with SHA256 in CMake example (766bde9f) +- example: restore `sys/time.h` for AIX (24503cb9 #1340 #1335 #1334 #1001 regr: e53aae0e) +- example: use `libssh2_socket_t` in X11 example (3f60ccb7) +- example: replace remaining libssh2_scp_recv with libssh2_scp_recv2 in output messages (8d69e63d #1258 follow: 6c84a426) +- example: fix regression in `ssh2_exec.c` (279a2e57 #1106 #861 #846 #1105 regr: b13936bd) +- example, tests: call `WSACleanup()` for each `WSAStartup()` (94b6bad3 #1283) +- example, tests: fix/silence `-Wformat-truncation=2` gcc warnings (744e059f) +- hostkey: do not advertise ssh-rsa when SHA1 is disabled (82d1b8ff #1093 #1092) +- kex: prevent possible double free of hostkey (b3465418 #1452) +- kex: always check for null pointers before calling _libssh2_bn_set_word (9f23a3bb #1423) +- kex: fix a memory leak in key exchange (19101843 #1412 #1404) +- kex: always add extension indicators to kex_algorithms (00e2a07e #1327 #1326) +- libssh2.h: add deprecated function warnings (9839ebe5 #1289 #1260) +- libssh2.h: add portable `LIBSSH2_SOCKET_CLOSE()` macro (28dbf016 #1278) +- libssh2.h: use `_WIN32` for Windows detection instead of rolling our own (631e7734 #1238) +- libssh2.pc: reference mbedcrypto pkgconfig (c149a127 #1405) +- libssh2.pc: re-add & extend support for static-only libssh2 builds (624abe27 #1119 #1114) +- libssh2.pc: don't put `@LIBS@` in pc file (1209c16d) +- mac: add empty hash functions for `mac_method_hmac_aesgcm` to not crash when e.g. setting `LIBSSH2_METHOD_CRYPT_CS` (b2738391 #1321) +- mac: handle low-level errors (f64885b6 #1297) +- Makefile.mk: delete Windows-focused raw GNU Make build (43485579 #1204) +- maketgz: reproducible tarballs/zip, display tarball hashes (d52fe1b4 #1357 #1359) +- maketgz: `set -eu`, reproducibility, improve zip, add CI test (cba7f975 #1353) +- man: improve `libssh2_userauth_publickey_from*` manpages (581b72aa #1347 #1308 #652) +- man: fix double spaces and dash escaping (a3ffc422 #1210) +- man: add description to `libssh2_session_get_blocking.3` (67e39091 #1185) +- mbedtls: always init ECDSA mbedtls_pk_context (a50d7deb #1430) +- mbedtls: correctly initialize values (ECDSA) (1701d5c0 #1428 #1421) +- mbedtls: expose `mbedtls_pk_load_file()` for our use (1628f6ca #1421 #1393 #1349 follow: e973493f) +- mbedtls: add workaround + FIXME to build with 3.6.0 (2e4c5ec4 #1349) +- mbedtls: improve disabling `-Wredundant-decls` (ecec68a2 #1226 #1224) +- mbedtls: include `version.h` for `MBEDTLS_VERSION_NUMBER` (9d7bc253 #1095 #1094) +- mbedtls: use more `size_t` to sync up with `crypto.h` (1153ebde #1054 #879 #846 #1053) +- md5: allow disabling old-style encrypted private keys at build-time (eb9f9de2 #1181) +- mingw: fix printf mask for 64-bit integers (36c1e1d1 #1091 #876 #846 #1090) +- misc: flatten `_libssh2_explicit_zero` if tree (74e74288 #1149) +- NMakefile: delete (c515eed3 #1134 #1129) +- openssl: free allocated resources when using openssl3 (b942bad1 #1459) +- openssl: fix memory leaks in `_libssh2_ecdsa_curve_name_with_octal_new` and `_libssh2_ecdsa_verify` (8d3bc19b #1449) +- openssl: fix calculating DSA public key with OpenSSL 3 (8b3c6e9d #1380) +- openssl: initialize BIGNUMs to NULL in `gen_publickey_from_dsa` for OpenSSL 3 (f1133c75 #1320) +- openssl: fix cppcheck found NULL dereferences (f2945905 #1304) +- openssl: delete internal `read_openssh_private_key_from_memory()` (34aff5ff #1306) +- openssl: use OpenSSL 3 HMAC API, add `no-deprecated` CI job (363dcbf4 #1243 #1235 #1207) +- openssl: make a function static, add `#ifdef` comments (efee9133 #1246 #248 follow: 03092292) +- openssl: fix DSA code to use OpenSSL 3 API (82581941 #1244 #1207) +- openssl: fix `EC_KEY` reference with OpenSSL 3 `no-deprecated` build (487152f4 #1236 #1235 #1207) +- openssl: use non-deprecated APIs with OpenSSL 3.x (b0ab005f #1207) +- openssl: silence `-Wunused-value` warnings (bf285500 #1205) +- openssl: use automatic initialization with LibreSSL 2.7.0+ (d79047c9 #1146 #302) +- openssl: add missing check for `LIBRESSL_VERSION_NUMBER` before use (4a42f42e #1117 #1115) +- os400: drop vsprintf() use (40e817ff #1462 #1457) +- os400: Add two recent files to the distribution (e4c65e5b #1364) +- os400: fix shellcheck warnings in scripts (fixups) (81341e1e #1366 #1364 #1358) +- os400: fix shellcheck warnings in scripts (c6625707 #1358) +- os400: maintain up to date (8457c37a #1309) +- packet: properly bounds check packet_authagent_open() (88a960a8 #1179) +- pem: fix private keys encrypted with AES-GCM methods (e87bdefa #1133) +- reuse: upgrade to `REUSE.toml` (70b8bf31 #1419) +- reuse: fix duplicate copyright warning (b9a4ed83) +- reuse: comply with 3.1 spec and 2.0.0 checker (fe6239a1 #1102 #1101 #1098) +- reuse: provide SPDX identifiers (f6aa31f4 #1084) +- scp: fix missing cast for targets without large file support (c317e06f #1060 #1057 #1002 regr: 5db836b2) +- session: support server banners up to 8192 bytes (was: 256) (1a9e8811 #1443 #1442) +- session: add `libssh2_session_callback_set2()` (c0f69548 #1285) +- session: handle EINTR from send/recv/poll/select to try again as the error is not fatal (798ed4a7 #1058 #955) +- sftp: increase SFTP_HANDLE_MAXLEN back to 4092 (75de6a37 #1422) +- sftp: implement posix-rename@openssh.com (fb652746 #1386) +- src: implement chacha20-poly1305@openssh.com (492bc543 #1426 #584) +- src: use `UINT32_MAX` (dc206408 #1413) +- src: fix type warning in `libssh2_sftp_unlink` macro (ac2e8c73 #1406) +- src: check the return value from `_libssh2_bn_*()` functions (95c824d5 #1354) +- src: support RSA-SHA2 cert-based authentication (rsa-sha2-512_cert and rsa-sha2-256_cert) (3a6ab70d #1314) +- src: check hash update/final success (4718ede4 #1303 #1301) +- src: check hash init success (2ed9eb92 #1301) +- src: add 'strict KEX' to fix CVE-2023-48795 "Terrapin Attack" (d34d9258 #1291 #1290) +- src: disable `-Wsign-conversion` warnings, add option to re-enable (6e451669 #1284 #1257) +- src: fix gcc 13 `-Wconversion` warning on Darwin (8cca7b77 #1209 follow: 08354e0a) +- src: drop a redundant `#include` (1f0174d0 #1153) +- src: improve MSVC C4701 warning fix (8b924999 #1086 #876 #1083) +- src: bump `hash_len` to `size_t` in `LIBSSH2_HOSTKEY_METHOD` (8b917d76 #1076) +- src: bump DSA and ECDSA sign `hash_len` to `size_t` (7b8e0225 #1055) +- tests: avoid using `MAXPATHLEN`, for portability (12427f4f #1415 #198 #1414) +- tests: fix excluding AES-GCM tests (fbd9d192 #1410) +- tests: drop default cygpath option `-u` (38e50aa0) +- tests: fix shellcheck issues in `test_sshd.test` (a2ac8c55) +- tests: sync port number type with the rest of codebase (eb996af8) +- tests: fall back to `$LOGNAME` for username (5326a5ce #1241 #1240) +- tests: show cmake version used in integration tests (2cd2f40e #1201) +- tests: formatting and tidy-ups (e61987a3) +- tests: replace FIXME with comments (1a99a86a) +- tests: add aes256-gcm encrypted key test (802336cf #1135 #1133) +- tests: trap signals in scripts (b2916b28 #1098) +- tests: cast to avoid `-Wchar-subscripts` with Cygwin (43df6a46 #1081 #1080) +- test_read: make it run without Docker (57e9d18e #1139) +- test_sshd.test: show sshd and test connect logs on harness failure (299c2040 #1097) +- test_sshd.test: set a safe PID directory (e8cabdcf #1089) +- test_sshd.test: minor cleanups (d29eea1d) +- tidy-up: link updates (c905bfd2 #1434) +- tidy-up: typo in comment (792e1b6f) +- tidy-up: fix typo found by codespell (706ec36d) +- tidy-up: bump casts from int to long for large C99 types in printfs (2e5a8719 #1264 #1257) +- tidy-up: `unsigned` -> `unsigned int` (b136c379) +- tidy-up: stop using leading underscores in macro names (c6589b88 #1248) +- tidy-up: around `stdint.h` (bfa00f1b #1212) +- tidy-up: fix typo in `readme.vms` (a9a79e7a) +- tidy-up: use built-in `_WIN32` macro to detect Windows (6fbc9505 #1195) +- tidy-up: drop `www.` from `www.libssh2.org` (6e3e8839 #1172) +- tidy-up: delete duplicate word from comment (76307435) +- tidy-up: avoid exclamations, prefer single quotes, in outputs (003fb454 #1079) +- TODO: disable or drop weak algos (0b4bdc85 #1261) +- transport: fix unstable connections over non-blocking sockets (de004875 #1454 #720 #1431 #1397) +- transport: check ETM on remote end when receiving (bde10825 #1332 #1331) +- transport: fix incorrect byte offset in debug message (2388a3aa #1096) +- userauth: avoid oob with huge interactive kbd response (f3a85cad #1337) +- userauth: add a new structure to separate memory read and file read (63b4c20e #773) +- userauth: check whether `*key_method` is a NULL pointer instead of `key_method` (bec57c40) +- wincng: fix `DH_GEX_MAXGROUP` set higher than supported (48584671 #1372 #493) +- wincng: add to ci/GHA, add `./configure` option `--enable-ecdsa-wincng` (3f98bfb0 #1368 #1315) +- wincng: add ECDSA support for host and user authentication (3e723437 #1315) +- wincng: prefer `ULONG`/`DWORD` over `unsigned long` (186c1d63 #1165) +- wincng: tidy-ups (7bb669b5 #1164) +- wolfssl: drop header path hack (8ae1b2d7 #1439) +- wolfssl: fix `EVP_Cipher()` use with v5.6.0 and older (a5b0fac2 #1407 #1394 #797 #1299 #1020) +- wolfssl: bump version in upstream issue comment (5cab802c) +- wolfssl: require v5.4.0 for AES-GCM (260a721c #1411 #1299 #1020) +- wolfssl: enable debug logging in wolfSSL when compiled in (76e7a68a #1310) This release would not have looked like this without help, code, reports and advice from friends like these: - 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) + Viktor Szakats, Michael Buckley, Patrick Monnerat, Ren Mingshuai, + Will Cosgrove, Daniel Stenberg, Josef Cejka, Nicolas Mora, Ryan Kelley, + Aaron Stone, Adam, Anders Borum, András Fekete, Andrei Augustin, binary1248, + Brian Inglis, brucsc on GitHub, concussious on github, Dan Fandrich, + dksslq on github, Haowei Hsu, Harmen Stoppels, Harry Mallon, Jack L, + Jakob Egger, Jiwoo Park, João M. S. Silva, Joel Depooter, Johannes Passing, + Jose Quaresma, Juliusz Sosinowicz, Kai Pastor, Kenneth Davidson, + klux21 on github, Lyndon Brown, Marc Hoersken, mike-jumper, naddy, + Nursan Valeyev, Paul Howarth, PewPewPew, Radek Brich, rahmanih on github, + rolag on github, Seo Suchan, shubhamhii on github, Steve McIntyre, + Tejaswi Kandula, Tobias Stoeckmann, Trzik, Xi Ruoyao diff --git a/uppsrc/Core/SSH/libssh2/agent.c b/uppsrc/Core/SSH/libssh2/agent.c index 85c3e34af..dd709eb1f 100644 --- a/uppsrc/Core/SSH/libssh2/agent.c +++ b/uppsrc/Core/SSH/libssh2/agent.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2009 by Daiki Ueno - * Copyright (C) 2010-2014 by Daniel Stenberg + * Copyright (C) Daiki Ueno + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,12 +35,15 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include "agent.h" -#include "misc.h" + #include +#include /* for getenv() */ + #ifdef HAVE_SYS_UN_H #include #else @@ -49,12 +52,15 @@ support them. */ #undef PF_UNIX #endif -#include "userauth.h" -#include "session.h" -#ifdef WIN32 -#include + +#if defined(_WIN32) && !defined(LIBSSH2_WINDOWS_UWP) +#define HAVE_WIN32_AGENTS #endif +#include "userauth.h" +#include "session.h" + +#if 0 /* Requests from client to agent for protocol 1 key operations */ #define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 #define SSH_AGENTC_RSA_CHALLENGE 3 @@ -62,10 +68,12 @@ #define SSH_AGENTC_REMOVE_RSA_IDENTITY 8 #define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9 #define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24 +#endif /* Requests from client to agent for protocol 2 key operations */ #define SSH2_AGENTC_REQUEST_IDENTITIES 11 #define SSH2_AGENTC_SIGN_REQUEST 13 +#if 0 #define SSH2_AGENTC_ADD_IDENTITY 17 #define SSH2_AGENTC_REMOVE_IDENTITY 18 #define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 @@ -86,13 +94,79 @@ #define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 #define SSH_AGENT_RSA_RESPONSE 4 +/* Key constraint identifiers */ +#define SSH_AGENT_CONSTRAIN_LIFETIME 1 +#define SSH_AGENT_CONSTRAIN_CONFIRM 2 +#endif + /* Replies from agent to client for protocol 2 key operations */ #define SSH2_AGENT_IDENTITIES_ANSWER 12 #define SSH2_AGENT_SIGN_RESPONSE 14 -/* Key constraint identifiers */ -#define SSH_AGENT_CONSTRAIN_LIFETIME 1 -#define SSH_AGENT_CONSTRAIN_CONFIRM 2 +/* Signature request methods */ +#define SSH_AGENT_RSA_SHA2_256 2 +#define SSH_AGENT_RSA_SHA2_512 4 + +/* non-blocking mode on agent connection is not yet implemented, but + for future use. */ +typedef enum { + 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 { + const agent_connect_func connect; + const agent_transact_func transact; + const 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 HAVE_WIN32_AGENTS + OVERLAPPED overlapped; + HANDLE pipe; + BOOL pending_io; +#endif +}; + +#include "agent_win.c" #ifdef PF_UNIX static int @@ -115,10 +189,10 @@ agent_connect_unix(LIBSSH2_AGENT *agent) "failed creating socket"); s_un.sun_family = AF_UNIX; - strncpy(s_un.sun_path, path, sizeof s_un.sun_path); + strncpy(s_un.sun_path, path, sizeof(s_un.sun_path)); s_un.sun_path[sizeof(s_un.sun_path)-1] = 0; /* make sure there's a trailing zero */ - if(connect(agent->fd, (struct sockaddr*)(&s_un), sizeof s_un) != 0) { + if(connect(agent->fd, (struct sockaddr*)(&s_un), sizeof(s_un)) != 0) { close(agent->fd); return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "failed connecting with agent"); @@ -128,20 +202,22 @@ agent_connect_unix(LIBSSH2_AGENT *agent) } #define RECV_SEND_ALL(func, socket, buffer, length, flags, abstract) \ - int rc; \ - size_t finished = 0; \ + do { \ + size_t finished = 0; \ \ - while(finished < length) { \ - rc = func(socket, \ - (char *)buffer + finished, length - finished, \ - flags, abstract); \ - if(rc < 0) \ - return rc; \ + while(finished < length) { \ + ssize_t rc; \ + rc = func(socket, \ + (char *)buffer + finished, length - finished, \ + flags, abstract); \ + if(rc < 0) \ + return rc; \ \ - finished += rc; \ - } \ + finished += rc; \ + } \ \ - return finished; + return finished; \ + } while(0) static ssize_t _send_all(LIBSSH2_SEND_FUNC(func), libssh2_socket_t socket, const void *buffer, size_t length, @@ -167,9 +243,10 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Send the length of the request */ if(transctx->state == agent_NB_state_request_created) { - _libssh2_htonu32(buf, transctx->request_len); - rc = _send_all(agent->session->send, agent->fd, - buf, sizeof buf, 0, &agent->session->abstract); + _libssh2_htonu32(buf, (uint32_t)transctx->request_len); + rc = (int)_send_all(agent->session->send, agent->fd, + buf, sizeof(buf), 0, + &agent->session->abstract); if(rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; else if(rc < 0) @@ -180,8 +257,9 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Send the request body */ if(transctx->state == agent_NB_state_request_length_sent) { - rc = _send_all(agent->session->send, agent->fd, transctx->request, - transctx->request_len, 0, &agent->session->abstract); + rc = (int)_send_all(agent->session->send, agent->fd, + transctx->request, transctx->request_len, 0, + &agent->session->abstract); if(rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; else if(rc < 0) @@ -192,8 +270,9 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Receive the length of a response */ if(transctx->state == agent_NB_state_request_sent) { - rc = _recv_all(agent->session->recv, agent->fd, - buf, sizeof buf, 0, &agent->session->abstract); + rc = (int)_recv_all(agent->session->recv, agent->fd, + buf, sizeof(buf), 0, + &agent->session->abstract); if(rc < 0) { if(rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; @@ -211,8 +290,9 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Receive the response body */ if(transctx->state == agent_NB_state_response_length_received) { - rc = _recv_all(agent->session->recv, agent->fd, transctx->response, - transctx->response_len, 0, &agent->session->abstract); + rc = (int)_recv_all(agent->session->recv, agent->fd, + transctx->response, transctx->response_len, 0, + &agent->session->abstract); if(rc < 0) { if(rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; @@ -238,14 +318,14 @@ agent_disconnect_unix(LIBSSH2_AGENT *agent) return LIBSSH2_ERROR_NONE; } -struct agent_ops agent_ops_unix = { +static struct agent_ops agent_ops_unix = { agent_connect_unix, agent_transact_unix, agent_disconnect_unix }; #endif /* PF_UNIX */ -#ifdef WIN32 +#ifdef HAVE_WIN32_AGENTS /* Code to talk to Pageant was taken from PuTTY. * * Portions copyright Robert de Bath, Joris van Rantwijk, Delian @@ -276,7 +356,7 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) HANDLE filemap; unsigned char *p; unsigned char *p2; - int id; + LRESULT id; COPYDATASTRUCT cds; if(!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN) @@ -289,16 +369,16 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) "found no pageant"); snprintf(mapname, sizeof(mapname), - "PageantRequest%08x%c", (unsigned)GetCurrentThreadId(), '\0'); + "PageantRequest%08x", (unsigned)GetCurrentThreadId()); filemap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, PAGEANT_MAX_MSGLEN, mapname); - if(filemap == NULL || filemap == INVALID_HANDLE_VALUE) + if(!filemap || filemap == INVALID_HANDLE_VALUE) return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "failed setting up pageant filemap"); p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); - if(p == NULL || p2 == NULL) { + if(!p || !p2) { CloseHandle(filemap); return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "failed to open pageant filemap for writing"); @@ -308,7 +388,7 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) transctx->request_len); cds.dwData = PAGEANT_COPYDATA_ID; - cds.cbData = 1 + strlen(mapname); + cds.cbData = (DWORD)(1 + strlen(mapname)); cds.lpData = mapname; id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds); @@ -343,21 +423,21 @@ agent_disconnect_pageant(LIBSSH2_AGENT *agent) return 0; } -struct agent_ops agent_ops_pageant = { +static struct agent_ops agent_ops_pageant = { agent_connect_pageant, agent_transact_pageant, agent_disconnect_pageant }; -#endif /* WIN32 */ +#endif /* HAVE_WIN32_AGENTS */ static struct { const char *name; struct agent_ops *ops; } supported_backends[] = { -#ifdef WIN32 +#ifdef HAVE_WIN32_AGENTS {"Pageant", &agent_ops_pageant}, {"OpenSSH", &agent_ops_openssh}, -#endif /* WIN32 */ +#endif /* HAVE_WIN32_AGENTS */ #ifdef PF_UNIX {"Unix", &agent_ops_unix}, #endif /* PF_UNIX */ @@ -375,6 +455,9 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, ssize_t method_len; unsigned char *s; int rc; + unsigned char *method_name = NULL; + uint32_t sign_flags = 0; + ssize_t plain_len; /* Create a request to sign the data */ if(transctx->state == agent_NB_state_init) { @@ -391,7 +474,18 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, _libssh2_store_str(&s, (const char *)data, data_len); /* flags */ - _libssh2_store_u32(&s, 0); + if(session->userauth_pblc_method_len > 0 && + session->userauth_pblc_method) { + if(session->userauth_pblc_method_len == 12 && + !memcmp(session->userauth_pblc_method, "rsa-sha2-512", 12)) { + sign_flags = SSH_AGENT_RSA_SHA2_512; + } + else if(session->userauth_pblc_method_len == 12 && + !memcmp(session->userauth_pblc_method, "rsa-sha2-256", 12)) { + sign_flags = SSH_AGENT_RSA_SHA2_256; + } + } + _libssh2_store_u32(&s, sign_flags); transctx->request_len = s - transctx->request; transctx->send_recv_total = 0; @@ -449,8 +543,32 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } + + /* method name */ + method_name = LIBSSH2_ALLOC(session, method_len); + if(!method_name) { + rc = LIBSSH2_ERROR_ALLOC; + goto error; + } + memcpy(method_name, s, method_len); s += method_len; + plain_len = plain_method((char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + + /* check to see if we match requested */ + if(((size_t)method_len != session->userauth_pblc_method_len && + method_len != plain_len) || + memcmp(method_name, session->userauth_pblc_method, method_len)) { + _libssh2_debug((session, + LIBSSH2_TRACE_KEX, + "Agent sign method %.*s", + (int)method_len, method_name)); + + rc = LIBSSH2_ERROR_ALGO_UNSUPPORTED; + goto error; + } + /* Read the signature */ len -= 4; if(len < 0) { @@ -472,13 +590,19 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, } memcpy(*sig, s, *sig_len); - error: +error: + + if(method_name) + LIBSSH2_FREE(session, method_name); + LIBSSH2_FREE(session, transctx->request); transctx->request = NULL; LIBSSH2_FREE(session, transctx->response); transctx->response = NULL; + transctx->state = agent_NB_state_init; + return _libssh2_error(session, rc, "agent sign failure"); } @@ -541,7 +665,7 @@ agent_list_identities(LIBSSH2_AGENT *agent) while(num_identities--) { struct agent_publickey *identity; - ssize_t comment_len; + size_t comment_len; /* Read the length of the blob */ len -= 4; @@ -549,7 +673,7 @@ agent_list_identities(LIBSSH2_AGENT *agent) rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } - identity = LIBSSH2_ALLOC(agent->session, sizeof *identity); + identity = LIBSSH2_ALLOC(agent->session, sizeof(*identity)); if(!identity) { rc = LIBSSH2_ERROR_ALLOC; goto error; @@ -586,14 +710,14 @@ agent_list_identities(LIBSSH2_AGENT *agent) comment_len = _libssh2_ntohu32(s); s += 4; - /* Read the comment */ - len -= comment_len; - if(len < 0) { + if(comment_len > (size_t)len) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; LIBSSH2_FREE(agent->session, identity->external.blob); LIBSSH2_FREE(agent->session, identity); goto error; } + /* Read the comment */ + len -= comment_len; identity->external.comment = LIBSSH2_ALLOC(agent->session, comment_len + 1); @@ -609,7 +733,7 @@ agent_list_identities(LIBSSH2_AGENT *agent) _libssh2_list_add(&agent->head, &identity->node); } - error: +error: LIBSSH2_FREE(agent->session, transctx->response); transctx->response = NULL; @@ -634,7 +758,7 @@ agent_free_identities(LIBSSH2_AGENT *agent) #define AGENT_PUBLICKEY_MAGIC 0x3bdefed2 /* - * agent_publickey_to_external() + * agent_publickey_to_external * * Copies data from the internal to the external representation struct. * @@ -661,7 +785,7 @@ libssh2_agent_init(LIBSSH2_SESSION *session) { LIBSSH2_AGENT *agent; - agent = LIBSSH2_CALLOC(session, sizeof *agent); + agent = LIBSSH2_CALLOC(session, sizeof(*agent)); if(!agent) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for agent connection"); @@ -672,7 +796,7 @@ libssh2_agent_init(LIBSSH2_SESSION *session) agent->identity_agent_path = NULL; _libssh2_list_init(&agent->head); -#ifdef WIN32 +#ifdef HAVE_WIN32_AGENTS agent->pipe = INVALID_HANDLE_VALUE; memset(&agent->overlapped, 0, sizeof(OVERLAPPED)); agent->pending_io = FALSE; @@ -682,7 +806,7 @@ libssh2_agent_init(LIBSSH2_SESSION *session) } /* - * libssh2_agent_connect() + * libssh2_agent_connect * * Connect to an ssh-agent. * @@ -702,7 +826,7 @@ libssh2_agent_connect(LIBSSH2_AGENT *agent) } /* - * libssh2_agent_list_identities() + * libssh2_agent_list_identities * * Request ssh-agent to list identities. * @@ -711,14 +835,14 @@ libssh2_agent_connect(LIBSSH2_AGENT *agent) LIBSSH2_API int libssh2_agent_list_identities(LIBSSH2_AGENT *agent) { - memset(&agent->transctx, 0, sizeof agent->transctx); + memset(&agent->transctx, 0, sizeof(agent->transctx)); /* Abandon the last fetched identities */ agent_free_identities(agent); return agent_list_identities(agent); } /* - * libssh2_agent_get_identity() + * libssh2_agent_get_identity * * Traverse the internal list of public keys. Pass NULL to 'prev' to get * the first one. Or pass a pointer to the previously returned one to get the @@ -755,7 +879,7 @@ libssh2_agent_get_identity(LIBSSH2_AGENT *agent, } /* - * libssh2_agent_userauth() + * libssh2_agent_userauth * * Do publickey user authentication with the help of ssh-agent. * @@ -770,7 +894,7 @@ libssh2_agent_userauth(LIBSSH2_AGENT *agent, int rc; if(agent->session->userauth_pblc_state == libssh2_NB_state_idle) { - memset(&agent->transctx, 0, sizeof agent->transctx); + memset(&agent->transctx, 0, sizeof(agent->transctx)); agent->identity = identity->node; } @@ -785,7 +909,58 @@ libssh2_agent_userauth(LIBSSH2_AGENT *agent, } /* - * libssh2_agent_disconnect() + * libssh2_agent_sign + * + * Sign a payload using a system-installed ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_sign(LIBSSH2_AGENT *agent, + struct libssh2_agent_publickey *identity, + unsigned char **sig, + size_t *s_len, + const unsigned char *data, + size_t d_len, + const char *method, + unsigned int method_len) +{ + void *abstract = agent; + int rc; + uint32_t methodLen; + + if(agent->session->userauth_pblc_state == libssh2_NB_state_idle) { + memset(&agent->transctx, 0, sizeof(agent->transctx)); + agent->identity = identity->node; + } + + if(identity->blob_len < sizeof(uint32_t)) { + return LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } + + methodLen = _libssh2_ntohu32(identity->blob); + + if(identity->blob_len < sizeof(uint32_t) + methodLen) { + return LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } + + agent->session->userauth_pblc_method_len = method_len; + agent->session->userauth_pblc_method = LIBSSH2_ALLOC(agent->session, + method_len); + + memcpy(agent->session->userauth_pblc_method, method, methodLen); + + rc = agent_sign(agent->session, sig, s_len, data, d_len, &abstract); + + LIBSSH2_FREE(agent->session, agent->session->userauth_pblc_method); + agent->session->userauth_pblc_method = NULL; + agent->session->userauth_pblc_method_len = 0; + + return rc; +} + +/* + * libssh2_agent_disconnect * * Close a connection to an ssh-agent. * @@ -800,7 +975,7 @@ libssh2_agent_disconnect(LIBSSH2_AGENT *agent) } /* - * libssh2_agent_free() + * libssh2_agent_free * * Free an ssh-agent handle. This function also frees the internal * collection of public keys. @@ -813,7 +988,7 @@ libssh2_agent_free(LIBSSH2_AGENT *agent) libssh2_agent_disconnect(agent); } - if(agent->identity_agent_path != NULL) + if(agent->identity_agent_path) LIBSSH2_FREE(agent->session, agent->identity_agent_path); agent_free_identities(agent); @@ -821,7 +996,7 @@ libssh2_agent_free(LIBSSH2_AGENT *agent) } /* - * libssh2_agent_set_identity_path() + * libssh2_agent_set_identity_path * * Allows a custom agent socket path beyond SSH_AUTH_SOCK env * @@ -846,7 +1021,7 @@ libssh2_agent_set_identity_path(LIBSSH2_AGENT *agent, const char *path) } /* - * libssh2_agent_get_identity_path() + * libssh2_agent_get_identity_path * * Returns the custom agent socket path if set * diff --git a/uppsrc/Core/SSH/libssh2/agent.h b/uppsrc/Core/SSH/libssh2/agent.h deleted file mode 100644 index dfac0715c..000000000 --- a/uppsrc/Core/SSH/libssh2/agent.h +++ /dev/null @@ -1,112 +0,0 @@ -#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/uppsrc/Core/SSH/libssh2/agent_win.c b/uppsrc/Core/SSH/libssh2/agent_win.c index a1605a95f..3764fe433 100644 --- a/uppsrc/Core/SSH/libssh2/agent_win.c +++ b/uppsrc/Core/SSH/libssh2/agent_win.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2009 by Daiki Ueno - * Copyright (C) 2010-2014 by Daniel Stenberg + * Copyright (C) Daiki Ueno + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,32 +35,19 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause */ -#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 HAVE_WIN32_AGENTS /* Compile this via agent.c */ + +#include /* for getenv() */ -#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: + * specifically the following files: * * - contrib\win32\win32compat\fileio.c * - Structure of agent_connect_openssh from ssh_get_authentication_socket @@ -74,7 +61,7 @@ * - fileio_close replacing close * * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * Copyright (C) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved * Functions for connecting the local authentication agent. * @@ -85,7 +72,7 @@ * called by a name other than "ssh" or "Secure Shell". * * SSH2 implementation, - * Copyright (c) 2000 Markus Friedl. All rights reserved. + * 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 @@ -107,7 +94,7 @@ * (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. + * Copyright (C) 2015 Microsoft Corp. * All rights reserved * * Microsoft openssh win32 port @@ -195,7 +182,7 @@ agent_connect_openssh(LIBSSH2_AGENT *agent) } event = CreateEventA(NULL, TRUE, FALSE, NULL); - if(event == NULL) { + if(!event) { ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "unable to create async I/O event"); goto cleanup; @@ -208,7 +195,7 @@ agent_connect_openssh(LIBSSH2_AGENT *agent) agent->fd = 0; /* Mark as the connection has been established */ cleanup: - if(event != NULL) + if(event) CloseHandle(event); if(pipe != INVALID_HANDLE_VALUE) CloseHandle(pipe); @@ -273,7 +260,7 @@ agent_transact_openssh(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, (uint32_t)transctx->request_len); - rc = win32_openssh_send_all(agent, buf, sizeof buf, + rc = win32_openssh_send_all(agent, buf, sizeof(buf), &transctx->send_recv_total); if(rc == LIBSSH2_ERROR_EAGAIN) return LIBSSH2_ERROR_EAGAIN; @@ -298,7 +285,7 @@ agent_transact_openssh(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Receive the length of the body */ if(transctx->state == agent_NB_state_request_sent) { - rc = win32_openssh_recv_all(agent, buf, sizeof buf, + rc = win32_openssh_recv_all(agent, buf, sizeof(buf), &transctx->send_recv_total); if(rc == LIBSSH2_ERROR_EAGAIN) return LIBSSH2_ERROR_EAGAIN; @@ -353,9 +340,10 @@ agent_disconnect_openssh(LIBSSH2_AGENT *agent) return LIBSSH2_ERROR_NONE; } -struct agent_ops agent_ops_openssh = { +static struct agent_ops agent_ops_openssh = { agent_connect_openssh, agent_transact_openssh, agent_disconnect_openssh }; -#endif /* WIN32 */ + +#endif /* HAVE_WIN32_AGENTS */ diff --git a/uppsrc/Core/SSH/libssh2/bcrypt_pbkdf.c b/uppsrc/Core/SSH/libssh2/bcrypt_pbkdf.c index f782bcac5..73cda4357 100644 --- a/uppsrc/Core/SSH/libssh2/bcrypt_pbkdf.c +++ b/uppsrc/Core/SSH/libssh2/bcrypt_pbkdf.c @@ -1,6 +1,6 @@ /* $OpenBSD: bcrypt_pbkdf.c,v 1.4 2013/07/29 00:55:53 tedu Exp $ */ /* - * Copyright (c) 2013 Ted Unangst + * Copyright (C) Ted Unangst * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -13,21 +13,18 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: MIT */ +#include "libssh2_priv.h" #ifndef HAVE_BCRYPT_PBKDF -#include "libssh2_priv.h" #include -#include -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#include "blf.h" - -#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) +#define LIBSSH2_BCRYPT_PBKDF_C +#include "blowfish.c" /* * pkcs #5 pbkdf2 implementation using the "bcrypt" hash @@ -60,12 +57,15 @@ static void bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) { blf_ctx state; - uint8_t ciphertext[BCRYPT_HASHSIZE] = - "OxychromaticBlowfishSwatDynamite"; + uint8_t ciphertext[BCRYPT_HASHSIZE] = { + 'O', 'x', 'y', 'c', 'h', 'r', 'o', 'm', 'a', 't', 'i', 'c', + 'B', 'l', 'o', 'w', 'f', 'i', 's', 'h', + 'S', 'w', 'a', 't', + 'D', 'y', 'n', 'a', 'm', 'i', 't', 'e' }; uint32_t cdata[BCRYPT_BLOCKS]; int i; uint16_t j; - size_t shalen = SHA512_DIGEST_LENGTH; + uint16_t shalen = SHA512_DIGEST_LENGTH; /* key expansion */ Blowfish_initstate(&state); @@ -85,7 +85,7 @@ bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) /* copy out */ for(i = 0; i < BCRYPT_BLOCKS; i++) { - out[4 * i + 3] = (cdata[i] >> 24) & 0xff; + out[4 * i + 3] = (uint8_t)((cdata[i] >> 24) & 0xff); out[4 * i + 2] = (cdata[i] >> 16) & 0xff; out[4 * i + 1] = (cdata[i] >> 8) & 0xff; out[4 * i + 0] = cdata[i] & 0xff; @@ -97,7 +97,7 @@ bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) _libssh2_explicit_zero(&state, sizeof(state)); } -int +static int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, uint8_t *key, size_t keylen, unsigned int rounds) @@ -116,10 +116,10 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, if(rounds < 1) return -1; if(passlen == 0 || saltlen == 0 || keylen == 0 || - keylen > sizeof(out) * sizeof(out) || saltlen > 1<<20) + keylen > sizeof(out) * sizeof(out) || saltlen > 1 << 20) return -1; countsalt = calloc(1, saltlen + 4); - if(countsalt == NULL) + if(!countsalt) return -1; stride = (keylen + sizeof(out) - 1) / sizeof(out); amt = (keylen + stride - 1) / stride; @@ -127,30 +127,41 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, memcpy(countsalt, salt, saltlen); /* collapse password */ - libssh2_sha512_init(&ctx); - libssh2_sha512_update(ctx, pass, passlen); - libssh2_sha512_final(ctx, sha2pass); + if(!libssh2_sha512_init(&ctx) || + !libssh2_sha512_update(ctx, pass, passlen) || + !libssh2_sha512_final(ctx, sha2pass)) { + free(countsalt); + return -1; + } /* generate key, sizeof(out) at a time */ for(count = 1; keylen > 0; count++) { - countsalt[saltlen + 0] = (count >> 24) & 0xff; + countsalt[saltlen + 0] = (uint8_t)((count >> 24) & 0xff); countsalt[saltlen + 1] = (count >> 16) & 0xff; countsalt[saltlen + 2] = (count >> 8) & 0xff; countsalt[saltlen + 3] = count & 0xff; /* first round, salt is salt */ - libssh2_sha512_init(&ctx); - libssh2_sha512_update(ctx, countsalt, saltlen + 4); - libssh2_sha512_final(ctx, sha2salt); + if(!libssh2_sha512_init(&ctx) || + !libssh2_sha512_update(ctx, countsalt, saltlen + 4) || + !libssh2_sha512_final(ctx, sha2salt)) { + _libssh2_explicit_zero(out, sizeof(out)); + free(countsalt); + return -1; + } bcrypt_hash(sha2pass, sha2salt, tmpout); memcpy(out, tmpout, sizeof(out)); for(i = 1; i < rounds; i++) { /* subsequent rounds, salt is previous output */ - libssh2_sha512_init(&ctx); - libssh2_sha512_update(ctx, tmpout, sizeof(tmpout)); - libssh2_sha512_final(ctx, sha2salt); + if(!libssh2_sha512_init(&ctx) || + !libssh2_sha512_update(ctx, tmpout, sizeof(tmpout)) || + !libssh2_sha512_final(ctx, sha2salt)) { + _libssh2_explicit_zero(out, sizeof(out)); + free(countsalt); + return -1; + } bcrypt_hash(sha2pass, sha2salt, tmpout); for(j = 0; j < sizeof(out); j++) @@ -160,7 +171,7 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, /* * pbkdf2 deviation: output the key material non-linearly. */ - amt = MINIMUM(amt, keylen); + amt = LIBSSH2_MIN(amt, keylen); for(i = 0; i < amt; i++) { size_t dest = i * stride + (count - 1); if(dest >= origkeylen) { @@ -178,3 +189,22 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, return 0; } #endif /* HAVE_BCRYPT_PBKDF */ + +/* Wrapper */ + +int _libssh2_bcrypt_pbkdf(const char *pass, + size_t passlen, + const uint8_t *salt, + size_t saltlen, + uint8_t *key, + size_t keylen, + unsigned int rounds) +{ + return bcrypt_pbkdf(pass, + passlen, + salt, + saltlen, + key, + keylen, + rounds); +} diff --git a/uppsrc/Core/SSH/libssh2/blf.h b/uppsrc/Core/SSH/libssh2/blf.h deleted file mode 100644 index 5b7c8aae0..000000000 --- a/uppsrc/Core/SSH/libssh2/blf.h +++ /dev/null @@ -1,89 +0,0 @@ -#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 - * - * Copyright 1997 Niels Provos - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Niels Provos. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) - -/* Schneier specifies a maximum key length of 56 bytes. - * This ensures that every key bit affects every cipher - * bit. However, the subkeys can hold up to 72 bytes. - * Warning: For normal blowfish encryption only 56 bytes - * of the key affect all cipherbits. - */ - -#define BLF_N 16 /* Number of Subkeys */ -#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */ -#define BLF_MAXUTILIZED ((BLF_N + 2)*4) /* 576 bits */ - -/* Blowfish context */ -typedef struct BlowfishContext { - uint32_t S[4][256]; /* S-Boxes */ - uint32_t P[BLF_N + 2]; /* Subkeys */ -} blf_ctx; - -/* Raw access to customized Blowfish - * blf_key is just: - * Blowfish_initstate( state ) - * Blowfish_expand0state( state, key, keylen ) - */ - -void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *); -void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *); -void Blowfish_initstate(blf_ctx *); -void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t); -void Blowfish_expandstate -(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t); - -/* Standard Blowfish */ - -void blf_key(blf_ctx *, const uint8_t *, uint16_t); -void blf_enc(blf_ctx *, uint32_t *, uint16_t); -void blf_dec(blf_ctx *, uint32_t *, uint16_t); - -void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t); -void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t); - -void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); -void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); - -/* Converts uint8_t to uint32_t */ -uint32_t Blowfish_stream2word(const uint8_t *, uint16_t, uint16_t *); - -/* bcrypt with pbkd */ -int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, - size_t saltlen, - uint8_t *key, size_t keylen, unsigned int rounds); - -#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */ -#endif /* __LIBSSH2_BLF_H */ diff --git a/uppsrc/Core/SSH/libssh2/blowfish.c b/uppsrc/Core/SSH/libssh2/blowfish.c index 4aefc66ac..5de54f596 100644 --- a/uppsrc/Core/SSH/libssh2/blowfish.c +++ b/uppsrc/Core/SSH/libssh2/blowfish.c @@ -1,7 +1,8 @@ /* $OpenBSD: blowfish.c,v 1.18 2004/11/02 17:23:26 hshoexer Exp $ */ /* - * Blowfish block cipher for OpenBSD - * Copyright 1997 Niels Provos + * Blowfish for OpenBSD - a fast block cipher designed by Bruce Schneier + * + * Copyright (C) Niels Provos * All rights reserved. * * Implementation advice by David Mazieres . @@ -14,10 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Niels Provos. - * 4. The name of the author may not be used to endorse or promote products + * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR @@ -30,6 +28,8 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* @@ -39,38 +39,81 @@ * Bruce Schneier. */ +#if defined(LIBSSH2_BCRYPT_PBKDF_C) || defined(_DEBUG_BLOWFISH) #if !defined(HAVE_BCRYPT_PBKDF) && (!defined(HAVE_BLOWFISH_INITSTATE) || \ !defined(HAVE_BLOWFISH_EXPAND0STATE) || \ !defined(HAVE_BLF_ENC)) -#if 0 -#include /* used for debugging */ +#ifdef _DEBUG_BLOWFISH +#include #include +#include #endif -#include +/* Schneier specifies a maximum key length of 56 bytes. + * This ensures that every key bit affects every cipher + * bit. However, the subkeys can hold up to 72 bytes. + * Warning: For normal blowfish encryption only 56 bytes + * of the key affect all cipherbits. + */ -#include "libssh2.h" -#include "blf.h" +#define BLF_N 16 /* Number of Subkeys */ +#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */ +#define BLF_MAXUTILIZED ((BLF_N + 2)*4) /* 576 bits */ -#undef inline -#ifdef __GNUC__ -#define inline __inline -#else /* !__GNUC__ */ -#define inline -#endif /* !__GNUC__ */ +/* Blowfish context */ +typedef struct BlowfishContext { + uint32_t S[4][256]; /* S-Boxes */ + uint32_t P[BLF_N + 2]; /* Subkeys */ +} blf_ctx; + +/* Raw access to customized Blowfish + * blf_key is just: + * Blowfish_initstate( state ) + * Blowfish_expand0state( state, key, keylen ) + */ + +static void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *); +#ifdef _DEBUG_BLOWFISH +static void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *); +#endif +static void Blowfish_initstate(blf_ctx *); +static void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t); +static void Blowfish_expandstate +(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t); + +/* Standard Blowfish */ + +#ifdef _DEBUG_BLOWFISH +static void blf_key(blf_ctx *, const uint8_t *, uint16_t); +#endif +static void blf_enc(blf_ctx *, uint32_t *, uint16_t); +#ifdef _DEBUG_BLOWFISH +static void blf_dec(blf_ctx *, uint32_t *, uint16_t); +#endif + +#if 0 +static void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t); +static void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t); + +static void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); +static void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); +#endif + +/* Converts uint8_t to uint32_t */ +static uint32_t Blowfish_stream2word(const uint8_t *, uint16_t, uint16_t *); /* Function for Feistel Networks */ -#define F(s, x) ((((s)[ (((x)>>24)&0xFF)] \ - + (s)[0x100 + (((x)>>16)&0xFF)]) \ - ^ (s)[0x200 + (((x)>> 8)&0xFF)]) \ - + (s)[0x300 + ( (x) &0xFF)]) +#define F(s, x) ((((s)[ (((x) >> 24) & 0xFF)] \ + + (s)[0x100 + (((x) >> 16) & 0xFF)]) \ + ^ (s)[0x200 + (((x) >> 8) & 0xFF)]) \ + + (s)[0x300 + ( (x) & 0xFF)]) #define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n]) -void +static void Blowfish_encipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) { uint32_t Xl; @@ -95,7 +138,8 @@ Blowfish_encipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) *xr = Xl; } -void +#ifdef _DEBUG_BLOWFISH +static void Blowfish_decipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) { uint32_t Xl; @@ -119,8 +163,9 @@ Blowfish_decipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) *xl = Xr ^ p[0]; *xr = Xl; } +#endif -void +static void Blowfish_initstate(blf_ctx *c) { /* P-box and S-box tables initialized with digits of Pi */ @@ -399,7 +444,7 @@ Blowfish_initstate(blf_ctx *c) *c = initstate; } -uint32_t +static uint32_t Blowfish_stream2word(const uint8_t *data, uint16_t databytes, uint16_t *current) { @@ -420,12 +465,12 @@ Blowfish_stream2word(const uint8_t *data, uint16_t databytes, return temp; } -void +static void Blowfish_expand0state(blf_ctx *c, const uint8_t *key, uint16_t keybytes) { - uint16_t i; + int i; + int k; uint16_t j; - uint16_t k; uint32_t temp; uint32_t datal; uint32_t datar; @@ -457,14 +502,13 @@ Blowfish_expand0state(blf_ctx *c, const uint8_t *key, uint16_t keybytes) } } - -void +static void Blowfish_expandstate(blf_ctx *c, const uint8_t *data, uint16_t databytes, const uint8_t *key, uint16_t keybytes) { - uint16_t i; + int i; + int k; uint16_t j; - uint16_t k; uint32_t temp; uint32_t datal; uint32_t datar; @@ -501,7 +545,8 @@ Blowfish_expandstate(blf_ctx *c, const uint8_t *data, uint16_t databytes, } -void +#ifdef _DEBUG_BLOWFISH +static void blf_key(blf_ctx *c, const uint8_t *k, uint16_t len) { /* Initialize S-boxes and subkeys with Pi */ @@ -510,8 +555,9 @@ blf_key(blf_ctx *c, const uint8_t *k, uint16_t len) /* Transform S-boxes and subkeys with key */ Blowfish_expand0state(c, k, len); } +#endif -void +static void blf_enc(blf_ctx *c, uint32_t *data, uint16_t blocks) { uint32_t *d; @@ -524,7 +570,8 @@ blf_enc(blf_ctx *c, uint32_t *data, uint16_t blocks) } } -void +#ifdef _DEBUG_BLOWFISH +static void blf_dec(blf_ctx *c, uint32_t *data, uint16_t blocks) { uint32_t *d; @@ -536,8 +583,10 @@ blf_dec(blf_ctx *c, uint32_t *data, uint16_t blocks) d += 2; } } +#endif -void +#if 0 +static void blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len) { uint32_t l, r; @@ -547,11 +596,11 @@ blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_encipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; @@ -559,7 +608,7 @@ blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len) } } -void +static void blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len) { uint32_t l, r; @@ -569,11 +618,11 @@ blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; @@ -581,7 +630,7 @@ blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len) } } -void +static void blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len) { uint32_t l, r; @@ -593,11 +642,11 @@ blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_encipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; @@ -606,7 +655,7 @@ blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len) } } -void +static void blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len) { uint32_t l, r; @@ -619,11 +668,11 @@ blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; @@ -635,31 +684,31 @@ blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; for(j = 0; j < 8; j++) data[j] ^= iva[j]; } +#endif -#if 0 -void +#ifdef _DEBUG_BLOWFISH +static void report(uint32_t data[], uint16_t len) { - uint16_t i; + int i; for(i = 0; i < len; i += 2) - printf("Block %0hd: %08lx %08lx.\n", - i / 2, data[i], data[i + 1]); + printf("Block %d: 0x%08lx 0x%08lx.\n", + i / 2, (unsigned long)data[i], (unsigned long)data[i + 1]); } -void +int main(void) { - blf_ctx c; char key[] = "AAAAA"; char key2[] = "abcdefghijklmnopqrstuvwxyz"; @@ -682,12 +731,15 @@ main(void) report(data, 10); /* Second test */ - blf_key(&c, (uint8_t *) key2, strlen(key2)); + blf_key(&c, (uint8_t *) key2, (uint16_t)strlen(key2)); blf_enc(&c, data2, 1); printf("\nShould read as: 0x324ed0fe 0xf413a203.\n"); report(data2, 2); blf_dec(&c, data2, 1); + printf("\nShould read as: 0x424c4f57 0x46495348.\n"); report(data2, 2); + + return 0; } #endif @@ -695,3 +747,5 @@ main(void) (!defined(HAVE_BLOWFISH_INITSTATE) || \ !defined(HAVE_BLOWFISH_EXPAND0STATE) || \ '!defined(HAVE_BLF_ENC)) */ + +#endif /* defined(LIBSSH2_BCRYPT_PBKDF_C) || defined(_DEBUG_BLOWFISH) */ diff --git a/uppsrc/Core/SSH/libssh2/chacha.c b/uppsrc/Core/SSH/libssh2/chacha.c new file mode 100644 index 000000000..72560f861 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/chacha.c @@ -0,0 +1,224 @@ +/* + * chacha-merged.c version 20080118 + * D. J. Bernstein + * Public domain. + * Copyright not intended 2024. + * + * SPDX-License-Identifier: SAX-PD-2.0 + */ + +#include "libssh2_priv.h" + +#include "chacha.h" + +/* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct chacha_ctx chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[17] = "expand 32-byte k"; +static const char tau[17] = "expand 16-byte k"; + +void +chacha_keysetup(chacha_ctx *x, const u8 *k, u32 kbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if(kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } + else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void +chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) +{ + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void +chacha_encrypt_bytes(chacha_ctx *x, const u8 *m, u8 *c, u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + u_int i; + + if(!bytes) + return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for(;;) { + if(bytes < 64) { + for(i = 0; i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for(i = 20; i > 0; i -= 2) { + QUARTERROUND(x0, x4, x8, x12) + QUARTERROUND(x1, x5, x9, x13) + QUARTERROUND(x2, x6, x10, x14) + QUARTERROUND(x3, x7, x11, x15) + QUARTERROUND(x0, x5, x10, x15) + QUARTERROUND(x1, x6, x11, x12) + QUARTERROUND(x2, x7, x8, x13) + QUARTERROUND(x3, x4, x9, x14) + } + x0 = PLUS(x0, j0); + x1 = PLUS(x1, j1); + x2 = PLUS(x2, j2); + x3 = PLUS(x3, j3); + x4 = PLUS(x4, j4); + x5 = PLUS(x5, j5); + x6 = PLUS(x6, j6); + x7 = PLUS(x7, j7); + x8 = PLUS(x8, j8); + x9 = PLUS(x9, j9); + x10 = PLUS(x10, j10); + x11 = PLUS(x11, j11); + x12 = PLUS(x12, j12); + x13 = PLUS(x13, j13); + x14 = PLUS(x14, j14); + x15 = PLUS(x15, j15); + + x0 = XOR(x0, U8TO32_LITTLE(m + 0)); + x1 = XOR(x1, U8TO32_LITTLE(m + 4)); + x2 = XOR(x2, U8TO32_LITTLE(m + 8)); + x3 = XOR(x3, U8TO32_LITTLE(m + 12)); + x4 = XOR(x4, U8TO32_LITTLE(m + 16)); + x5 = XOR(x5, U8TO32_LITTLE(m + 20)); + x6 = XOR(x6, U8TO32_LITTLE(m + 24)); + x7 = XOR(x7, U8TO32_LITTLE(m + 28)); + x8 = XOR(x8, U8TO32_LITTLE(m + 32)); + x9 = XOR(x9, U8TO32_LITTLE(m + 36)); + x10 = XOR(x10, U8TO32_LITTLE(m + 40)); + x11 = XOR(x11, U8TO32_LITTLE(m + 44)); + x12 = XOR(x12, U8TO32_LITTLE(m + 48)); + x13 = XOR(x13, U8TO32_LITTLE(m + 52)); + x14 = XOR(x14, U8TO32_LITTLE(m + 56)); + x15 = XOR(x15, U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if(!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0, x0); + U32TO8_LITTLE(c + 4, x1); + U32TO8_LITTLE(c + 8, x2); + U32TO8_LITTLE(c + 12, x3); + U32TO8_LITTLE(c + 16, x4); + U32TO8_LITTLE(c + 20, x5); + U32TO8_LITTLE(c + 24, x6); + U32TO8_LITTLE(c + 28, x7); + U32TO8_LITTLE(c + 32, x8); + U32TO8_LITTLE(c + 36, x9); + U32TO8_LITTLE(c + 40, x10); + U32TO8_LITTLE(c + 44, x11); + U32TO8_LITTLE(c + 48, x12); + U32TO8_LITTLE(c + 52, x13); + U32TO8_LITTLE(c + 56, x14); + U32TO8_LITTLE(c + 60, x15); + + if(bytes <= 64) { + if(bytes < 64) { + for(i = 0; i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} diff --git a/uppsrc/Core/SSH/libssh2/chacha.h b/uppsrc/Core/SSH/libssh2/chacha.h new file mode 100644 index 000000000..b17ecd5c6 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/chacha.h @@ -0,0 +1,33 @@ +/* $OpenBSD: chacha.h,v 1.4 2016/08/27 04:04:56 guenther Exp $ */ + +/* + * chacha-merged.c version 20080118 + * D. J. Bernstein + * Public domain. + * Copyright not intended 2024. + * + * SPDX-License-Identifier: SAX-PD-2.0 + */ + +#ifndef CHACHA_H +#define CHACHA_H + +#include + +struct chacha_ctx { + u_int input[16]; +}; + +#define CHACHA_MINKEYLEN 16 +#define CHACHA_NONCELEN 8 +#define CHACHA_CTRLEN 8 +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) +#define CHACHA_BLOCKLEN 64 + +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits); +void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr); +void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m, + u_char *c, u_int bytes); + +#endif /* CHACHA_H */ + diff --git a/uppsrc/Core/SSH/libssh2/channel.c b/uppsrc/Core/SSH/libssh2/channel.c index 78ed40e87..529c2ef82 100644 --- a/uppsrc/Core/SSH/libssh2/channel.c +++ b/uppsrc/Core/SSH/libssh2/channel.c @@ -1,7 +1,6 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2005 Mikhail Gusarov - * Copyright (c) 2008-2019 by Daniel Stenberg - * +/* Copyright (C) Sara Golemon + * Copyright (C) Mikhail Gusarov + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,16 +35,19 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" + #ifdef HAVE_UNISTD_H #include #endif -#include #ifdef HAVE_INTTYPES_H #include #endif + #include #include "channel.h" @@ -81,8 +83,8 @@ _libssh2_channel_nextid(LIBSSH2_SESSION * session) * told... */ session->next_channel = id + 1; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Allocated new channel ID#%lu", - id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Allocated new channel ID#%u", id)); return id; } @@ -154,9 +156,9 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, memset(&session->open_packet_requirev_state, 0, sizeof(session->open_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Opening Channel - win %d pack %d", window_size, - packet_size); + packet_size)); session->open_channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); if(!session->open_channel) { @@ -262,15 +264,15 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, _libssh2_ntohu32(session->open_data + 9); session->open_channel->local.packet_size = _libssh2_ntohu32(session->open_data + 13); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Connection Established - ID: %lu/%lu win: %lu/%lu" - " pack: %lu/%lu", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Connection Established - ID: %u/%u win: %u/%u" + " pack: %u/%u", session->open_channel->local.id, session->open_channel->remote.id, session->open_channel->local.window_size, session->open_channel->remote.window_size, session->open_channel->local.packet_size, - session->open_channel->remote.packet_size); + session->open_channel->remote.packet_size)); LIBSSH2_FREE(session, session->open_packet); session->open_packet = NULL; LIBSSH2_FREE(session, session->open_data); @@ -308,7 +310,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, } } - channel_error: +channel_error: if(session->open_data) { LIBSSH2_FREE(session, session->open_data); @@ -327,14 +329,14 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, /* Clear out packets meant for this channel */ _libssh2_htonu32(channel_id, session->open_channel->local.id); while((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, - &session->open_data, - &session->open_data_len, 1, - channel_id, 4) >= 0) - || - (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, - &session->open_data, - &session->open_data_len, 1, - channel_id, 4) >= 0)) { + &session->open_data, + &session->open_data_len, 1, + channel_id, 4) >= 0) + || + (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, + &session->open_data, + &session->open_data_len, 1, + channel_id, 4) >= 0)) { LIBSSH2_FREE(session, session->open_data); session->open_data = NULL; } @@ -390,9 +392,9 @@ channel_direct_tcpip(LIBSSH2_SESSION * session, const char *host, session->direct_message_len = session->direct_host_len + session->direct_shost_len + 16; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Requesting direct-tcpip session from %s:%d to %s:%d", - shost, sport, host, port); + shost, sport, host, port)); s = session->direct_message = LIBSSH2_ALLOC(session, session->direct_message_len); @@ -452,6 +454,85 @@ libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, return ptr; } +/* + * libssh2_channel_direct_streamlocal_ex + * + * Tunnel TCP/IP connect through the SSH session to direct UNIX socket + */ +static LIBSSH2_CHANNEL * +channel_direct_streamlocal(LIBSSH2_SESSION * session, const char *socket_path, + const char *shost, int sport) +{ + LIBSSH2_CHANNEL *channel; + unsigned char *s; + + if(session->direct_state == libssh2_NB_state_idle) { + session->direct_host_len = strlen(socket_path); + session->direct_shost_len = strlen(shost); + session->direct_message_len = + session->direct_host_len + session->direct_shost_len + 12; + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Requesting direct-streamlocal session to %s", + socket_path)); + + s = session->direct_message = + LIBSSH2_ALLOC(session, session->direct_message_len); + if(!session->direct_message) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for direct-streamlocal connection"); + return NULL; + } + _libssh2_store_str(&s, socket_path, session->direct_host_len); + _libssh2_store_str(&s, shost, session->direct_shost_len); + _libssh2_store_u32(&s, sport); + } + + channel = + _libssh2_channel_open(session, "direct-streamlocal@openssh.com", + sizeof("direct-streamlocal@openssh.com") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, + session->direct_message, + session->direct_message_len); + + if(!channel && + libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { + /* The error code is still set to LIBSSH2_ERROR_EAGAIN, set our state + to created to avoid re-creating the package on next invoke */ + session->direct_state = libssh2_NB_state_created; + return NULL; + } + /* by default we set (keep?) idle state... */ + session->direct_state = libssh2_NB_state_idle; + + LIBSSH2_FREE(session, session->direct_message); + session->direct_message = NULL; + + return channel; +} + +/* + * libssh2_channel_direct_streamlocal_ex + * + * Tunnel TCP/IP connect through the SSH session to direct UNIX socket + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_direct_streamlocal_ex(LIBSSH2_SESSION * session, + const char *socket_path, + const char *shost, int sport) +{ + LIBSSH2_CHANNEL *ptr; + + if(!session) + return NULL; + + BLOCK_ADJUST_ERRNO(ptr, session, + channel_direct_streamlocal(session, + socket_path, shost, sport)); + return ptr; +} + /* * channel_forward_listen * @@ -470,19 +551,20 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host, host = "0.0.0.0"; if(session->fwdLstn_state == libssh2_NB_state_idle) { - session->fwdLstn_host_len = strlen(host); + session->fwdLstn_host_len = (uint32_t)strlen(host); /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */ session->fwdLstn_packet_len = - session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14; + session->fwdLstn_host_len + + (uint32_t)(sizeof("tcpip-forward") - 1) + 14; /* Zero the whole thing out */ memset(&session->fwdLstn_packet_requirev_state, 0, sizeof(session->fwdLstn_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Requesting tcpip-forward session for %s:%d", host, - port); + port)); s = session->fwdLstn_packet = LIBSSH2_ALLOC(session, session->fwdLstn_packet_len); @@ -567,10 +649,10 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host, listener->host[session->fwdLstn_host_len] = 0; if(data_len >= 5 && !port) { listener->port = _libssh2_ntohu32(data + 1); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Dynamic tcpip-forward port " "allocated: %d", - listener->port); + listener->port)); } else listener->port = port; @@ -647,9 +729,9 @@ int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener) int retcode = 0; if(listener->chanFwdCncl_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Cancelling tcpip-forward session for %s:%d", - listener->host, listener->port); + listener->host, listener->port)); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { @@ -818,10 +900,10 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel, memset(&channel->setenv_packet_requirev_state, 0, sizeof(channel->setenv_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Setting remote environment variable: %s=%s on " - "channel %lu/%lu", - varname, value, channel->local.id, channel->remote.id); + "channel %u/%u", + varname, value, channel->local.id, channel->remote.id)); s = channel->setenv_packet = LIBSSH2_ALLOC(session, channel->setenv_packet_len); @@ -877,7 +959,9 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel, } if(rc) { channel->setenv_state = libssh2_NB_state_idle; - return rc; + return _libssh2_error(session, rc, + "Failed getting response for " + "channel-setenv"); } else if(data_len < 1) { channel->setenv_state = libssh2_NB_state_idle; @@ -951,9 +1035,9 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel, memset(&channel->reqPTY_packet_requirev_state, 0, sizeof(channel->reqPTY_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Allocating tty on channel %lu/%lu", channel->local.id, - channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Allocating tty on channel %u/%u", channel->local.id, + channel->remote.id)); s = channel->reqPTY_packet; @@ -1054,9 +1138,9 @@ static int channel_request_auth_agent(LIBSSH2_CHANNEL *channel, memset(&channel->req_auth_agent_requirev_state, 0, sizeof(channel->req_auth_agent_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting auth agent on channel %lu/%lu", - channel->local.id, channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Requesting auth agent on channel %u/%u", + channel->local.id, channel->remote.id)); /* * byte SSH_MSG_CHANNEL_REQUEST @@ -1083,6 +1167,7 @@ static int channel_request_auth_agent(LIBSSH2_CHANNEL *channel, if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, rc, "Would block sending auth-agent request"); + return rc; } else if(rc) { channel->req_auth_agent_state = libssh2_NB_state_idle; @@ -1099,10 +1184,10 @@ static int channel_request_auth_agent(LIBSSH2_CHANNEL *channel, size_t data_len; unsigned char code; - rc = _libssh2_packet_requirev( - session, reply_codes, &data, &data_len, 1, - channel->req_auth_agent_local_channel, - 4, &channel->req_auth_agent_requirev_state); + rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, + 1, channel->req_auth_agent_local_channel, + 4, + &channel->req_auth_agent_requirev_state); if(rc == LIBSSH2_ERROR_EAGAIN) { return rc; } @@ -1125,13 +1210,14 @@ static int channel_request_auth_agent(LIBSSH2_CHANNEL *channel, "Unable to complete request for auth-agent"); } -/** +/* * libssh2_channel_request_auth_agent + * * Requests that agent forwarding be enabled for the session. The * request must be sent over a specific channel, which starts the agent * listener on the remote side. Once the channel is closed, the agent * listener continues to exist. - * */ + */ LIBSSH2_API int libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel) { @@ -1140,6 +1226,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 +1240,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 +1252,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; @@ -1212,10 +1302,10 @@ channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width, memset(&channel->reqPTY_packet_requirev_state, 0, sizeof(channel->reqPTY_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "changing tty size on channel %lu/%lu", - channel->local.id, - channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "changing tty size on channel %u/%u", + channel->local.id, + channel->remote.id)); s = channel->reqPTY_packet; @@ -1301,13 +1391,13 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, memset(&channel->reqX11_packet_requirev_state, 0, sizeof(channel->reqX11_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Requesting x11-req for channel %lu/%lu: single=%d " + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Requesting x11-req for channel %u/%u: single=%d " "proto=%s cookie=%s screen=%d", channel->local.id, channel->remote.id, single_connection, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", - auth_cookie ? auth_cookie : "", screen_number); + auth_cookie ? auth_cookie : "", screen_number)); s = channel->reqX11_packet = LIBSSH2_ALLOC(session, channel->reqX11_packet_len); @@ -1326,7 +1416,7 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, _libssh2_store_str(&s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len); - _libssh2_store_u32(&s, cookie_len); + _libssh2_store_u32(&s, (uint32_t)cookie_len); if(auth_cookie) { memcpy(s, auth_cookie, cookie_len); } @@ -1459,10 +1549,10 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, if(message) channel->process_packet_len += + 4; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "starting request(%s) on channel %lu/%lu, message=%s", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "starting request(%s) on channel %u/%u, message=%s", request, channel->local.id, channel->remote.id, - message ? message : ""); + message ? message : "")); s = channel->process_packet = LIBSSH2_ALLOC(session, channel->process_packet_len); if(!channel->process_packet) @@ -1476,7 +1566,7 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, *(s++) = 0x01; if(message) - _libssh2_store_u32(&s, message_len); + _libssh2_store_u32(&s, (uint32_t)message_len); channel->process_state = libssh2_NB_state_created; } @@ -1567,7 +1657,7 @@ LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking) { if(channel) - (void) _libssh2_session_set_blocking(channel->session, blocking); + (void)_libssh2_session_set_blocking(channel->session, blocking); } /* @@ -1591,8 +1681,8 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) if(packet->data_len < 1) { packet = next; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); continue; } @@ -1628,11 +1718,11 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) size_t bytes_to_flush = packet->data_len - packet->data_head; - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Flushing %d bytes of data from stream " - "%lu on channel %lu/%lu", - bytes_to_flush, packet_stream_id, - channel->local.id, channel->remote.id); + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, + "Flushing %ld bytes of data from stream " + "%d on channel %u/%u", + (long)bytes_to_flush, packet_stream_id, + channel->local.id, channel->remote.id)); /* It's one of the streams we wanted to flush */ channel->flush_refund_bytes += packet->data_len - 13; @@ -1652,20 +1742,20 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) } channel->read_avail -= channel->flush_flush_bytes; - channel->remote.window_size -= channel->flush_flush_bytes; + channel->remote.window_size -= (uint32_t)channel->flush_flush_bytes; if(channel->flush_refund_bytes) { int rc = _libssh2_channel_receive_window_adjust(channel, - channel->flush_refund_bytes, - 1, NULL); + (uint32_t)channel->flush_refund_bytes, + 1, NULL); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; } channel->flush_state = libssh2_NB_state_idle; - return channel->flush_flush_bytes; + return (int)channel->flush_flush_bytes; } /* @@ -1734,7 +1824,7 @@ libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, *exitsignal = LIBSSH2_ALLOC(session, namelen + 1); if(!*exitsignal) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for signal name"); + "Unable to allocate memory for signal name"); } memcpy(*exitsignal, channel->exit_signal, namelen); (*exitsignal)[namelen] = '\0'; @@ -1791,10 +1881,10 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, if(!force && (adjustment + channel->adjust_queue < LIBSSH2_CHANNEL_MINADJUST)) { - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Queueing %lu bytes for receive window adjustment " - "for channel %lu/%lu", - adjustment, channel->local.id, channel->remote.id); + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, + "Queueing %u bytes for receive window adjustment " + "for channel %u/%u", + adjustment, channel->local.id, channel->remote.id)); channel->adjust_queue += adjustment; return 0; } @@ -1810,10 +1900,10 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; _libssh2_htonu32(&channel->adjust_adjust[1], channel->remote.id); _libssh2_htonu32(&channel->adjust_adjust[5], adjustment); - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Adjusting window %lu bytes for data on " - "channel %lu/%lu", - adjustment, channel->local.id, channel->remote.id); + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, + "Adjusting window %u bytes for data on " + "channel %u/%u", + adjustment, channel->local.id, channel->remote.id)); channel->adjust_state = libssh2_NB_state_created; } @@ -1840,10 +1930,9 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, return 0; } +#ifndef LIBSSH2_NO_DEPRECATED /* - * libssh2_channel_receive_window_adjust - * - * DEPRECATED + * libssh2_channel_receive_window_adjust (DEPRECATED, DO NOT USE!) * * Adjust the receive window for a channel by adjustment bytes. If the amount * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the @@ -1865,13 +1954,15 @@ libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, return (unsigned long)LIBSSH2_ERROR_BAD_USE; BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, adj, + _libssh2_channel_receive_window_adjust(channel, + (uint32_t)adj, force, &window)); /* stupid - but this is how it was made to work before and this is just kept for backwards compatibility */ return rc ? (unsigned long)rc : window; } +#endif /* * libssh2_channel_receive_window_adjust2 @@ -1896,8 +1987,9 @@ libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, return LIBSSH2_ERROR_BAD_USE; BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, adj, force, - window)); + _libssh2_channel_receive_window_adjust(channel, + (uint32_t)adj, + force, window)); return rc; } @@ -1905,10 +1997,10 @@ int _libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) { if(channel->extData2_state == libssh2_NB_state_idle) { - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Setting channel %lu/%lu handle_extended_data" + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, + "Setting channel %u/%u handle_extended_data" " mode to %d", - channel->local.id, channel->remote.id, ignore_mode); + channel->local.id, channel->remote.id, ignore_mode)); channel->remote.extended_data_ignore_mode = (char)ignore_mode; channel->extData2_state = libssh2_NB_state_created; @@ -1929,7 +2021,7 @@ _libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) } /* - * libssh2_channel_handle_extended_data2() + * libssh2_channel_handle_extended_data2 * */ LIBSSH2_API int @@ -1946,10 +2038,9 @@ libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, return rc; } +#ifndef LIBSSH2_NO_DEPRECATED /* - * libssh2_channel_handle_extended_data - * - * DEPRECATED DO NOTE USE! + * libssh2_channel_handle_extended_data (DEPRECATED, DO NOT USE!) * * How should extended data look to the calling app? Keep it in separate * channels[_read() _read_stdder()]? (NORMAL) Merge the extended data to the @@ -1962,7 +2053,7 @@ libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, { (void)libssh2_channel_handle_extended_data2(channel, ignore_mode); } - +#endif /* @@ -1988,19 +2079,19 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, LIBSSH2_PACKET *read_packet; LIBSSH2_PACKET *read_next; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "channel_read() wants %d bytes from channel %lu/%lu " + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "channel_read() wants %ld bytes from channel %u/%u " "stream #%d", - (int) buflen, channel->local.id, channel->remote.id, - stream_id); + (long)buflen, channel->local.id, channel->remote.id, + stream_id)); /* expand the receiving window first if it has become too narrow */ if((channel->read_state == libssh2_NB_state_jump1) || (channel->remote.window_size < - channel->remote.window_size_initial / 4 * 3 + buflen) ) { + channel->remote.window_size_initial / 4 * 3 + buflen)) { - uint32_t adjustment = channel->remote.window_size_initial + buflen - - channel->remote.window_size; + uint32_t adjustment = (uint32_t)(channel->remote.window_size_initial + + buflen - channel->remote.window_size); if(adjustment < LIBSSH2_CHANNEL_MINADJUST) adjustment = LIBSSH2_CHANNEL_MINADJUST; @@ -2041,8 +2132,13 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, if(readpkt->data_len < 5) { read_packet = read_next; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + + if(readpkt->data_len != 1 || + readpkt->data[0] != SSH_MSG_REQUEST_FAILURE) { + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); + } + continue; } @@ -2080,11 +2176,11 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, unlink_packet = TRUE; } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "channel_read() got %d of data from %lu/%lu/%d%s", - bytes_want, channel->local.id, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "channel_read() got %ld of data from %u/%u/%d%s", + (long)bytes_want, channel->local.id, channel->remote.id, stream_id, - unlink_packet?" [ul]":""); + unlink_packet ? " [ul]" : "")); /* copy data from this struct to the target buffer */ memcpy(&buf[bytes_read], @@ -2123,7 +2219,7 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, } channel->read_avail -= bytes_read; - channel->remote.window_size -= bytes_read; + channel->remote.window_size -= (uint32_t)bytes_read; return bytes_read; } @@ -2146,7 +2242,7 @@ LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen) { - int rc; + ssize_t rc; unsigned long recv_window; if(!channel) @@ -2156,8 +2252,8 @@ libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, if(buflen > recv_window) { BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, buflen, - 1, NULL)); + _libssh2_channel_receive_window_adjust(channel, + (uint32_t)buflen, 1, NULL)); } BLOCK_ADJUST(rc, channel->session, @@ -2180,7 +2276,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) uint32_t read_local_id; read_packet = _libssh2_list_first(&session->packets); - if(read_packet == NULL) + if(!read_packet) return 0; while(read_packet) { @@ -2189,8 +2285,8 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) if(read_packet->data_len < 5) { read_packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); continue; } @@ -2218,7 +2314,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) && (channel->local.id == read_local_id) && (channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) { - return (read_packet->data_len - read_packet->data_head); + return read_packet->data_len - read_packet->data_head; } read_packet = next_packet; @@ -2258,15 +2354,15 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, if(channel->write_state == libssh2_NB_state_idle) { unsigned char *s = channel->write_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, - "Writing %d bytes on channel %lu/%lu, stream #%d", - (int) buflen, channel->local.id, channel->remote.id, - stream_id); + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, + "Writing %ld bytes on channel %u/%u, stream #%d", + (long)buflen, channel->local.id, channel->remote.id, + stream_id)); if(channel->local.close) return _libssh2_error(channel->session, LIBSSH2_ERROR_CHANNEL_CLOSED, - "We've already closed this channel"); + "We have already closed this channel"); else if(channel->local.eof) return _libssh2_error(channel->session, LIBSSH2_ERROR_CHANNEL_EOF_SENT, @@ -2293,7 +2389,7 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, */ session->socket_block_directions = LIBSSH2_SESSION_BLOCK_INBOUND; - return (rc == LIBSSH2_ERROR_EAGAIN?rc:0); + return rc == LIBSSH2_ERROR_EAGAIN ? rc : 0; } channel->write_bufwrite = buflen; @@ -2307,30 +2403,30 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, /* Don't exceed the remote end's limits */ /* REMEMBER local means local as the SOURCE of the data */ if(channel->write_bufwrite > channel->local.window_size) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Splitting write block due to %lu byte " - "window_size on %lu/%lu/%d", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Splitting write block due to %u byte " + "window_size on %u/%u/%d", channel->local.window_size, channel->local.id, - channel->remote.id, stream_id); + channel->remote.id, stream_id)); channel->write_bufwrite = channel->local.window_size; } if(channel->write_bufwrite > channel->local.packet_size) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Splitting write block due to %lu byte " - "packet_size on %lu/%lu/%d", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Splitting write block due to %u byte " + "packet_size on %u/%u/%d", channel->local.packet_size, channel->local.id, - channel->remote.id, stream_id); + channel->remote.id, stream_id)); channel->write_bufwrite = channel->local.packet_size; } /* store the size here only, the buffer is passed in as-is to _libssh2_transport_send() */ - _libssh2_store_u32(&s, channel->write_bufwrite); + _libssh2_store_u32(&s, (uint32_t)channel->write_bufwrite); channel->write_packet_len = s - channel->write_packet; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Sending %d bytes on channel %lu/%lu, stream_id=%d", - (int) channel->write_bufwrite, channel->local.id, - channel->remote.id, stream_id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Sending %ld bytes on channel %u/%u, stream_id=%d", + (long)channel->write_bufwrite, channel->local.id, + channel->remote.id, stream_id)); channel->write_state = libssh2_NB_state_created; } @@ -2349,7 +2445,7 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, "Unable to send channel data"); } /* Shrink local window size */ - channel->local.window_size -= channel->write_bufwrite; + channel->local.window_size -= (uint32_t)channel->write_bufwrite; wrote += channel->write_bufwrite; @@ -2402,9 +2498,9 @@ static int channel_send_eof(LIBSSH2_CHANNEL *channel) unsigned char packet[5]; /* packet_type(1) + channelno(4) */ int rc; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Sending EOF on channel %lu/%lu", - channel->local.id, channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Sending EOF on channel %u/%u", + channel->local.id, channel->remote.id)); packet[0] = SSH_MSG_CHANNEL_EOF; _libssh2_htonu32(packet + 1, channel->remote.id); rc = _libssh2_transport_send(session, packet, 5, NULL, 0); @@ -2463,8 +2559,8 @@ libssh2_channel_eof(LIBSSH2_CHANNEL * channel) if(packet->data_len < 1) { packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); continue; } @@ -2492,9 +2588,9 @@ static int channel_wait_eof(LIBSSH2_CHANNEL *channel) int rc; if(channel->wait_eof_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Awaiting EOF for channel %lu/%lu", channel->local.id, - channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Awaiting EOF for channel %u/%u", channel->local.id, + channel->remote.id)); channel->wait_eof_state = libssh2_NB_state_created; } @@ -2521,7 +2617,7 @@ static int channel_wait_eof(LIBSSH2_CHANNEL *channel) else if(rc < 0) { channel->wait_eof_state = libssh2_NB_state_idle; return _libssh2_error(session, rc, - "_libssh2_transport_read() bailed out!"); + "_libssh2_transport_read() bailed out"); } } while(1); @@ -2566,7 +2662,7 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel) return rc; } _libssh2_error(session, rc, - "Unable to send EOF, but closing channel anyway"); + "Unable to send EOF, but closing channel anyway"); } } @@ -2574,8 +2670,8 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel) late for us to wait for it. Continue closing! */ if(channel->close_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Closing channel %lu/%lu", - channel->local.id, channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Closing channel %u/%u", + channel->local.id, channel->remote.id)); channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE; _libssh2_htonu32(channel->close_packet + 1, channel->remote.id); @@ -2643,7 +2739,7 @@ libssh2_channel_close(LIBSSH2_CHANNEL *channel) if(!channel) return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel) ); + BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel)); return rc; } @@ -2664,9 +2760,9 @@ static int channel_wait_closed(LIBSSH2_CHANNEL *channel) } if(channel->wait_closed_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Awaiting close of channel %lu/%lu", channel->local.id, - channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Awaiting close of channel %u/%u", channel->local.id, + channel->remote.id)); channel->wait_closed_state = libssh2_NB_state_created; } @@ -2727,9 +2823,9 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel) assert(session); if(channel->free_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Freeing channel %lu/%lu resources", channel->local.id, - channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Freeing channel %u/%u resources", channel->local.id, + channel->remote.id)); channel->free_state = libssh2_NB_state_created; } @@ -2761,10 +2857,10 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel) /* Clear out packets meant for this channel */ _libssh2_htonu32(channel_id, channel->local.id); while((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, &data, - &data_len, 1, channel_id, 4) >= 0) - || - (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, - &data_len, 1, channel_id, 4) >= 0)) { + &data_len, 1, channel_id, 4) >= 0) + || + (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, + &data_len, 1, channel_id, 4) >= 0)) { LIBSSH2_FREE(session, data); } @@ -2824,7 +2920,7 @@ libssh2_channel_free(LIBSSH2_CHANNEL *channel) */ LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, - unsigned long *read_avail, + /* FIXME: -> size_t */ unsigned long *read_avail, unsigned long *window_size_initial) { if(!channel) @@ -2846,8 +2942,8 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, if(packet->data_len < 1) { packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); continue; } @@ -2864,7 +2960,7 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, packet = next_packet; } - *read_avail = bytes_queued; + *read_avail = (unsigned long)bytes_queued; } return channel->remote.window_size; @@ -2893,3 +2989,87 @@ libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, return channel->local.window_size; } + +/* A signal can be delivered to the remote process/service using the + following message. Some systems may not implement signals, in which + case they SHOULD ignore this message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "signal" + boolean FALSE + string signal name (without the "SIG" prefix) + + 'signal name' values will be encoded as discussed in the passage + describing SSH_MSG_CHANNEL_REQUEST messages using "exit-signal" in + this section. + */ +static int channel_signal(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len) +{ + LIBSSH2_SESSION *session = channel->session; + int retcode = LIBSSH2_ERROR_PROTO; + + if(channel->sendsignal_state == libssh2_NB_state_idle) { + unsigned char *s; + + /* 20 = packet_type(1) + channel(4) + + signal_len + sizeof(signal) - 1 + want_reply(1) + + signame_len_len(4) */ + channel->sendsignal_packet_len = 20 + signame_len; + + s = channel->sendsignal_packet = + LIBSSH2_ALLOC(session, channel->sendsignal_packet_len); + if(!channel->sendsignal_packet) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "signal request"); + + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, "signal", sizeof("signal") - 1); + *(s++) = 0x00; /* Don't reply */ + _libssh2_store_str(&s, signame, signame_len); + + channel->sendsignal_state = libssh2_NB_state_created; + } + + if(channel->sendsignal_state == libssh2_NB_state_created) { + int rc; + + rc = _libssh2_transport_send(session, channel->sendsignal_packet, + channel->sendsignal_packet_len, + NULL, 0); + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, "Would block sending signal request"); + return rc; + } + else if(rc) { + LIBSSH2_FREE(session, channel->sendsignal_packet); + channel->sendsignal_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, "Unable to send signal packet"); + } + LIBSSH2_FREE(session, channel->sendsignal_packet); + retcode = LIBSSH2_ERROR_NONE; + } + + channel->sendsignal_state = libssh2_NB_state_idle; + + return retcode; +} + +LIBSSH2_API int +libssh2_channel_signal_ex(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + channel_signal(channel, signame, signame_len)); + return rc; +} diff --git a/uppsrc/Core/SSH/libssh2/channel.h b/uppsrc/Core/SSH/libssh2/channel.h index dc0ee3764..709ec0615 100644 --- a/uppsrc/Core/SSH/libssh2/channel.h +++ b/uppsrc/Core/SSH/libssh2/channel.h @@ -1,6 +1,6 @@ -#ifndef __LIBSSH2_CHANNEL_H -#define __LIBSSH2_CHANNEL_H -/* Copyright (c) 2008-2010 by Daniel Stenberg +#ifndef LIBSSH2_CHANNEL_H +#define LIBSSH2_CHANNEL_H +/* Copyright (C) Daniel Stenberg * * All rights reserved. * @@ -36,6 +36,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* @@ -137,5 +139,4 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel); */ int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); -#endif /* __LIBSSH2_CHANNEL_H */ - +#endif /* LIBSSH2_CHANNEL_H */ diff --git a/uppsrc/Core/SSH/libssh2/cipher-chachapoly.c b/uppsrc/Core/SSH/libssh2/cipher-chachapoly.c new file mode 100644 index 000000000..9e4b11700 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/cipher-chachapoly.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2013 Damien Miller + * + * Adapted by Will Cosgrove for libssh2 + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* $OpenBSD: cipher-chachapoly.c,v 1.8 2016/08/03 05:41:57 djm Exp $ */ + +#include "libssh2_priv.h" +#include "misc.h" +#include "cipher-chachapoly.h" + +int +chachapoly_timingsafe_bcmp(const void *b1, const void *b2, size_t n); + +int +chachapoly_init(struct chachapoly_ctx *ctx, const u_char *key, u_int keylen) +{ + if(keylen != (32 + 32)) /* 2 x 256 bit keys */ + return LIBSSH2_ERROR_INVAL; + chacha_keysetup(&ctx->main_ctx, key, 256); + chacha_keysetup(&ctx->header_ctx, key + 32, 256); + return 0; +} + +/* + * chachapoly_crypt() operates as following: + * En/decrypt with header key 'aadlen' bytes from 'src', storing result + * to 'dest'. The ciphertext here is treated as additional authenticated + * data for MAC calculation. + * En/decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. Use + * POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the authentication + * tag. This tag is written on encryption and verified on decryption. + */ +int +chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest, + const u_char *src, u_int len, u_int aadlen, int do_encrypt) +{ + u_char seqbuf[8]; + const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */ + u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; + int r = LIBSSH2_ERROR_INVAL; + unsigned char *ptr = NULL; + + /* + * Run ChaCha20 once to generate the Poly1305 key. The IV is the + * packet sequence number. + */ + memset(poly_key, 0, sizeof(poly_key)); + ptr = &seqbuf[0]; + _libssh2_store_u64(&ptr, seqnr); + chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->main_ctx, + poly_key, poly_key, sizeof(poly_key)); + + /* If decrypting, check tag before anything else */ + if(!do_encrypt) { + const u_char *tag = src + aadlen + len; + + poly1305_auth(expected_tag, src, aadlen + len, poly_key); + if(chachapoly_timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) + != 0) { + r = LIBSSH2_ERROR_DECRYPT; + goto out; + } + } + + /* Crypt additional data */ + if(aadlen) { + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); + } + + /* Set Chacha's block counter to 1 */ + chacha_ivsetup(&ctx->main_ctx, seqbuf, one); + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, + dest + aadlen, len); + + /* If encrypting, calculate and append tag */ + if(do_encrypt) { + poly1305_auth(dest + aadlen + len, dest, aadlen + len, + poly_key); + } + r = 0; +out: + memset(expected_tag, 0, sizeof(expected_tag)); + memset(seqbuf, 0, sizeof(seqbuf)); + memset(poly_key, 0, sizeof(poly_key)); + return r; +} + +/* Decrypt and extract the encrypted packet length */ +int +chachapoly_get_length(struct chachapoly_ctx *ctx, unsigned int *plenp, + unsigned int seqnr, const unsigned char *cp, + unsigned int len) +{ + u_char buf[4], seqbuf[8]; + unsigned char *ptr = NULL; + + if(len < 4) + return -1; + ptr = &seqbuf[0]; + _libssh2_store_u64(&ptr, seqnr); + chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, cp, buf, 4); + *plenp = _libssh2_ntohu32(buf); + return 0; +} + +int +chachapoly_timingsafe_bcmp(const void *b1, const void *b2, size_t n) +{ + const unsigned char *p1 = b1, *p2 = b2; + int ret = 0; + + for(; n > 0; n--) + ret |= *p1++ ^ *p2++; + return (ret != 0); +} diff --git a/uppsrc/Core/SSH/libssh2/cipher-chachapoly.h b/uppsrc/Core/SSH/libssh2/cipher-chachapoly.h new file mode 100644 index 000000000..4d0015cb7 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/cipher-chachapoly.h @@ -0,0 +1,41 @@ +/* $OpenBSD: cipher-chachapoly.h,v 1.4 2014/06/24 01:13:21 djm Exp $ */ + +/* + * Copyright (c) Damien Miller 2013 + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#ifndef CHACHA_POLY_AEAD_H +#define CHACHA_POLY_AEAD_H + +#include "chacha.h" +#include "poly1305.h" + +#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ + +struct chachapoly_ctx { + struct chacha_ctx main_ctx, header_ctx; +}; + +int chachapoly_init(struct chachapoly_ctx *cpctx, + const u_char *key, u_int keylen); +int chachapoly_crypt(struct chachapoly_ctx *cpctx, u_int seqnr, + u_char *dest, const u_char *src, u_int len, u_int aadlen, + int do_encrypt); +int chachapoly_get_length(struct chachapoly_ctx *cpctx, + u_int *plenp, u_int seqnr, const u_char *cp, + u_int len); + +#endif /* CHACHA_POLY_AEAD_H */ diff --git a/uppsrc/Core/SSH/libssh2/comp.c b/uppsrc/Core/SSH/libssh2/comp.c index ab80b36e2..af3bcc033 100644 --- a/uppsrc/Core/SSH/libssh2/comp.c +++ b/uppsrc/Core/SSH/libssh2/comp.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2007, 2019, Sara Golemon - * Copyright (c) 2010-2014, Daniel Stenberg +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,13 +34,15 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #ifdef LIBSSH2_HAVE_ZLIB -#include UPP_ZLIB_INCLUDE /* Upp-SSH: Patched, 11/17/2020 */ -#undef compress /* dodge name clash with ZLIB macro */ +#include UPP_ZLIB_INCLUDE +#undef compress /* dodge name clash with ZLIB macro */ #endif #include "comp.h" @@ -62,12 +64,12 @@ comp_method_none_comp(LIBSSH2_SESSION *session, size_t src_len, void **abstract) { - (void) session; - (void) abstract; - (void) dest; - (void) dest_len; - (void) src; - (void) src_len; + (void)session; + (void)abstract; + (void)dest; + (void)dest_len; + (void)src; + (void)src_len; return 0; } @@ -85,9 +87,9 @@ comp_method_none_decomp(LIBSSH2_SESSION * session, const unsigned char *src, size_t src_len, void **abstract) { - (void) session; - (void) payload_limit; - (void) abstract; + (void)session; + (void)payload_limit; + (void)abstract; *dest = (unsigned char *) src; *dest_len = src_len; return 0; @@ -164,8 +166,8 @@ comp_method_zlib_init(LIBSSH2_SESSION * session, int compr, if(status != Z_OK) { LIBSSH2_FREE(session, strm); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "unhandled zlib error %d", status)); return LIBSSH2_ERROR_COMPRESS; } *abstract = strm; @@ -190,11 +192,11 @@ comp_method_zlib_comp(LIBSSH2_SESSION *session, void **abstract) { z_stream *strm = *abstract; - int out_maxlen = *dest_len; + uInt out_maxlen = (uInt)*dest_len; int status; strm->next_in = (unsigned char *) src; - strm->avail_in = src_len; + strm->avail_in = (uInt)src_len; strm->next_out = dest; strm->avail_out = out_maxlen; @@ -205,9 +207,9 @@ comp_method_zlib_comp(LIBSSH2_SESSION *session, return 0; } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib compression error %d, avail_out", - status, strm->avail_out); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "unhandled zlib compression error %d, avail_out %u", + status, strm->avail_out)); return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compression failure"); } @@ -228,17 +230,17 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session, /* A short-term alloc of a full data chunk is better than a series of reallocs */ char *out; - size_t out_maxlen = src_len; + size_t out_maxlen; if(src_len <= SIZE_MAX / 4) - out_maxlen = src_len * 4; + out_maxlen = (uInt)src_len * 4; else out_maxlen = payload_limit; /* If strm is null, then we have not yet been initialized. */ - if(strm == NULL) + if(!strm) return _libssh2_error(session, LIBSSH2_ERROR_COMPRESS, - "decompression uninitialized");; + "decompression uninitialized"); /* In practice they never come smaller than this */ if(out_maxlen < 25) @@ -248,10 +250,11 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session, out_maxlen = payload_limit; strm->next_in = (unsigned char *) src; - strm->avail_in = src_len; - strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen); + strm->avail_in = (uInt)src_len; + strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, + (uInt)out_maxlen); out = (char *) strm->next_out; - strm->avail_out = out_maxlen; + strm->avail_out = (uInt)out_maxlen; if(!strm->next_out) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate decompression buffer"); @@ -277,8 +280,8 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session, else { /* error state */ LIBSSH2_FREE(session, out); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "unhandled zlib error %d", status)); return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, "decompression failure"); } @@ -300,7 +303,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session, } out = newout; strm->next_out = (unsigned char *) out + out_ofs; - strm->avail_out = out_maxlen - out_ofs; + strm->avail_out = (uInt)(out_maxlen - out_ofs); } *dest = (unsigned char *) out; diff --git a/uppsrc/Core/SSH/libssh2/comp.h b/uppsrc/Core/SSH/libssh2/comp.h index 82ac2dc95..6a35d6949 100644 --- a/uppsrc/Core/SSH/libssh2/comp.h +++ b/uppsrc/Core/SSH/libssh2/comp.h @@ -1,6 +1,6 @@ -#ifndef __LIBSSH2_COMP_H -#define __LIBSSH2_COMP_H -/* Copyright (C) 2009-2010 by Daniel Stenberg +#ifndef LIBSSH2_COMP_H +#define LIBSSH2_COMP_H +/* Copyright (C) Daniel Stenberg * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -35,10 +35,11 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(LIBSSH2_SESSION *session); -#endif /* __LIBSSH2_COMP_H */ +#endif /* LIBSSH2_COMP_H */ diff --git a/uppsrc/Core/SSH/libssh2/crypt.c b/uppsrc/Core/SSH/libssh2/crypt.c index 8d493b484..6c816eb44 100644 --- a/uppsrc/Core/SSH/libssh2/crypt.c +++ b/uppsrc/Core/SSH/libssh2/crypt.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2009, 2010 Simon Josefsson - * Copyright (c) 2004-2007, Sara Golemon +/* Copyright (C) Simon Josefsson + * Copyright (C) Sara Golemon * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,18 +34,36 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" +#include "cipher-chachapoly.h" -#ifdef LIBSSH2_CRYPT_NONE +#include +#if defined(LIBSSH2DEBUG) && defined(LIBSSH2_CRYPT_NONE_INSECURE) /* crypt_none_crypt - * Minimalist cipher: VERY secure *wink* + * Minimalist cipher: no encryption. DO NOT USE. + * + * The SSH2 Transport allows for unencrypted data transmission using + * the "none" cipher. Because this is such a huge security hole, it is + * typically disabled on SSH2 implementations and is disabled in libssh2 + * by default as well. + * + * Enabling this option will allow for "none" as a negotiable method, + * however it still requires that the method be advertised by the remote + * end and that no more-preferable methods are available. + * */ static int -crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf, - void **abstract) +crypt_none_crypt(LIBSSH2_SESSION * session, + unsigned int seqno, + unsigned char *buf, + size_t buf_len, + void **abstract, + int firstlast) { /* Do nothing to the data! */ return 0; @@ -62,13 +80,14 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = { crypt_none_crypt, NULL }; -#endif /* LIBSSH2_CRYPT_NONE */ +#endif /* defined(LIBSSH2DEBUG) && defined(LIBSSH2_CRYPT_NONE_INSECURE) */ struct crypt_ctx { int encrypt; _libssh2_cipher_type(algo); _libssh2_cipher_ctx h; + struct chachapoly_ctx chachapoly_ctx; }; static int @@ -96,13 +115,18 @@ crypt_init(LIBSSH2_SESSION * session, } static int -crypt_encrypt(LIBSSH2_SESSION * session, unsigned char *block, - size_t blocksize, void **abstract) +crypt_encrypt(LIBSSH2_SESSION * session, + unsigned int seqno, + unsigned char *buf, + size_t buf_len, + void **abstract, + int firstlast) { struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; (void) session; - return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block, - blocksize); + (void) seqno; + return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, buf, + buf_len, firstlast); } static int @@ -117,6 +141,38 @@ crypt_dtor(LIBSSH2_SESSION * session, void **abstract) return 0; } +#if LIBSSH2_AES_GCM +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_gcm = { + "aes256-gcm@openssh.com", + "", + 16, /* blocksize */ + 12, /* initial value length */ + 32, /* secret length -- 32*8 == 256bit */ + 16, /* length of the authentication tag */ + LIBSSH2_CRYPT_FLAG_INTEGRATED_MAC | LIBSSH2_CRYPT_FLAG_PKTLEN_AAD, + &crypt_init, + NULL, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes256gcm +}; + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_gcm = { + "aes128-gcm@openssh.com", + "", + 16, /* blocksize */ + 12, /* initial value length */ + 16, /* secret length -- 16*8 == 128bit */ + 16, /* length of the authentication tag */ + LIBSSH2_CRYPT_FLAG_INTEGRATED_MAC | LIBSSH2_CRYPT_FLAG_PKTLEN_AAD, + &crypt_init, + NULL, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes128gcm +}; +#endif + #if LIBSSH2_AES_CTR static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = { "aes128-ctr", @@ -124,8 +180,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = { 16, /* blocksize */ 16, /* initial value length */ 16, /* secret length -- 16*8 == 128bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes128ctr @@ -137,8 +195,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = { 16, /* blocksize */ 16, /* initial value length */ 24, /* secret length -- 24*8 == 192bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes192ctr @@ -150,23 +210,27 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = { 16, /* blocksize */ 16, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes256ctr }; #endif -#if LIBSSH2_AES +#if LIBSSH2_AES_CBC static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = { "aes128-cbc", "DEK-Info: AES-128-CBC", 16, /* blocksize */ 16, /* initial value length */ 16, /* secret length -- 16*8 == 128bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes128 @@ -178,8 +242,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = { 16, /* blocksize */ 16, /* initial value length */ 24, /* secret length -- 24*8 == 192bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes192 @@ -191,8 +257,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = { 16, /* blocksize */ 16, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes256 @@ -206,13 +274,15 @@ static const LIBSSH2_CRYPT_METHOD 16, /* blocksize */ 16, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes256 }; -#endif /* LIBSSH2_AES */ +#endif /* LIBSSH2_AES_CBC */ #if LIBSSH2_BLOWFISH static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = { @@ -221,8 +291,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_blowfish @@ -236,8 +308,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_arcfour @@ -260,7 +334,8 @@ crypt_init_arcfour128(LIBSSH2_SESSION * session, size_t discard = 1536; for(; discard; discard -= 8) _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block, - method->blocksize); + method->blocksize, MIDDLE_BLOCK); + /* Not all middle, but here it doesn't matter */ } return rc; @@ -272,8 +347,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour128 = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init_arcfour128, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_arcfour @@ -287,8 +364,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_cast5 @@ -302,26 +381,147 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = { 8, /* blocksize */ 8, /* initial value length */ 24, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_3des }; #endif +static int +crypt_init_chacha20_poly(LIBSSH2_SESSION * session, + const LIBSSH2_CRYPT_METHOD * method, + unsigned char *iv, int *free_iv, + unsigned char *secret, int *free_secret, + int encrypt, void **abstract) +{ + struct crypt_ctx *ctx = LIBSSH2_ALLOC(session, + sizeof(struct crypt_ctx)); + + (void)iv; + + if(!ctx) + return LIBSSH2_ERROR_ALLOC; + + ctx->encrypt = encrypt; + ctx->algo = method->algo; + + if(chachapoly_init(&ctx->chachapoly_ctx, secret, method->secret_len)) { + LIBSSH2_FREE(session, ctx); + return -1; + } + + *abstract = ctx; + *free_iv = 1; + *free_secret = 1; + return 0; +} + + +static int +crypt_encrypt_chacha20_poly_buffer(LIBSSH2_SESSION * session, + unsigned int seqno, + unsigned char *buf, + size_t buf_len, + void **abstract, + int firstlast) +{ + int ret = 1; + struct crypt_ctx *ctx = *(struct crypt_ctx **) abstract; + + (void)session; + (void)firstlast; + + if(ctx) { + if(ctx->encrypt) { + /* requires out_buf to be large enough to hold encrypted output + plus auth tag (auth len) + + buf is a full packet so we need to subtract packet length from + length + */ + ret = chachapoly_crypt(&ctx->chachapoly_ctx, seqno, buf, buf, + ((u_int)buf_len) - 4, 4, ctx->encrypt); + } + else { + /* buf is full packet including size and auth tag but buf_len + doesn't include size */ + ret = chachapoly_crypt(&ctx->chachapoly_ctx, seqno, buf, buf, + ((u_int)buf_len), 4, ctx->encrypt); + + /* the api expects the size field to already be removed + from the decrypted packet so we'll help it out */ + if(ret == 0) { + memmove(buf, buf + 4, buf_len - 4); + } + } + } + + return (ret == 0 ? 0 : 1); +} + +static int +crypt_get_length_chacha20_poly(LIBSSH2_SESSION * session, unsigned int seqno, + unsigned char *data, size_t data_size, + unsigned int *len, void **abstract) +{ + struct crypt_ctx *ctx = *(struct crypt_ctx **) abstract; + + (void)session; + + return chachapoly_get_length(&ctx->chachapoly_ctx, len, seqno, data, + (u_int)data_size); +} + +static int +crypt_dtor_chacha20_poly(LIBSSH2_SESSION * session, void **abstract) +{ + struct crypt_ctx **cctx = (struct crypt_ctx **) abstract; + if(cctx && *cctx) { + LIBSSH2_FREE(session, *cctx); + *abstract = NULL; + } + return 0; +} + +static const LIBSSH2_CRYPT_METHOD + libssh2_crypt_method_chacha20_poly1305_openssh = { + "chacha20-poly1305@openssh.com", + "", + 8, /* blocksize */ + 0, /* initial value length */ + 64, /* secret length */ + 16, /* length of the auth_tag */ + LIBSSH2_CRYPT_FLAG_REQUIRES_FULL_PACKET, /* flags */ + &crypt_init_chacha20_poly, + &crypt_get_length_chacha20_poly, + &crypt_encrypt_chacha20_poly_buffer, + &crypt_dtor_chacha20_poly, + _libssh2_cipher_chacha20 /* not actually used */ +}; + +/* These are the crypt methods that are available to be negotiated. Methods + towards the start are chosen in preference to ones further down the list. */ static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { + &libssh2_crypt_method_chacha20_poly1305_openssh, +#if LIBSSH2_AES_GCM + &libssh2_crypt_method_aes256_gcm, + &libssh2_crypt_method_aes128_gcm, +#endif /* LIBSSH2_AES_GCM */ #if LIBSSH2_AES_CTR - &libssh2_crypt_method_aes128_ctr, - &libssh2_crypt_method_aes192_ctr, - &libssh2_crypt_method_aes256_ctr, -#endif /* LIBSSH2_AES */ -#if LIBSSH2_AES + &libssh2_crypt_method_aes256_ctr, + &libssh2_crypt_method_aes192_ctr, + &libssh2_crypt_method_aes128_ctr, +#endif /* LIBSSH2_AES_CTR */ +#if LIBSSH2_AES_CBC &libssh2_crypt_method_aes256_cbc, &libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */ &libssh2_crypt_method_aes192_cbc, &libssh2_crypt_method_aes128_cbc, -#endif /* LIBSSH2_AES */ +#endif /* LIBSSH2_AES_CBC */ #if LIBSSH2_BLOWFISH &libssh2_crypt_method_blowfish_cbc, #endif /* LIBSSH2_BLOWFISH */ @@ -335,7 +535,7 @@ static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { #if LIBSSH2_3DES &libssh2_crypt_method_3des_cbc, #endif /* LIBSSH2_DES */ -#ifdef LIBSSH2_CRYPT_NONE +#if defined(LIBSSH2DEBUG) && defined(LIBSSH2_CRYPT_NONE_INSECURE) &libssh2_crypt_method_none, #endif NULL diff --git a/uppsrc/Core/SSH/libssh2/crypto.c b/uppsrc/Core/SSH/libssh2/crypto.c new file mode 100644 index 000000000..b3b1afcb1 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/crypto.c @@ -0,0 +1,19 @@ +/* Copyright (C) Viktor Szakats + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define LIBSSH2_CRYPTO_C +#include "libssh2_priv.h" + +#if defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL) +#include "openssl.c" +#elif defined(LIBSSH2_LIBGCRYPT) +#include "libgcrypt.c" +#elif defined(LIBSSH2_MBEDTLS) +#include "mbedtls.c" +#elif defined(LIBSSH2_OS400QC3) +#include "os400qc3.c" +#elif defined(LIBSSH2_WINCNG) +#include "wincng.c" +#endif diff --git a/uppsrc/Core/SSH/libssh2/crypto.h b/uppsrc/Core/SSH/libssh2/crypto.h index f512d6039..25ab4d9de 100644 --- a/uppsrc/Core/SSH/libssh2/crypto.h +++ b/uppsrc/Core/SSH/libssh2/crypto.h @@ -1,8 +1,9 @@ -#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 +#ifndef LIBSSH2_CRYPTO_H +#define LIBSSH2_CRYPTO_H +/* Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -36,28 +37,45 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ - -#ifdef LIBSSH2_OPENSSL +#define LIBSSH2_OPENSSL +#if defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL) #include "openssl.h" -#endif - -#ifdef LIBSSH2_LIBGCRYPT +#elif defined(LIBSSH2_LIBGCRYPT) #include "libgcrypt.h" -#endif - -#ifdef LIBSSH2_WINCNG -#include "wincng.h" -#endif - -#ifdef LIBSSH2_OS400QC3 -#include "os400qc3.h" -#endif - -#ifdef LIBSSH2_MBEDTLS +#elif defined(LIBSSH2_MBEDTLS) #include "mbedtls.h" +#elif defined(LIBSSH2_OS400QC3) +#include "os400qc3.h" +#elif defined(LIBSSH2_WINCNG) +#include "wincng.h" +#else +#error "no cryptography backend selected" #endif +/* return: success = 1, error = 0 */ +int _libssh2_hmac_ctx_init(libssh2_hmac_ctx *ctx); +#if LIBSSH2_MD5 +int _libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen); +#endif +#if LIBSSH2_HMAC_RIPEMD +int _libssh2_hmac_ripemd160_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen); +#endif +int _libssh2_hmac_sha1_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen); +int _libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen); +int _libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen); +int _libssh2_hmac_update(libssh2_hmac_ctx *ctx, + const void *data, size_t datalen); +int _libssh2_hmac_final(libssh2_hmac_ctx *ctx, void *data); +void _libssh2_hmac_cleanup(libssh2_hmac_ctx *ctx); + #define LIBSSH2_ED25519_KEY_LEN 32 #define LIBSSH2_ED25519_PRIVATE_KEY_LEN 64 #define LIBSSH2_ED25519_SIG_LEN 64 @@ -83,16 +101,31 @@ int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, LIBSSH2_SESSION * session, const char *filename, unsigned const char *passphrase); -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); +#if LIBSSH2_RSA_SHA1 int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, libssh2_rsa_ctx * rsactx, const unsigned char *hash, size_t hash_len, unsigned char **signature, size_t *signature_len); +int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, size_t m_len); +#endif +#if LIBSSH2_RSA_SHA2 +int _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session, + libssh2_rsa_ctx * rsactx, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, + size_t *signature_len); +int _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsa, + size_t hash_len, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, size_t m_len); +#endif int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, LIBSSH2_SESSION * session, const char *filedata, @@ -117,10 +150,10 @@ int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, unsigned const char *passphrase); int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, const unsigned char *sig, - const unsigned char *m, unsigned long m_len); + const unsigned char *m, size_t m_len); int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, const unsigned char *hash, - unsigned long hash_len, unsigned char *sig); + size_t hash_len, unsigned char *sig); int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, LIBSSH2_SESSION * session, const char *filedata, @@ -134,12 +167,23 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ecdsactx, const unsigned char *k, size_t k_len, libssh2_curve_type type); + int _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, LIBSSH2_SESSION * session, const char *filename, unsigned const char *passphrase); +int +_libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase); + int _libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx, const unsigned char *r, size_t r_len, @@ -160,7 +204,7 @@ _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, int _libssh2_ecdsa_sign(LIBSSH2_SESSION *session, libssh2_ecdsa_ctx *ec_ctx, - const unsigned char *hash, unsigned long hash_len, + const unsigned char *hash, size_t hash_len, unsigned char **signature, size_t *signature_len); int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, @@ -169,6 +213,16 @@ int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, size_t filedata_len, unsigned const char *passphrase); +int _libssh2_ecdsa_new_private_frommemory_sk(libssh2_ecdsa_ctx ** ec_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase); + libssh2_curve_type _libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx); @@ -198,11 +252,21 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx **ed_ctx, LIBSSH2_SESSION *session, const char *filename, const uint8_t *passphrase); +int +_libssh2_ed25519_new_private_sk(libssh2_ed25519_ctx **ed_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION *session, + const char *filename, + const uint8_t *passphrase); + int _libssh2_ed25519_new_public(libssh2_ed25519_ctx **ed_ctx, LIBSSH2_SESSION *session, const unsigned char *raw_pub_key, - const uint8_t key_len); + const size_t key_len); int _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, @@ -216,6 +280,17 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx **ed_ctx, size_t filedata_len, unsigned const char *passphrase); +int +_libssh2_ed25519_new_private_frommemory_sk(libssh2_ed25519_ctx **ed_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION *session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase); + #endif /* LIBSSH2_ED25519 */ @@ -226,7 +301,8 @@ int _libssh2_cipher_init(_libssh2_cipher_ctx * h, int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blocksize); + int encrypt, unsigned char *block, size_t blocksize, + int firstlast); int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, unsigned char **method, @@ -245,4 +321,37 @@ int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, size_t privatekeydata_len, const char *passphrase); -#endif /* __LIBSSH2_CRYPTO_H */ + +int _libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase); + +/** + * @function _libssh2_supported_key_sign_algorithms + * @abstract Returns supported algorithms used for upgrading public + * key signing RFC 8332 + * @discussion Based on the incoming key_method value, this function + * will return supported algorithms that can upgrade the key method + * @related _libssh2_key_sign_algorithm() + * @param key_method current key method, usually the default key sig method + * @param key_method_len length of the key method buffer + * @result comma separated list of supported upgrade options per RFC 8332, if + * there is no upgrade option return NULL + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len); + +#endif /* LIBSSH2_CRYPTO_H */ diff --git a/uppsrc/Core/SSH/libssh2/crypto_config.h b/uppsrc/Core/SSH/libssh2/crypto_config.h new file mode 100644 index 000000000..885a6a918 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/crypto_config.h @@ -0,0 +1,76 @@ +/* Copyright (C) Viktor Szakats + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define LIBSSH2_MD5_PEM LIBSSH2_MD5 + +#ifdef LIBSSH2_NO_MD5 +#undef LIBSSH2_MD5 +#define LIBSSH2_MD5 0 +#endif + +#ifdef LIBSSH2_NO_MD5_PEM +#undef LIBSSH2_MD5_PEM +#define LIBSSH2_MD5_PEM 0 +#endif + +#ifdef LIBSSH2_NO_HMAC_RIPEMD +#undef LIBSSH2_HMAC_RIPEMD +#define LIBSSH2_HMAC_RIPEMD 0 +#endif + +#if !defined(LIBSSH2_DSA_ENABLE) +#undef LIBSSH2_DSA +#define LIBSSH2_DSA 0 +#endif + +#ifdef LIBSSH2_NO_RSA +#undef LIBSSH2_RSA +#define LIBSSH2_RSA 0 +#endif + +#ifdef LIBSSH2_NO_RSA_SHA1 +#undef LIBSSH2_RSA_SHA1 +#define LIBSSH2_RSA_SHA1 0 +#endif + +#ifdef LIBSSH2_NO_ECDSA +#undef LIBSSH2_ECDSA +#define LIBSSH2_ECDSA 0 +#endif + +#ifdef LIBSSH2_NO_ED25519 +#undef LIBSSH2_ED25519 +#define LIBSSH2_ED25519 0 +#endif + +#ifdef LIBSSH2_NO_AES_CTR +#undef LIBSSH2_AES_CTR +#define LIBSSH2_AES_CTR 0 +#endif + +#ifdef LIBSSH2_NO_AES_CBC +#undef LIBSSH2_AES_CBC +#define LIBSSH2_AES_CBC 0 +#endif + +#ifdef LIBSSH2_NO_BLOWFISH +#undef LIBSSH2_BLOWFISH +#define LIBSSH2_BLOWFISH 0 +#endif + +#ifdef LIBSSH2_NO_RC4 +#undef LIBSSH2_RC4 +#define LIBSSH2_RC4 0 +#endif + +#ifdef LIBSSH2_NO_CAST +#undef LIBSSH2_CAST +#define LIBSSH2_CAST 0 +#endif + +#ifdef LIBSSH2_NO_3DES +#undef LIBSSH2_3DES +#define LIBSSH2_3DES 0 +#endif diff --git a/uppsrc/Core/SSH/libssh2/global.c b/uppsrc/Core/SSH/libssh2/global.c index 68289845f..a8bc38078 100644 --- a/uppsrc/Core/SSH/libssh2/global.c +++ b/uppsrc/Core/SSH/libssh2/global.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2010 Lars Nordin - * Copyright (C) 2010 Simon Josefsson +/* Copyright (C) Lars Nordin + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,6 +34,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -74,5 +76,5 @@ void _libssh2_init_if_needed(void) { if(_libssh2_initialized == 0) - (void)libssh2_init (0); + (void)libssh2_init(0); } diff --git a/uppsrc/Core/SSH/libssh2/hostkey.c b/uppsrc/Core/SSH/libssh2/hostkey.c index d87a4c744..99eaf3e07 100644 --- a/uppsrc/Core/SSH/libssh2/hostkey.c +++ b/uppsrc/Core/SSH/libssh2/hostkey.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2006, Sara Golemon - * Copyright (c) 2009-2019 by Daniel Stenberg +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,10 +34,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include "misc.h" /* Needed for struct iovec on some platforms */ #ifdef HAVE_SYS_UIO_H @@ -64,8 +65,8 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, void **abstract) { libssh2_rsa_ctx *rsactx; - unsigned char *e, *n; - size_t e_len, n_len; + unsigned char *e, *n, *type; + size_t e_len, n_len, type_len; struct string_buf buf; if(*abstract) { @@ -74,8 +75,8 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, } if(hostkey_data_len < 19) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "host key length too short")); return -1; } @@ -83,8 +84,31 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, buf.dataptr = buf.data; buf.len = hostkey_data_len; - if(_libssh2_match_string(&buf, "ssh-rsa")) + if(_libssh2_get_string(&buf, &type, &type_len)) { return -1; + } + + /* we accept one of 3 header types */ +#if LIBSSH2_RSA_SHA1 + if(type_len == 7 && strncmp("ssh-rsa", (char *)type, 7) == 0) { + /* ssh-rsa */ + } + else +#endif +#if LIBSSH2_RSA_SHA2 + if(type_len == 12 && strncmp("rsa-sha2-256", (char *)type, 12) == 0) { + /* rsa-sha2-256 */ + } + else if(type_len == 12 && strncmp("rsa-sha2-512", (char *)type, 12) == 0) { + /* rsa-sha2-512 */ + } + else +#endif + { + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "unexpected rsa type: %.*s", (int)type_len, type)); + return -1; + } if(_libssh2_get_string(&buf, &e, &e_len)) return -1; @@ -92,8 +116,14 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, if(_libssh2_get_string(&buf, &n, &n_len)) return -1; - if(_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) { + if(!_libssh2_eob(&buf)) + return -1; + + if(_libssh2_rsa_new(&rsactx, + e, (unsigned long)e_len, + n, (unsigned long)n_len, + NULL, 0, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, NULL, 0)) { return -1; } @@ -163,6 +193,7 @@ hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session, return 0; } +#if LIBSSH2_RSA_SHA1 /* * hostkey_method_ssh_rsa_sign * @@ -176,7 +207,7 @@ hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session, size_t m_len, void **abstract) { libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - (void) session; + (void)session; /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */ if(sig_len < 15) @@ -211,11 +242,18 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, unsigned char hash[SHA_DIGEST_LENGTH]; libssh2_sha1_ctx ctx; - libssh2_sha1_init(&ctx); - for(i = 0; i < veccount; i++) { - libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); + if(!libssh2_sha1_init(&ctx)) { + return -1; + } + for(i = 0; i < veccount; i++) { + if(!libssh2_sha1_update(ctx, + datavec[i].iov_base, datavec[i].iov_len)) { + return -1; + } + } + if(!libssh2_sha1_final(ctx, hash)) { + return -1; } - libssh2_sha1_final(ctx, hash); ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH, signature, signature_len); @@ -226,6 +264,161 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, return 0; #endif } +#endif + +/* + * hostkey_method_ssh_rsa_sha2_256_sig_verify + * + * Verify signature created by remote + */ +#if LIBSSH2_RSA_SHA2 + +static int +hostkey_method_ssh_rsa_sha2_256_sig_verify(LIBSSH2_SESSION * session, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len, void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + (void)session; + + /* Skip past keyname_len(4) + keyname(12){"rsa-sha2-256"} + + signature_len(4) */ + if(sig_len < 20) + return -1; + + sig += 20; + sig_len -= 20; + return _libssh2_rsa_sha2_verify(rsactx, SHA256_DIGEST_LENGTH, sig, sig_len, + m, m_len); +} + +/* + * hostkey_method_ssh_rsa_sha2_256_signv + * + * Construct a signature from an array of vectors + */ + +static int +hostkey_method_ssh_rsa_sha2_256_signv(LIBSSH2_SESSION * session, + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec datavec[], + void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + +#ifdef _libssh2_rsa_sha2_256_signv + return _libssh2_rsa_sha2_256_signv(session, signature, signature_len, + veccount, datavec, rsactx); +#else + int ret; + int i; + unsigned char hash[SHA256_DIGEST_LENGTH]; + libssh2_sha256_ctx ctx; + + if(!libssh2_sha256_init(&ctx)) { + return -1; + } + for(i = 0; i < veccount; i++) { + if(!libssh2_sha256_update(ctx, + datavec[i].iov_base, datavec[i].iov_len)) { + return -1; + } + } + if(!libssh2_sha256_final(ctx, hash)) { + return -1; + } + + ret = _libssh2_rsa_sha2_sign(session, rsactx, hash, SHA256_DIGEST_LENGTH, + signature, signature_len); + if(ret) { + return -1; + } + + return 0; +#endif +} + +/* + * hostkey_method_ssh_rsa_sha2_512_sig_verify + * + * Verify signature created by remote + */ + +static int +hostkey_method_ssh_rsa_sha2_512_sig_verify(LIBSSH2_SESSION * session, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len, void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + (void)session; + + /* Skip past keyname_len(4) + keyname(12){"rsa-sha2-512"} + + signature_len(4) */ + if(sig_len < 20) + return -1; + + sig += 20; + sig_len -= 20; + return _libssh2_rsa_sha2_verify(rsactx, SHA512_DIGEST_LENGTH, sig, + sig_len, m, m_len); +} + + +/* + * hostkey_method_ssh_rsa_sha2_512_signv + * + * Construct a signature from an array of vectors + */ +static int +hostkey_method_ssh_rsa_sha2_512_signv(LIBSSH2_SESSION * session, + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec datavec[], + void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + +#ifdef _libssh2_rsa_sha2_512_signv + return _libssh2_rsa_sha2_512_signv(session, signature, signature_len, + veccount, datavec, rsactx); +#else + int ret; + int i; + unsigned char hash[SHA512_DIGEST_LENGTH]; + libssh2_sha512_ctx ctx; + + if(!libssh2_sha512_init(&ctx)) { + return -1; + } + for(i = 0; i < veccount; i++) { + if(!libssh2_sha512_update(ctx, + datavec[i].iov_base, datavec[i].iov_len)) { + return -1; + } + } + if(!libssh2_sha512_final(ctx, hash)) { + return -1; + } + + ret = _libssh2_rsa_sha2_sign(session, rsactx, hash, SHA512_DIGEST_LENGTH, + signature, signature_len); + if(ret) { + return -1; + } + + return 0; +#endif +} + +#endif /* LIBSSH2_RSA_SHA2 */ + /* * hostkey_method_ssh_rsa_dtor @@ -236,7 +429,7 @@ static int hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract) { libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - (void) session; + (void)session; _libssh2_rsa_free(rsactx); @@ -245,13 +438,11 @@ hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract) return 0; } -#ifdef OPENSSL_NO_MD5 -#define MD5_DIGEST_LENGTH 16 -#endif +#if LIBSSH2_RSA_SHA1 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { "ssh-rsa", - MD5_DIGEST_LENGTH, + SHA_DIGEST_LENGTH, hostkey_method_ssh_rsa_init, hostkey_method_ssh_rsa_initPEM, hostkey_method_ssh_rsa_initPEMFromMemory, @@ -260,6 +451,81 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { NULL, /* encrypt */ hostkey_method_ssh_rsa_dtor, }; + +#endif /* LIBSSH2_RSA_SHA1 */ + +#if LIBSSH2_RSA_SHA2 + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_256 = { + "rsa-sha2-256", + SHA256_DIGEST_LENGTH, + hostkey_method_ssh_rsa_init, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_initPEMFromMemory, + hostkey_method_ssh_rsa_sha2_256_sig_verify, + hostkey_method_ssh_rsa_sha2_256_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_512 = { + "rsa-sha2-512", + SHA512_DIGEST_LENGTH, + hostkey_method_ssh_rsa_init, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_initPEMFromMemory, + hostkey_method_ssh_rsa_sha2_512_sig_verify, + hostkey_method_ssh_rsa_sha2_512_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; + +#endif /* LIBSSH2_RSA_SHA2 */ + +#if LIBSSH2_RSA_SHA1 + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_cert = { + "ssh-rsa-cert-v01@openssh.com", + SHA_DIGEST_LENGTH, + NULL, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_initPEMFromMemory, + NULL, + hostkey_method_ssh_rsa_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; + +#endif /* LIBSSH2_RSA_SHA1 */ + +#if LIBSSH2_RSA_SHA2 + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_256_cert = { + "rsa-sha2-256-cert-v01@openssh.com", + SHA256_DIGEST_LENGTH, + NULL, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_initPEMFromMemory, + NULL, + hostkey_method_ssh_rsa_sha2_256_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_512_cert = { + "rsa-sha2-512-cert-v01@openssh.com", + SHA512_DIGEST_LENGTH, + NULL, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_initPEMFromMemory, + NULL, + hostkey_method_ssh_rsa_sha2_512_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; + +#endif /* LIBSSH2_RSA_SHA2 */ + #endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA @@ -292,8 +558,8 @@ hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, } if(hostkey_data_len < 27) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "host key length too short")); return -1; } @@ -305,7 +571,7 @@ hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, return -1; if(_libssh2_get_string(&buf, &p, &p_len)) - return -1; + return -1; if(_libssh2_get_string(&buf, &q, &q_len)) return -1; @@ -316,8 +582,15 @@ hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, if(_libssh2_get_string(&buf, &y, &y_len)) return -1; - if(_libssh2_dsa_new(&dsactx, p, p_len, q, q_len, - g, g_len, y, y_len, NULL, 0)) { + if(!_libssh2_eob(&buf)) + return -1; + + if(_libssh2_dsa_new(&dsactx, + p, (unsigned long)p_len, + q, (unsigned long)q_len, + g, (unsigned long)g_len, + y, (unsigned long)y_len, + NULL, 0)) { return -1; } @@ -431,6 +704,12 @@ hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session, libssh2_sha1_ctx ctx; int i; + if(!libssh2_sha1_init(&ctx)) { + *signature = NULL; + *signature_len = 0; + return -1; + } + *signature = LIBSSH2_CALLOC(session, 2 * SHA_DIGEST_LENGTH); if(!*signature) { return -1; @@ -438,11 +717,15 @@ hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session, *signature_len = 2 * SHA_DIGEST_LENGTH; - libssh2_sha1_init(&ctx); for(i = 0; i < veccount; i++) { - libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); + if(!libssh2_sha1_update(ctx, + datavec[i].iov_base, datavec[i].iov_len)) { + return -1; + } + } + if(!libssh2_sha1_final(ctx, hash)) { + return -1; } - libssh2_sha1_final(ctx, hash); if(_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) { LIBSSH2_FREE(session, *signature); @@ -461,7 +744,7 @@ static int hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract) { libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); - (void) session; + (void)session; _libssh2_dsa_free(dsactx); @@ -472,7 +755,7 @@ hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract) static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = { "ssh-dss", - MD5_DIGEST_LENGTH, + SHA_DIGEST_LENGTH, hostkey_method_ssh_dss_init, hostkey_method_ssh_dss_initPEM, hostkey_method_ssh_dss_initPEMFromMemory, @@ -500,9 +783,9 @@ hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, - const unsigned char *hostkey_data, - size_t hostkey_data_len, - void **abstract) + const unsigned char *hostkey_data, + size_t hostkey_data_len, + void **abstract) { libssh2_ecdsa_ctx *ecdsactx = NULL; unsigned char *type_str, *domain, *public_key; @@ -510,14 +793,14 @@ hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, libssh2_curve_type type; struct string_buf buf; - if(abstract != NULL && *abstract) { + if(abstract && *abstract) { hostkey_method_ssh_ecdsa_dtor(session, abstract); *abstract = NULL; } if(hostkey_data_len < 39) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "host key length too short")); return -1; } @@ -561,11 +844,14 @@ hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, if(_libssh2_get_string(&buf, &public_key, &key_len)) return -1; + if(!_libssh2_eob(&buf)) + return -1; + if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, public_key, key_len, type)) return -1; - if(abstract != NULL) + if(abstract) *abstract = ecdsactx; return 0; @@ -578,14 +864,14 @@ hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) + const char *privkeyfile, + unsigned const char *passphrase, + void **abstract) { libssh2_ecdsa_ctx *ec_ctx = NULL; int ret; - if(abstract != NULL && *abstract) { + if(abstract && *abstract) { hostkey_method_ssh_ecdsa_dtor(session, abstract); *abstract = NULL; } @@ -593,7 +879,7 @@ hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session, ret = _libssh2_ecdsa_new_private(&ec_ctx, session, privkeyfile, passphrase); - if(abstract != NULL) + if(abstract) *abstract = ec_ctx; return ret; @@ -606,15 +892,15 @@ hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ecdsa_initPEMFromMemory(LIBSSH2_SESSION * session, - const char *privkeyfiledata, - size_t privkeyfiledata_len, - unsigned const char *passphrase, - void **abstract) + const char *privkeyfiledata, + size_t privkeyfiledata_len, + unsigned const char *passphrase, + void **abstract) { libssh2_ecdsa_ctx *ec_ctx = NULL; int ret; - if(abstract != NULL && *abstract) { + if(abstract && *abstract) { hostkey_method_ssh_ecdsa_dtor(session, abstract); *abstract = NULL; } @@ -627,7 +913,7 @@ hostkey_method_ssh_ecdsa_initPEMFromMemory(LIBSSH2_SESSION * session, return -1; } - if(abstract != NULL) + if(abstract) *abstract = ec_ctx; return 0; @@ -651,7 +937,7 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, struct string_buf buf; libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract); - (void) session; + (void)session; if(sig_len < 35) return -1; @@ -662,14 +948,14 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, buf.dataptr = buf.data; buf.len = sig_len; - if(_libssh2_get_string(&buf, &name, &name_len) || name_len != 19) + if(_libssh2_get_string(&buf, &name, &name_len) || name_len != 19) return -1; if(_libssh2_get_u32(&buf, &len) != 0 || len < 8) return -1; if(_libssh2_get_string(&buf, &r, &r_len)) - return -1; + return -1; if(_libssh2_get_string(&buf, &s, &s_len)) return -1; @@ -678,21 +964,34 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, } -#define LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(digest_type) \ - { \ - unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ - libssh2_sha##digest_type##_ctx ctx; \ - int i; \ - 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); \ - } \ - libssh2_sha##digest_type##_final(ctx, hash); \ - ret = _libssh2_ecdsa_sign(session, ec_ctx, hash, \ - SHA##digest_type##_DIGEST_LENGTH, \ - signature, signature_len); \ - } +#define LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(digest_type) \ + do { \ + unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ + libssh2_sha##digest_type##_ctx ctx; \ + int i; \ + if(!libssh2_sha##digest_type##_init(&ctx)) { \ + ret = -1; \ + break; \ + } \ + for(i = 0; i < veccount; i++) { \ + if(!libssh2_sha##digest_type##_update(ctx, \ + datavec[i].iov_base, \ + datavec[i].iov_len)) { \ + ret = -1; \ + break; \ + } \ + } \ + if(ret == -1) { \ + break; \ + } \ + if(!libssh2_sha##digest_type##_final(ctx, hash)) { \ + ret = -1; \ + break; \ + } \ + ret = _libssh2_ecdsa_sign(session, ec_ctx, hash, \ + SHA##digest_type##_DIGEST_LENGTH, \ + signature, signature_len); \ + } while(0) /* @@ -737,9 +1036,9 @@ static int hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, void **abstract) { libssh2_ecdsa_ctx *keyctx = (libssh2_ecdsa_ctx *) (*abstract); - (void) session; + (void)session; - if(keyctx != NULL) + if(keyctx) _libssh2_ecdsa_free(keyctx); *abstract = NULL; @@ -841,9 +1140,10 @@ hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session, size_t hostkey_data_len, void **abstract) { - const unsigned char *s; - unsigned long len, key_len; + size_t key_len; + unsigned char *key; libssh2_ed25519_ctx *ctx = NULL; + struct string_buf buf; if(*abstract) { hostkey_method_ssh_ed25519_dtor(session, abstract); @@ -851,26 +1151,26 @@ hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session, } if(hostkey_data_len < 19) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "host key length too short")); return -1; } - s = hostkey_data; - len = _libssh2_ntohu32(s); - s += 4; + buf.data = (unsigned char *)hostkey_data; + buf.dataptr = buf.data; + buf.len = hostkey_data_len; - if(len != 11 || strncmp((char *) s, "ssh-ed25519", 11) != 0) { + if(_libssh2_match_string(&buf, "ssh-ed25519")) return -1; - } - - s += 11; /* public key */ - key_len = _libssh2_ntohu32(s); - s += 4; + if(_libssh2_get_string(&buf, &key, &key_len)) + return -1; - if(_libssh2_ed25519_new_public(&ctx, session, s, key_len) != 0) { + if(!_libssh2_eob(&buf)) + return -1; + + if(_libssh2_ed25519_new_public(&ctx, session, key, key_len) != 0) { return -1; } @@ -886,9 +1186,9 @@ hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ed25519_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) + const char *privkeyfile, + unsigned const char *passphrase, + void **abstract) { libssh2_ed25519_ctx *ec_ctx = NULL; int ret; @@ -924,7 +1224,7 @@ hostkey_method_ssh_ed25519_initPEMFromMemory(LIBSSH2_SESSION * session, libssh2_ed25519_ctx *ed_ctx = NULL; int ret; - if(abstract != NULL && *abstract) { + if(abstract && *abstract) { hostkey_method_ssh_ed25519_dtor(session, abstract); *abstract = NULL; } @@ -937,7 +1237,7 @@ hostkey_method_ssh_ed25519_initPEMFromMemory(LIBSSH2_SESSION * session, return -1; } - if(abstract != NULL) + if(abstract) *abstract = ed_ctx; return 0; @@ -956,7 +1256,7 @@ hostkey_method_ssh_ed25519_sig_verify(LIBSSH2_SESSION * session, size_t m_len, void **abstract) { libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract); - (void) session; + (void)session; if(sig_len < 19) return -1; @@ -979,11 +1279,11 @@ hostkey_method_ssh_ed25519_sig_verify(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ed25519_signv(LIBSSH2_SESSION * session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec datavec[], - void **abstract) + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec datavec[], + void **abstract) { libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract); @@ -992,7 +1292,8 @@ hostkey_method_ssh_ed25519_signv(LIBSSH2_SESSION * session, } return _libssh2_ed25519_sign(ctx, session, signature, signature_len, - datavec[0].iov_base, datavec[0].iov_len); + (const uint8_t *)datavec[0].iov_base, + datavec[0].iov_len); } @@ -1005,7 +1306,7 @@ static int hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session, void **abstract) { libssh2_ed25519_ctx *keyctx = (libssh2_ed25519_ctx*) (*abstract); - (void) session; + (void)session; if(keyctx) _libssh2_ed25519_free(keyctx); @@ -1027,7 +1328,19 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519 = { hostkey_method_ssh_ed25519_dtor, }; -#endif /*LIBSSH2_ED25519*/ +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519_cert = { + "ssh-ed25519-cert-v01@openssh.com", + SHA256_DIGEST_LENGTH, + hostkey_method_ssh_ed25519_init, + hostkey_method_ssh_ed25519_initPEM, + hostkey_method_ssh_ed25519_initPEMFromMemory, + hostkey_method_ssh_ed25519_sig_verify, + hostkey_method_ssh_ed25519_signv, + NULL, /* encrypt */ + hostkey_method_ssh_ed25519_dtor, +}; + +#endif /* LIBSSH2_ED25519 */ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = { @@ -1041,9 +1354,19 @@ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = { #endif #if LIBSSH2_ED25519 &hostkey_method_ssh_ed25519, + &hostkey_method_ssh_ed25519_cert, #endif #if LIBSSH2_RSA +#if LIBSSH2_RSA_SHA2 + &hostkey_method_ssh_rsa_sha2_512, + &hostkey_method_ssh_rsa_sha2_256, + &hostkey_method_ssh_rsa_sha2_512_cert, + &hostkey_method_ssh_rsa_sha2_256_cert, +#endif /* LIBSSH2_RSA_SHA2 */ +#if LIBSSH2_RSA_SHA1 &hostkey_method_ssh_rsa, + &hostkey_method_ssh_rsa_cert, +#endif /* LIBSSH2_RSA_SHA1 */ #endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA &hostkey_method_ssh_dss, @@ -1074,18 +1397,15 @@ libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type) return (session->server_hostkey_md5_valid) ? (char *) session->server_hostkey_md5 : NULL; - break; #endif /* LIBSSH2_MD5 */ case LIBSSH2_HOSTKEY_HASH_SHA1: return (session->server_hostkey_sha1_valid) ? (char *) session->server_hostkey_sha1 : NULL; - break; case LIBSSH2_HOSTKEY_HASH_SHA256: return (session->server_hostkey_sha256_valid) ? (char *) session->server_hostkey_sha256 : NULL; - break; default: return NULL; } @@ -1096,9 +1416,11 @@ static int hostkey_type(const unsigned char *hostkey, size_t len) static const unsigned char rsa[] = { 0, 0, 0, 0x07, 's', 's', 'h', '-', 'r', 's', 'a' }; +#if LIBSSH2_DSA static const unsigned char dss[] = { 0, 0, 0, 0x07, 's', 's', 'h', '-', 'd', 's', 's' }; +#endif static const unsigned char ecdsa_256[] = { 0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-', 'n', 'i', 's', 't', 'p', '2', '5', '6' @@ -1121,8 +1443,10 @@ static int hostkey_type(const unsigned char *hostkey, size_t len) if(!memcmp(rsa, hostkey, 11)) return LIBSSH2_HOSTKEY_TYPE_RSA; +#if LIBSSH2_DSA if(!memcmp(dss, hostkey, 11)) return LIBSSH2_HOSTKEY_TYPE_DSS; +#endif if(len < 15) return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; @@ -1146,7 +1470,7 @@ static int hostkey_type(const unsigned char *hostkey, size_t len) } /* - * libssh2_session_hostkey() + * libssh2_session_hostkey * * Returns the server key and length. * diff --git a/uppsrc/Core/SSH/libssh2/keepalive.c b/uppsrc/Core/SSH/libssh2/keepalive.c index 2151b1710..489a1daaa 100644 --- a/uppsrc/Core/SSH/libssh2/keepalive.c +++ b/uppsrc/Core/SSH/libssh2/keepalive.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2010 Simon Josefsson - * Author: Simon Josefsson +/* Copyright (C) Simon Josefsson + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -34,6 +34,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -42,9 +43,9 @@ /* Keep-alive stuff. */ LIBSSH2_API void -libssh2_keepalive_config (LIBSSH2_SESSION *session, - int want_reply, - unsigned interval) +libssh2_keepalive_config(LIBSSH2_SESSION *session, + int want_reply, + unsigned int interval) { if(interval == 1) session->keepalive_interval = 2; @@ -54,8 +55,8 @@ libssh2_keepalive_config (LIBSSH2_SESSION *session, } LIBSSH2_API int -libssh2_keepalive_send (LIBSSH2_SESSION *session, - int *seconds_to_next) +libssh2_keepalive_send(LIBSSH2_SESSION *session, + int *seconds_to_next) { time_t now; diff --git a/uppsrc/Core/SSH/libssh2/kex.c b/uppsrc/Core/SSH/libssh2/kex.c index 9f3ef7992..4ca9c34c7 100644 --- a/uppsrc/Core/SSH/libssh2/kex.c +++ b/uppsrc/Core/SSH/libssh2/kex.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2010-2019, Daniel Stenberg +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,6 +34,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -53,8 +55,9 @@ /* Helper macro called from kex_method_diffie_hellman_group1_sha1_key_exchange */ +#if LIBSSH2_ECDSA #define LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(value, reqlen, version) \ - { \ + do { \ if(type == LIBSSH2_EC_CURVE_NISTP256) { \ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, value, reqlen, version); \ } \ @@ -64,39 +67,57 @@ else if(type == LIBSSH2_EC_CURVE_NISTP521) { \ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(512, value, reqlen, version); \ } \ - } \ - + } while(0) +#endif #define LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(digest_type, value, \ reqlen, version) \ -{ \ +do { \ libssh2_sha##digest_type##_ctx hash; \ - unsigned long len = 0; \ + size_t 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, \ - SHA##digest_type##_DIGEST_LENGTH); \ + while(len < (size_t)reqlen) { \ + if(!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, \ + SHA##digest_type##_DIGEST_LENGTH)) { \ + LIBSSH2_FREE(session, value); \ + value = NULL; \ + break; \ + } \ if(len > 0) { \ - libssh2_sha##digest_type##_update(hash, value, len); \ + if(!libssh2_sha##digest_type##_update(hash, value, len)) { \ + LIBSSH2_FREE(session, value); \ + value = NULL; \ + break; \ + } \ } \ else { \ - libssh2_sha##digest_type##_update(hash, (version), 1); \ - libssh2_sha##digest_type##_update(hash, session->session_id,\ - session->session_id_len); \ + if(!libssh2_sha##digest_type##_update(hash, \ + (version), 1) || \ + !libssh2_sha##digest_type##_update(hash, \ + session->session_id, \ + session->session_id_len)) { \ + LIBSSH2_FREE(session, value); \ + value = NULL; \ + break; \ + } \ + } \ + if(!libssh2_sha##digest_type##_final(hash, (value) + len)) { \ + LIBSSH2_FREE(session, value); \ + value = NULL; \ + break; \ } \ - libssh2_sha##digest_type##_final(hash, (value) + len); \ len += SHA##digest_type##_DIGEST_LENGTH; \ } \ -} +} while(0) /*! * @note The following are wrapper functions used by diffie_hellman_sha_algo(). @@ -105,82 +126,87 @@ * don't allow it so we have to wrap them up in helper functions */ -static void _libssh2_sha_algo_ctx_init(int sha_algo, void *ctx) +static int _libssh2_sha_algo_ctx_init(int sha_algo, void *ctx) { if(sha_algo == 512) { - libssh2_sha512_init((libssh2_sha512_ctx*)ctx); + return libssh2_sha512_init((libssh2_sha512_ctx*)ctx); } else if(sha_algo == 384) { - libssh2_sha384_init((libssh2_sha384_ctx*)ctx); + return libssh2_sha384_init((libssh2_sha384_ctx*)ctx); } else if(sha_algo == 256) { - libssh2_sha256_init((libssh2_sha256_ctx*)ctx); + return libssh2_sha256_init((libssh2_sha256_ctx*)ctx); } else if(sha_algo == 1) { - libssh2_sha1_init((libssh2_sha1_ctx*)ctx); + return libssh2_sha1_init((libssh2_sha1_ctx*)ctx); } else { - assert(0); - } -} - -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 +#ifdef LIBSSH2DEBUG assert(0); #endif } + return 0; } -static void _libssh2_sha_algo_ctx_final(int sha_algo, void *ctx, - void *hash) +static int _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_final(*_ctx, hash); + return libssh2_sha512_update(*_ctx, data, len); } else if(sha_algo == 384) { libssh2_sha384_ctx *_ctx = (libssh2_sha384_ctx*)ctx; - libssh2_sha384_final(*_ctx, hash); + return libssh2_sha384_update(*_ctx, data, len); } else if(sha_algo == 256) { libssh2_sha256_ctx *_ctx = (libssh2_sha256_ctx*)ctx; - libssh2_sha256_final(*_ctx, hash); + return libssh2_sha256_update(*_ctx, data, len); } else if(sha_algo == 1) { libssh2_sha1_ctx *_ctx = (libssh2_sha1_ctx*)ctx; - libssh2_sha1_final(*_ctx, hash); + return libssh2_sha1_update(*_ctx, data, len); } else { -#if LIBSSH2DEBUG +#ifdef LIBSSH2DEBUG assert(0); #endif } + return 0; +} + +static int _libssh2_sha_algo_ctx_final(int sha_algo, void *ctx, + void *hash) +{ + if(sha_algo == 512) { + libssh2_sha512_ctx *_ctx = (libssh2_sha512_ctx*)ctx; + return libssh2_sha512_final(*_ctx, hash); + } + else if(sha_algo == 384) { + libssh2_sha384_ctx *_ctx = (libssh2_sha384_ctx*)ctx; + return libssh2_sha384_final(*_ctx, hash); + } + else if(sha_algo == 256) { + libssh2_sha256_ctx *_ctx = (libssh2_sha256_ctx*)ctx; + return libssh2_sha256_final(*_ctx, hash); + } + else if(sha_algo == 1) { + libssh2_sha1_ctx *_ctx = (libssh2_sha1_ctx*)ctx; + return libssh2_sha1_final(*_ctx, hash); + } + else { +#ifdef LIBSSH2DEBUG + assert(0); +#endif + } + return 0; } 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) + 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); @@ -195,13 +221,67 @@ static void _libssh2_sha_algo_value_hash(int sha_algo, LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(1, *data, data_len, version); } else { -#if LIBSSH2DEBUG +#ifdef LIBSSH2DEBUG assert(0); #endif } } +static void +diffie_hellman_state_cleanup(LIBSSH2_SESSION * session, + kmdhgGPshakex_state_t *exchange_state) +{ + 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; + } + + if(exchange_state->s_packet) { + LIBSSH2_FREE(session, exchange_state->s_packet); + exchange_state->s_packet = NULL; + } + + if(exchange_state->k_value) { + LIBSSH2_FREE(session, exchange_state->k_value); + exchange_state->k_value = NULL; + } + + exchange_state->state = libssh2_NB_state_idle; +} + +static void +kex_diffie_hellman_cleanup(LIBSSH2_SESSION * session, + key_exchange_state_low_t * key_state) { + if(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; + + if(key_state->data) { + LIBSSH2_FREE(session, key_state->data); + key_state->data = NULL; + } + key_state->state = libssh2_NB_state_idle; + } + + if(key_state->exchange_state.state != libssh2_NB_state_idle) { + diffie_hellman_state_cleanup(session, &key_state->exchange_state); + } +} + + /*! * @function diffie_hellman_sha_algo * @abstract Diffie Hellman Key Exchange, Group Agnostic, @@ -217,7 +297,7 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, unsigned char packet_type_init, unsigned char packet_type_reply, unsigned char *midhash, - unsigned long midhash_len, + size_t midhash_len, kmdhgGPshakex_state_t *exchange_state) { int ret = 0; @@ -235,7 +315,7 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, digest_len = SHA1_DIGEST_LENGTH; else { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "sha algo value is unimplemented"); + "sha algo value is unimplemented"); goto clean_exit; } @@ -264,8 +344,11 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, rc = libssh2_dh_key_pair(&exchange_state->x, exchange_state->e, g, p, group_order, exchange_state->ctx); - if(rc) + if(rc) { + ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, + "dh key pair generation failed"); goto clean_exit; + } /* Send KEX init */ /* packet_type(1) + String Length(4) + leading 0(1) */ @@ -285,19 +368,27 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, } exchange_state->e_packet[0] = packet_type_init; _libssh2_htonu32(exchange_state->e_packet + 1, - exchange_state->e_packet_len - 5); + (uint32_t)(exchange_state->e_packet_len - 5)); if(_libssh2_bn_bits(exchange_state->e) % 8) { - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 5); + if(_libssh2_bn_to_bin(exchange_state->e, + exchange_state->e_packet + 5)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } else { exchange_state->e_packet[5] = 0; - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 6); + if(_libssh2_bn_to_bin(exchange_state->e, + exchange_state->e_packet + 6)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d", - (int) packet_type_init); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Sending KEX packet %u", + (unsigned int) packet_type_init)); exchange_state->state = libssh2_NB_state_created; } @@ -323,9 +414,9 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, * need to silently ignore it */ int burn_type; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Waiting for badly guessed KEX packet " - "(to be ignored)"); + "(to be ignored)")); burn_type = _libssh2_packet_burn(session, &exchange_state->burn_state); if(burn_type == LIBSSH2_ERROR_EAGAIN) { @@ -338,9 +429,9 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, } session->burn_optimistic_kexinit = 0; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Burnt packet of type: %02x", - (unsigned int) burn_type); + (unsigned int) burn_type)); } exchange_state->state = libssh2_NB_state_sent1; @@ -350,6 +441,8 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, /* Wait for KEX reply */ struct string_buf buf; size_t host_key_len; + int err; + int hok; rc = _libssh2_packet_require(session, packet_type_reply, &exchange_state->s_packet, @@ -367,7 +460,7 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, /* Parse KEXDH_REPLY */ if(exchange_state->s_packet_len < 5) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet length"); + "Unexpected packet length DH-SHA"); goto clean_exit; } @@ -376,8 +469,11 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, buf.dataptr = buf.data; buf.dataptr++; /* advance past type */ - if(session->server_hostkey) + if(session->server_hostkey) { LIBSSH2_FREE(session, session->server_hostkey); + session->server_hostkey = NULL; + session->server_hostkey_len = 0; + } if(_libssh2_copy_string(session, &buf, &(session->server_hostkey), &host_key_len)) { @@ -392,11 +488,11 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, { 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); + 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 { @@ -411,8 +507,8 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's MD5 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ #endif /* ! LIBSSH2_MD5 */ @@ -420,11 +516,11 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, { 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); + 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 { @@ -435,24 +531,23 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, { char fingerprint[64], *fprint = fingerprint; int i; - for(i = 0; i < 20; i++, fprint += 3) { snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's SHA1 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ { 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); + 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 { @@ -466,10 +561,10 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, (const char *) session->server_hostkey_sha256, SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + if(base64Fingerprint) { + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Server's SHA256 Fingerprint: %s", - base64Fingerprint); + base64Fingerprint)); LIBSSH2_FREE(session, base64Fingerprint); } } @@ -477,27 +572,33 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { + session->server_hostkey_len, + &session->server_hostkey_abstract)) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); + "Unable to initialize hostkey importer " + "DH-SHA"); goto clean_exit; } if(_libssh2_get_string(&buf, &(exchange_state->f_value), &(exchange_state->f_value_len))) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get f value"); + "Unable to get DH-SHA f value"); goto clean_exit; } - _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len, - exchange_state->f_value); + if(_libssh2_bn_from_bin(exchange_state->f, + exchange_state->f_value_len, + exchange_state->f_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, + "Invalid DH-SHA f value"); + goto clean_exit; + } if(_libssh2_get_string(&buf, &(exchange_state->h_sig), &(exchange_state->h_sig_len))) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get h sig"); + "Unable to get DH-SHA h sig"); goto clean_exit; } @@ -513,127 +614,154 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, LIBSSH2_ALLOC(session, exchange_state->k_value_len); if(!exchange_state->k_value) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); + "Unable to allocate buffer for DH-SHA K"); goto clean_exit; } _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); + (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 4)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->k"); + goto clean_exit; + } } else { exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 5)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->k"); + goto clean_exit; + } } exchange_state->exchange_hash = (void *)&exchange_hash_ctx; - _libssh2_sha_algo_ctx_init(sha_algo_value, exchange_hash_ctx); - + if(!_libssh2_sha_algo_ctx_init(sha_algo_value, exchange_hash_ctx)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_HASH_INIT, + "Unable to initialize hash context"); + goto clean_exit; + } + hok = 1; if(session->local.banner) { _libssh2_htonu32(exchange_state->h_sig_comp, - 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); + (uint32_t)(strlen((char *) session->local.banner) - 2)); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, + exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + hok &= _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_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); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, + exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + hok &= _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_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)); + (uint32_t)strlen((char *) session->remote.banner)); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + hok &= _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_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); + (uint32_t)session->local.kexinit_len); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + hok &= _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_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); + (uint32_t)session->remote.kexinit_len); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + hok &= _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_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); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + session->server_hostkey, + session->server_hostkey_len); if(packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) { /* diffie-hellman-group-exchange hashes additional fields */ -#ifdef LIBSSH2_DH_GEX_NEW _libssh2_htonu32(exchange_state->h_sig_comp, LIBSSH2_DH_GEX_MINGROUP); _libssh2_htonu32(exchange_state->h_sig_comp + 4, LIBSSH2_DH_GEX_OPTGROUP); _libssh2_htonu32(exchange_state->h_sig_comp + 8, LIBSSH2_DH_GEX_MAXGROUP); - _libssh2_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_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, - exchange_state->h_sig_comp, 4); -#endif + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, + exchange_hash_ctx, + exchange_state->h_sig_comp, + 12); } if(midhash) { - _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, - midhash, midhash_len); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, + exchange_hash_ctx, + midhash, midhash_len); } - _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, - exchange_state->e_packet + 1, - exchange_state->e_packet_len - 1); + hok &= _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_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); + (uint32_t)exchange_state->f_value_len); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->f_value, + exchange_state->f_value_len); - _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, - exchange_state->k_value, - exchange_state->k_value_len); + hok &= _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->k_value, + exchange_state->k_value_len); - _libssh2_sha_algo_ctx_final(sha_algo_value, exchange_hash_ctx, - exchange_state->h_sig_comp); - - if(session->hostkey-> - sig_verify(session, exchange_state->h_sig, - exchange_state->h_sig_len, exchange_state->h_sig_comp, - digest_len, &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); + if(!hok || + !_libssh2_sha_algo_ctx_final(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_HASH_CALC, + "kex: failed to calculate hash"); goto clean_exit; } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message"); + err = session->hostkey->sig_verify(session, + exchange_state->h_sig, + exchange_state->h_sig_len, + exchange_state->h_sig_comp, + digest_len, + &session->server_hostkey_abstract); + + if(err) { + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Failed hostkey sig_verify(): %s: %d", + session->hostkey->name, err)); + ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, + "Unable to verify hostkey signature " + "DH-SHA"); + 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; @@ -646,7 +774,7 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, } else if(rc) { ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); + "Unable to send NEWKEYS message DH-SHA"); goto clean_exit; } @@ -662,13 +790,16 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, return rc; } else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); + ret = _libssh2_error(session, rc, + "Timed out waiting for NEWKEYS DH-SHA"); goto clean_exit; } + /* The first key exchange has been performed, switch to active crypt/comp/mac mode */ session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Received NEWKEYS message DH-SHA")); /* This will actually end up being just packet_type(1) for this packet type anyway */ @@ -685,8 +816,8 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, memcpy(session->session_id, exchange_state->h_sig_comp, digest_len); session->session_id_len = digest_len; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "session_id calculated")); } /* Cleanup any existing cipher */ @@ -739,8 +870,8 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server IV and Key calculated")); if(session->remote.crypt->dtor) { /* Cleanup any existing cipher */ @@ -789,8 +920,8 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client IV and Key calculated")); if(session->local.mac->dtor) { session->local.mac->dtor(session, &session->local.mac_abstract); @@ -816,8 +947,8 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server HMAC Key calculated")); if(session->remote.mac->dtor) { session->remote.mac->dtor(session, &session->remote.mac_abstract); @@ -843,8 +974,8 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client HMAC Key calculated")); /* Initialize compression for each direction */ @@ -856,13 +987,13 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, if(session->local.comp && session->local.comp->init) { if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { + &session->local.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server compression initialized")); if(session->remote.comp && session->remote.comp->dtor) { session->remote.comp->dtor(session, 0, @@ -871,43 +1002,18 @@ static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, if(session->remote.comp && session->remote.comp->init) { if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { + &session->remote.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client compression initialized")); } - clean_exit: - 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; - } - - if(exchange_state->s_packet) { - LIBSSH2_FREE(session, exchange_state->s_packet); - exchange_state->s_packet = NULL; - } - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; +clean_exit: + diffie_hellman_state_cleanup(session, exchange_state); return ret; } @@ -951,11 +1057,19 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 128, p_value); + if(!key_state->g || _libssh2_bn_set_word(key_state->g, 2)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state g."); + goto clean_exit; + } + if(!key_state->p || _libssh2_bn_from_bin(key_state->p, 128, p_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state p."); + goto clean_exit; + } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group1 Key Exchange"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group1 Key Exchange")); key_state->state = libssh2_NB_state_created; } @@ -968,11 +1082,8 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, return ret; } - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - key_state->state = libssh2_NB_state_idle; +clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -990,7 +1101,7 @@ typedef int (*diffie_hellman_hash_func_t)(LIBSSH2_SESSION *, unsigned char, unsigned char, unsigned char *, - unsigned long, + size_t, kmdhgGPshakex_state_t *); static int kex_method_diffie_hellman_group14_key_exchange(LIBSSH2_SESSION *session, @@ -1044,26 +1155,32 @@ kex_method_diffie_hellman_group14_key_exchange(LIBSSH2_SESSION *session, /* g == 2 */ /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 256, p_value); + if(!key_state->g || _libssh2_bn_set_word(key_state->g, 2)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state g."); + goto clean_exit; + } + else if(!key_state->p || + _libssh2_bn_from_bin(key_state->p, 256, p_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state p."); + goto clean_exit; + } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group14 Key Exchange"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group14 Key Exchange")); key_state->state = libssh2_NB_state_created; } ret = hashfunc(session, key_state->g, key_state->p, - 256, sha_algo_value, exchange_hash_ctx, SSH_MSG_KEXDH_INIT, - SSH_MSG_KEXDH_REPLY, NULL, 0, &key_state->exchange_state); + 256, sha_algo_value, exchange_hash_ctx, SSH_MSG_KEXDH_INIT, + SSH_MSG_KEXDH_REPLY, NULL, 0, &key_state->exchange_state); if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; +clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1080,9 +1197,9 @@ kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, { libssh2_sha1_ctx ctx; return kex_method_diffie_hellman_group14_key_exchange(session, - key_state, 1, - &ctx, - diffie_hellman_sha_algo); + key_state, 1, + &ctx, + diffie_hellman_sha_algo); } @@ -1097,9 +1214,9 @@ kex_method_diffie_hellman_group14_sha256_key_exchange(LIBSSH2_SESSION *session, { libssh2_sha256_ctx ctx; return kex_method_diffie_hellman_group14_key_exchange(session, - key_state, 256, - &ctx, - diffie_hellman_sha_algo); + key_state, 256, + &ctx, + diffie_hellman_sha_algo); } /* kex_method_diffie_hellman_group16_sha512_key_exchange @@ -1109,7 +1226,6 @@ 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, @@ -1166,11 +1282,19 @@ kex_method_diffie_hellman_group16_sha512_key_exchange(LIBSSH2_SESSION *session, /* g == 2 */ /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 512, p_value); + if(!key_state->g || _libssh2_bn_set_word(key_state->g, 2)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state g."); + goto clean_exit; + } + if(!key_state->p || _libssh2_bn_from_bin(key_state->p, 512, p_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state p."); + goto clean_exit; + } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group16 Key Exchange"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group16 Key Exchange")); key_state->state = libssh2_NB_state_created; } @@ -1183,11 +1307,8 @@ kex_method_diffie_hellman_group16_sha512_key_exchange(LIBSSH2_SESSION *session, 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; +clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1199,7 +1320,6 @@ 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, @@ -1299,11 +1419,20 @@ kex_method_diffie_hellman_group18_sha512_key_exchange(LIBSSH2_SESSION *session, /* g == 2 */ /* Initialize P and G */ - _libssh2_bn_set_word(key_state->g, 2); - _libssh2_bn_from_bin(key_state->p, 1024, p_value); + if(!key_state->g || _libssh2_bn_set_word(key_state->g, 2)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state g."); + goto clean_exit; + } + else if(!key_state->p || + _libssh2_bn_from_bin(key_state->p, 1024, p_value)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to allocate key state p."); + goto clean_exit; + } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group18 Key Exchange"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group18 Key Exchange")); key_state->state = libssh2_NB_state_created; } @@ -1316,11 +1445,8 @@ kex_method_diffie_hellman_group18_sha512_key_exchange(LIBSSH2_SESSION *session, 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; +clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1330,8 +1456,9 @@ kex_method_diffie_hellman_group18_sha512_key_exchange(LIBSSH2_SESSION *session, * Negotiates random(ish) group for secret derivation */ static int -kex_method_diffie_hellman_group_exchange_sha1_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +kex_method_diffie_hellman_group_exchange_sha1_key_exchange( + LIBSSH2_SESSION * session, + key_exchange_state_low_t * key_state) { int ret = 0; int rc; @@ -1340,23 +1467,13 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange key_state->p = _libssh2_bn_init_from_bin(); key_state->g = _libssh2_bn_init_from_bin(); /* Ask for a P and G pair */ -#ifdef LIBSSH2_DH_GEX_NEW key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP); _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP); key_state->request_len = 13; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(New Method)"); -#else - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP); - key_state->request_len = 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(Old Method)"); -#endif + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group-Exchange SHA1")); key_state->state = libssh2_NB_state_created; } @@ -1400,7 +1517,7 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange if(key_state->data_len < 9) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected key length DH-SHA1"); goto dh_gex_clean_exit; } @@ -1412,21 +1529,30 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange if(_libssh2_get_bignum_bytes(&buf, &p, &p_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); + "Unexpected value DH-SHA1 p"); goto dh_gex_clean_exit; } if(_libssh2_get_bignum_bytes(&buf, &g, &g_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); + "Unexpected value DH-SHA1 g"); goto dh_gex_clean_exit; } - _libssh2_bn_from_bin(key_state->p, p_len, p); - _libssh2_bn_from_bin(key_state->g, g_len, g); + if(_libssh2_bn_from_bin(key_state->p, p_len, p)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DH-SHA1 p"); + goto dh_gex_clean_exit; + } + + if(_libssh2_bn_from_bin(key_state->g, g_len, g)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DH-SHA1 g"); + goto dh_gex_clean_exit; + } ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, - p_len, 1, + (int)p_len, 1, (void *)&exchange_hash_ctx, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, @@ -1436,16 +1562,10 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - - LIBSSH2_FREE(session, key_state->data); } - dh_gex_clean_exit: - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; +dh_gex_clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } @@ -1457,8 +1577,9 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange * Negotiates random(ish) group for secret derivation */ static int -kex_method_diffie_hellman_group_exchange_sha256_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +kex_method_diffie_hellman_group_exchange_sha256_key_exchange( + LIBSSH2_SESSION * session, + key_exchange_state_low_t * key_state) { int ret = 0; int rc; @@ -1467,23 +1588,13 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange key_state->p = _libssh2_bn_init(); key_state->g = _libssh2_bn_init(); /* Ask for a P and G pair */ -#ifdef LIBSSH2_DH_GEX_NEW key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP); _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP); key_state->request_len = 13; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(New Method SHA256)"); -#else - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP); - key_state->request_len = 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(Old Method SHA256)"); -#endif + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group-Exchange SHA256")); key_state->state = libssh2_NB_state_created; } @@ -1528,7 +1639,7 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange if(key_state->data_len < 9) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected key length DH-SHA256"); goto dh_gex_clean_exit; } @@ -1540,21 +1651,30 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange if(_libssh2_get_bignum_bytes(&buf, &p, &p_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); + "Unexpected value DH-SHA256 p"); goto dh_gex_clean_exit; } if(_libssh2_get_bignum_bytes(&buf, &g, &g_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); + "Unexpected value DH-SHA256 g"); goto dh_gex_clean_exit; } - _libssh2_bn_from_bin(key_state->p, p_len, p); - _libssh2_bn_from_bin(key_state->g, g_len, g); + if(_libssh2_bn_from_bin(key_state->p, p_len, p)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DH-SHA256 p"); + goto dh_gex_clean_exit; + } + + if(_libssh2_bn_from_bin(key_state->g, g_len, g)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DH-SHA256 g"); + goto dh_gex_clean_exit; + } ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, - p_len, 256, + (int)p_len, 256, (void *)&exchange_hash_ctx, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, @@ -1564,20 +1684,15 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - - LIBSSH2_FREE(session, key_state->data); } - dh_gex_clean_exit: - key_state->state = libssh2_NB_state_idle; - _libssh2_bn_free(key_state->g); - key_state->g = NULL; - _libssh2_bn_free(key_state->p); - key_state->p = NULL; +dh_gex_clean_exit: + kex_diffie_hellman_cleanup(session, key_state); return ret; } +#if LIBSSH2_ECDSA /* LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY * @@ -1595,100 +1710,103 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange * mpint K, shared secret * */ - -#define LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(digest_type) \ -{ \ - libssh2_sha##digest_type##_ctx ctx; \ - exchange_state->exchange_hash = (void *)&ctx; \ - libssh2_sha##digest_type##_init(&ctx); \ - if(session->local.banner) { \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - strlen((char *) session->local.banner) - 2); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - (char *) session->local.banner, \ - strlen((char *) \ - session->local.banner) \ - - 2); \ - } \ - else { \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - LIBSSH2_SSH_DEFAULT_BANNER, \ +#define LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(digest_type) \ +do { \ + libssh2_sha##digest_type##_ctx ctx; \ + int hok; \ + if(!libssh2_sha##digest_type##_init(&ctx)) { \ + rc = -1; \ + break; \ + } \ + exchange_state->exchange_hash = (void *)&ctx; \ + hok = 1; \ + if(session->local.banner) { \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)(strlen((char *) session->local.banner) - 2)); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, \ + 4); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + (char *)session->local.banner, \ + strlen((char *)session->local.banner) \ + - 2); \ + } \ + else { \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + LIBSSH2_SSH_DEFAULT_BANNER, \ sizeof(LIBSSH2_SSH_DEFAULT_BANNER) \ - - 1); \ - } \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - strlen((char *) session->remote.banner)); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->remote.banner, \ - strlen((char *) \ - session->remote.banner)); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->local.kexinit_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->local.kexinit, \ - session->local.kexinit_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->remote.kexinit_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->remote.kexinit, \ - session->remote.kexinit_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->server_hostkey_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->server_hostkey, \ - session->server_hostkey_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - public_key_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - public_key, \ - public_key_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - server_public_key_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - server_public_key, \ - server_public_key_len); \ - \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->k_value, \ - exchange_state->k_value_len); \ - \ - libssh2_sha##digest_type##_final(ctx, exchange_state->h_sig_comp); \ - \ - if(session->hostkey-> \ - sig_verify(session, exchange_state->h_sig, \ - exchange_state->h_sig_len, exchange_state->h_sig_comp, \ - SHA##digest_type##_DIGEST_LENGTH, \ - &session->server_hostkey_abstract)) { \ - rc = -1; \ - } \ -} \ - - -#if LIBSSH2_ECDSA + - 1); \ + } \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)strlen((char *) session->remote.banner)); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + hok &= libssh2_sha##digest_type##_update(ctx, session->remote.banner, \ + strlen((char *)session->remote.banner)); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)session->local.kexinit_len); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + session->local.kexinit, \ + session->local.kexinit_len); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)session->remote.kexinit_len); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + session->remote.kexinit, \ + session->remote.kexinit_len); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + session->server_hostkey_len); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + session->server_hostkey, \ + session->server_hostkey_len); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)public_key_len); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + public_key, \ + public_key_len); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)server_public_key_len); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + server_public_key, \ + server_public_key_len); \ + \ + hok &= libssh2_sha##digest_type##_update(ctx, \ + exchange_state->k_value, \ + exchange_state->k_value_len); \ + \ + if(!hok || \ + !libssh2_sha##digest_type##_final(ctx, exchange_state->h_sig_comp)) { \ + rc = -1; \ + break; \ + } \ + \ + if(session->hostkey-> \ + sig_verify(session, exchange_state->h_sig, \ + exchange_state->h_sig_len, exchange_state->h_sig_comp, \ + SHA##digest_type##_DIGEST_LENGTH, \ + &session->server_hostkey_abstract)) { \ + rc = -1; \ + } \ +} while(0) /* kex_session_ecdh_curve_type * returns the EC curve type by name used in key exchange @@ -1697,10 +1815,9 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange static int kex_session_ecdh_curve_type(const char *name, libssh2_curve_type *out_type) { - int ret = 0; libssh2_curve_type type; - if(name == NULL) + if(!name) return -1; if(strcmp(name, "ecdh-sha2-nistp256") == 0) @@ -1710,14 +1827,57 @@ kex_session_ecdh_curve_type(const char *name, libssh2_curve_type *out_type) else if(strcmp(name, "ecdh-sha2-nistp521") == 0) type = LIBSSH2_EC_CURVE_NISTP521; else { - ret = -1; + return -1; } - if(ret == 0 && out_type) { + if(out_type) { *out_type = type; } - return ret; + return 0; +} + + +static void +ecdh_exchange_state_cleanup(LIBSSH2_SESSION * session, + kmdhgGPshakex_state_t *exchange_state) +{ + _libssh2_bn_free(exchange_state->k); + exchange_state->k = NULL; + + if(exchange_state->k_value) { + LIBSSH2_FREE(session, exchange_state->k_value); + exchange_state->k_value = NULL; + } + + exchange_state->state = libssh2_NB_state_idle; +} + + +static void +kex_method_ecdh_cleanup +(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +{ + if(key_state->public_key_oct) { + LIBSSH2_FREE(session, key_state->public_key_oct); + key_state->public_key_oct = NULL; + } + + if(key_state->private_key) { + _libssh2_ecdsa_free(key_state->private_key); + key_state->private_key = NULL; + } + + if(key_state->data) { + LIBSSH2_FREE(session, key_state->data); + key_state->data = NULL; + } + + key_state->state = libssh2_NB_state_idle; + + if(key_state->exchange_state.state != libssh2_NB_state_idle) { + ecdh_exchange_state_cleanup(session, &key_state->exchange_state); + } } @@ -1736,7 +1896,7 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, if(data_len < 5) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Host key data is too short"); + "Host key data is too short"); return ret; } @@ -1761,11 +1921,11 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, buf.dataptr = buf.data; buf.dataptr++; /* Advance past packet type */ - if(_libssh2_copy_string(session, &buf, &(session->server_hostkey), + if(_libssh2_copy_string(session, &buf, &(session->server_hostkey), &server_public_key_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for a copy " - "of the host key"); + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for a copy " + "of the host ECDH key"); goto clean_exit; } @@ -1775,11 +1935,11 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, { 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); + 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 { @@ -1794,8 +1954,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's MD5 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ #endif /* ! LIBSSH2_MD5 */ @@ -1803,11 +1963,11 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, { 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); + 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 { @@ -1818,13 +1978,12 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, { char fingerprint[64], *fprint = fingerprint; int i; - for(i = 0; i < 20; i++, fprint += 3) { snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's SHA1 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ @@ -1832,11 +1991,11 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, { 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); + 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 { @@ -1850,20 +2009,21 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, (const char *) session->server_hostkey_sha256, SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + if(base64Fingerprint) { + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Server's SHA256 Fingerprint: %s", - base64Fingerprint); + base64Fingerprint)); LIBSSH2_FREE(session, base64Fingerprint); } } #endif /* LIBSSH2DEBUG */ if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { + session->server_hostkey_len, + &session->server_hostkey_abstract)) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); + "Unable to initialize hostkey importer " + "ECDH"); goto clean_exit; } @@ -1871,7 +2031,7 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, if(_libssh2_get_string(&buf, &server_public_key, &server_public_key_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected key length ECDH"); goto clean_exit; } @@ -1879,14 +2039,14 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, 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"); + "Unexpected ECDH server sig length"); goto clean_exit; } /* Compute the shared secret K */ rc = _libssh2_ecdh_gen_k(&exchange_state->k, private_key, server_public_key, server_public_key_len); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to create ECDH shared secret"); goto clean_exit; @@ -1901,17 +2061,27 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_ALLOC(session, exchange_state->k_value_len); if(!exchange_state->k_value) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); + "Unable to allocate buffer for ECDH K"); goto clean_exit; } _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); + (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 4)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->k"); + goto clean_exit; + } } else { exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 5)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } /* verify hash */ @@ -1920,7 +2090,6 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, case LIBSSH2_EC_CURVE_NISTP256: LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(256); break; - case LIBSSH2_EC_CURVE_NISTP384: LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(384); break; @@ -1929,9 +2098,10 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, break; } - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); + "Unable to verify hostkey signature " + "ECDH"); goto clean_exit; } @@ -1946,7 +2116,7 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, } else if(rc) { ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); + "Unable to send NEWKEYS message ECDH"); goto clean_exit; } @@ -1962,17 +2132,19 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, return rc; } else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); + ret = _libssh2_error(session, rc, + "Timed out waiting for NEWKEYS ECDH"); goto clean_exit; } /* The first key exchange has been performed, - switch to active crypt/comp/mac mode */ + switch to active crypt/comp/mac mode */ session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Received NEWKEYS message ECDH")); /* This will actually end up being just packet_type(1) - for this packet type anyway */ + for this packet type anyway */ LIBSSH2_FREE(session, exchange_state->tmp); if(!session->session_id) { @@ -2000,9 +2172,9 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, } memcpy(session->session_id, exchange_state->h_sig_comp, digest_length); - session->session_id_len = digest_length; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); + session->session_id_len = (uint32_t)digest_length; + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "session_id calculated")); } /* Cleanup any existing cipher */ @@ -2025,8 +2197,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, } LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(secret, - session->local.crypt-> - secret_len, "C"); + session->local.crypt-> + secret_len, "C"); if(!secret) { LIBSSH2_FREE(session, iv); @@ -2053,8 +2225,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server IV and Key calculated")); if(session->remote.crypt->dtor) { /* Cleanup any existing cipher */ @@ -2103,8 +2275,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client IV and Key calculated")); if(session->local.mac->dtor) { session->local.mac->dtor(session, &session->local.mac_abstract); @@ -2130,8 +2302,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server HMAC Key calculated")); if(session->remote.mac->dtor) { session->remote.mac->dtor(session, &session->remote.mac_abstract); @@ -2157,8 +2329,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client HMAC Key calculated")); /* Initialize compression for each direction */ @@ -2170,13 +2342,13 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, if(session->local.comp && session->local.comp->init) { if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { + &session->local.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server compression initialized")); if(session->remote.comp && session->remote.comp->dtor) { session->remote.comp->dtor(session, 0, @@ -2185,26 +2357,17 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, if(session->remote.comp && session->remote.comp->init) { if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { + &session->remote.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); - + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client compression initialized")); } clean_exit: - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; + ecdh_exchange_state_cleanup(session, exchange_state); return ret; } @@ -2212,10 +2375,9 @@ clean_exit: /* kex_method_ecdh_key_exchange * * Elliptic Curve Diffie Hellman Key Exchange - * supports SHA256/384/512 hashes based on negotated ecdh method + * supports SHA256/384/512 hashes based on negotiated ecdh method * */ - static int kex_method_ecdh_key_exchange (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) @@ -2234,7 +2396,7 @@ kex_method_ecdh_key_exchange if(key_state->state == libssh2_NB_state_created) { rc = kex_session_ecdh_curve_type(session->kex->name, &type); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, -1, "Unknown KEX nistp curve type"); goto ecdh_clean_exit; @@ -2244,7 +2406,7 @@ kex_method_ecdh_key_exchange &key_state->public_key_oct, &key_state->public_key_oct_len, type); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, rc, "Unable to create private key"); goto ecdh_clean_exit; @@ -2256,8 +2418,8 @@ kex_method_ecdh_key_exchange key_state->public_key_oct_len); key_state->request_len = key_state->public_key_oct_len + 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating ECDH SHA2 NISTP256"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating ECDH SHA2 NISTP256")); key_state->state = libssh2_NB_state_sent; } @@ -2295,7 +2457,13 @@ kex_method_ecdh_key_exchange if(key_state->state == libssh2_NB_state_sent2) { - (void)kex_session_ecdh_curve_type(session->kex->name, &type); + rc = kex_session_ecdh_curve_type(session->kex->name, &type); + + if(rc) { + ret = _libssh2_error(session, -1, + "Unknown KEX nistp curve type"); + goto ecdh_clean_exit; + } ret = ecdh_sha2_nistp(session, type, key_state->data, key_state->data_len, @@ -2307,36 +2475,68 @@ kex_method_ecdh_key_exchange if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - - LIBSSH2_FREE(session, key_state->data); } ecdh_clean_exit: - if(key_state->public_key_oct) { - LIBSSH2_FREE(session, key_state->public_key_oct); - key_state->public_key_oct = NULL; - } - - if(key_state->private_key) { - _libssh2_ecdsa_free(key_state->private_key); - key_state->private_key = NULL; - } - - key_state->state = libssh2_NB_state_idle; + kex_method_ecdh_cleanup(session, key_state); return ret; } -#endif /*LIBSSH2_ECDSA*/ +#endif /* LIBSSH2_ECDSA */ #if LIBSSH2_ED25519 +static void +curve25519_exchange_state_cleanup(LIBSSH2_SESSION * session, + kmdhgGPshakex_state_t *exchange_state) +{ + _libssh2_bn_free(exchange_state->k); + exchange_state->k = NULL; + + if(exchange_state->k_value) { + LIBSSH2_FREE(session, exchange_state->k_value); + exchange_state->k_value = NULL; + } + + exchange_state->state = libssh2_NB_state_idle; +} + +static void +kex_method_curve25519_cleanup +(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +{ + if(key_state->curve25519_public_key) { + _libssh2_explicit_zero(key_state->curve25519_public_key, + LIBSSH2_ED25519_KEY_LEN); + LIBSSH2_FREE(session, key_state->curve25519_public_key); + key_state->curve25519_public_key = NULL; + } + + if(key_state->curve25519_private_key) { + _libssh2_explicit_zero(key_state->curve25519_private_key, + LIBSSH2_ED25519_KEY_LEN); + LIBSSH2_FREE(session, key_state->curve25519_private_key); + key_state->curve25519_private_key = NULL; + } + + if(key_state->data) { + LIBSSH2_FREE(session, key_state->data); + key_state->data = NULL; + } + + key_state->state = libssh2_NB_state_idle; + + if(key_state->exchange_state.state != libssh2_NB_state_idle) { + curve25519_exchange_state_cleanup(session, &key_state->exchange_state); + } +} + /* curve25519_sha256 * Elliptic Curve Key Exchange */ - static int curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, size_t data_len, @@ -2369,7 +2569,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(data_len < 5) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected curve25519 key length 1"); goto clean_exit; } @@ -2380,7 +2580,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(_libssh2_get_string(&buf, &server_host_key, &hostkey_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected curve25519 key length 2"); goto clean_exit; } @@ -2390,7 +2590,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(!session->server_hostkey) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for a copy " - "of the host key"); + "of the host curve25519 key"); goto clean_exit; } @@ -2401,11 +2601,11 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, { 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); + 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 { @@ -2420,8 +2620,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's MD5 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ #endif /* ! LIBSSH2_MD5 */ @@ -2429,11 +2629,11 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, { 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); + 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 { @@ -2444,13 +2644,12 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, { char fingerprint[64], *fprint = fingerprint; int i; - for(i = 0; i < 20; i++, fprint += 3) { snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's SHA1 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ @@ -2458,11 +2657,11 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, { 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); + 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 { @@ -2476,20 +2675,21 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, (const char *) session->server_hostkey_sha256, SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + if(base64Fingerprint) { + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Server's SHA256 Fingerprint: %s", - base64Fingerprint); + base64Fingerprint)); LIBSSH2_FREE(session, base64Fingerprint); } } #endif /* LIBSSH2DEBUG */ if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { + session->server_hostkey_len, + &session->server_hostkey_abstract)) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); + "Unable to initialize hostkey importer " + "curve25519"); goto clean_exit; } @@ -2497,7 +2697,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(_libssh2_get_string(&buf, &server_public_key, &server_public_key_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected curve25519 key length"); goto clean_exit; } @@ -2519,9 +2719,9 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, /* Compute the shared secret K */ rc = _libssh2_curve25519_gen_k(&exchange_state->k, private_key, server_public_key); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, - "Unable to create ECDH shared secret"); + "Unable to create curve25519 shared secret"); goto clean_exit; } @@ -2538,21 +2738,32 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, goto clean_exit; } _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); + (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 4)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } else { exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); + if(_libssh2_bn_to_bin(exchange_state->k, + exchange_state->k_value + 5)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Can't write exchange_state->e"); + goto clean_exit; + } } /*/ verify hash */ LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(256); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); + "Unable to verify hostkey signature " + "curve25519"); goto clean_exit; } @@ -2567,7 +2778,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, } else if(rc) { ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); + "Unable to send NEWKEYS message curve25519"); goto clean_exit; } @@ -2583,18 +2794,19 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, return rc; } else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); + ret = _libssh2_error(session, rc, + "Timed out waiting for NEWKEYS curve25519"); goto clean_exit; } - /* The first key exchange has been performed, switch to active - crypt/comp/mac mode */ - + /* The first key exchange has been performed, + switch to active crypt/comp/mac mode */ session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Received NEWKEYS message curve25519")); - /* This will actually end up being just packet_type(1) for this packet - type anyway */ + /* This will actually end up being just packet_type(1) + for this packet type anyway */ LIBSSH2_FREE(session, exchange_state->tmp); if(!session->session_id) { @@ -2603,21 +2815,21 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, session->session_id = LIBSSH2_ALLOC(session, digest_length); if(!session->session_id) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allxcocate buffer for " + "Unable to allocate buffer for " "SHA digest"); goto clean_exit; } memcpy(session->session_id, exchange_state->h_sig_comp, digest_length); - session->session_id_len = digest_length; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); + session->session_id_len = (uint32_t)digest_length; + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "session_id calculated")); } /* Cleanup any existing cipher */ if(session->local.crypt->dtor) { session->local.crypt->dtor(session, - &session->local.crypt_abstract); + &session->local.crypt_abstract); } /* Calculate IV/Secret/Key for each direction */ @@ -2662,8 +2874,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server IV and Key calculated")); if(session->remote.crypt->dtor) { /* Cleanup any existing cipher */ @@ -2712,8 +2924,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client IV and Key calculated")); if(session->local.mac->dtor) { session->local.mac->dtor(session, &session->local.mac_abstract); @@ -2739,8 +2951,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server HMAC Key calculated")); if(session->remote.mac->dtor) { session->remote.mac->dtor(session, &session->remote.mac_abstract); @@ -2766,8 +2978,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client HMAC Key calculated")); /* Initialize compression for each direction */ @@ -2779,40 +2991,32 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(session->local.comp && session->local.comp->init) { if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { + &session->local.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server compression initialized")); if(session->remote.comp && session->remote.comp->dtor) { session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); + &session->remote.comp_abstract); } if(session->remote.comp && session->remote.comp->init) { if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { + &session->remote.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client compression initialized")); } clean_exit: - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; - } - - exchange_state->state = libssh2_NB_state_idle; + curve25519_exchange_state_cleanup(session, exchange_state); return ret; } @@ -2822,7 +3026,6 @@ clean_exit: * Elliptic Curve X25519 Key Exchange with SHA256 hash * */ - static int kex_method_curve25519_key_exchange (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) @@ -2840,10 +3043,10 @@ kex_method_curve25519_key_exchange unsigned char *s = NULL; rc = strcmp(session->kex->name, "curve25519-sha256@libssh.org"); - if(rc != 0) + if(rc) rc = strcmp(session->kex->name, "curve25519-sha256"); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, -1, "Unknown KEX curve25519 curve type"); goto clean_exit; @@ -2853,7 +3056,7 @@ kex_method_curve25519_key_exchange &key_state->curve25519_public_key, &key_state->curve25519_private_key); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, rc, "Unable to create private key"); goto clean_exit; @@ -2865,8 +3068,8 @@ kex_method_curve25519_key_exchange LIBSSH2_ED25519_KEY_LEN); key_state->request_len = LIBSSH2_ED25519_KEY_LEN + 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating curve25519 SHA2"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating curve25519 SHA2")); key_state->state = libssh2_NB_state_sent; } @@ -2912,33 +3115,17 @@ kex_method_curve25519_key_exchange if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } - - LIBSSH2_FREE(session, key_state->data); } clean_exit: - if(key_state->curve25519_public_key) { - _libssh2_explicit_zero(key_state->curve25519_public_key, - LIBSSH2_ED25519_KEY_LEN); - LIBSSH2_FREE(session, key_state->curve25519_public_key); - key_state->curve25519_public_key = NULL; - } - - if(key_state->curve25519_private_key) { - _libssh2_explicit_zero(key_state->curve25519_private_key, - LIBSSH2_ED25519_KEY_LEN); - LIBSSH2_FREE(session, key_state->curve25519_private_key); - key_state->curve25519_private_key = NULL; - } - - key_state->state = libssh2_NB_state_idle; + kex_method_curve25519_cleanup(session, key_state); return ret; } -#endif /*LIBSSH2_ED25519*/ +#endif /* LIBSSH2_ED25519 */ #define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001 @@ -2947,30 +3134,35 @@ clean_exit: static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group1_sha1 = { "diffie-hellman-group1-sha1", kex_method_diffie_hellman_group1_sha1_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha1 = { "diffie-hellman-group14-sha1", kex_method_diffie_hellman_group14_sha1_key_exchange, + kex_diffie_hellman_cleanup, 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, + kex_diffie_hellman_cleanup, 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, + kex_diffie_hellman_cleanup, 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, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -2978,6 +3170,7 @@ static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group_exchange_sha1 = { "diffie-hellman-group-exchange-sha1", kex_method_diffie_hellman_group_exchange_sha1_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -2985,6 +3178,7 @@ static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group_exchange_sha256 = { "diffie-hellman-group-exchange-sha256", kex_method_diffie_hellman_group_exchange_sha256_key_exchange, + kex_diffie_hellman_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -2993,6 +3187,7 @@ static const LIBSSH2_KEX_METHOD kex_method_ecdh_sha2_nistp256 = { "ecdh-sha2-nistp256", kex_method_ecdh_key_exchange, + kex_method_ecdh_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -3000,6 +3195,7 @@ static const LIBSSH2_KEX_METHOD kex_method_ecdh_sha2_nistp384 = { "ecdh-sha2-nistp384", kex_method_ecdh_key_exchange, + kex_method_ecdh_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; @@ -3007,6 +3203,7 @@ static const LIBSSH2_KEX_METHOD kex_method_ecdh_sha2_nistp521 = { "ecdh-sha2-nistp521", kex_method_ecdh_key_exchange, + kex_method_ecdh_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; #endif @@ -3016,16 +3213,38 @@ static const LIBSSH2_KEX_METHOD kex_method_ssh_curve25519_sha256_libssh = { "curve25519-sha256@libssh.org", kex_method_curve25519_key_exchange, + kex_method_curve25519_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; static const LIBSSH2_KEX_METHOD kex_method_ssh_curve25519_sha256 = { "curve25519-sha256", kex_method_curve25519_key_exchange, + kex_method_curve25519_cleanup, LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; #endif +/* this kex method signals that client can receive extensions + * as described in https://datatracker.ietf.org/doc/html/rfc8308 +*/ + +static const LIBSSH2_KEX_METHOD +kex_method_extension_negotiation = { + "ext-info-c", + NULL, + NULL, + 0, +}; + +static const LIBSSH2_KEX_METHOD +kex_method_strict_client_extension = { + "kex-strict-c-v00@openssh.com", + NULL, + NULL, + 0, +}; + static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = { #if LIBSSH2_ED25519 &kex_method_ssh_curve25519_sha256, @@ -3043,7 +3262,9 @@ static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = { &kex_method_diffie_helman_group14_sha1, &kex_method_diffie_helman_group1_sha1, &kex_method_diffie_helman_group_exchange_sha1, - NULL + &kex_method_extension_negotiation, + &kex_method_strict_client_extension, + NULL }; typedef struct _LIBSSH2_COMMON_METHOD @@ -3052,6 +3273,7 @@ typedef struct _LIBSSH2_COMMON_METHOD } LIBSSH2_COMMON_METHOD; /* kex_method_strlen + * * Calculate the length of a particular method list's resulting string * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 * (because the last coma isn't used) @@ -3079,8 +3301,8 @@ kex_method_strlen(LIBSSH2_COMMON_METHOD ** method) /* kex_method_list * Generate formatted preference list in buf */ -static size_t -kex_method_list(unsigned char *buf, size_t list_strlen, +static uint32_t +kex_method_list(unsigned char *buf, uint32_t list_strlen, LIBSSH2_COMMON_METHOD ** method) { _libssh2_htonu32(buf, list_strlen); @@ -3091,7 +3313,7 @@ kex_method_list(unsigned char *buf, size_t list_strlen, } while(*method && (*method)->name) { - int mlen = strlen((*method)->name); + uint32_t mlen = (uint32_t)strlen((*method)->name); memcpy(buf, (*method)->name, mlen); buf += mlen; *(buf++) = ','; @@ -3104,20 +3326,22 @@ kex_method_list(unsigned char *buf, size_t list_strlen, #define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) \ - ((prefvar) ? strlen(prefvar) : \ - kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar))) + (uint32_t)((prefvar) ? strlen(prefvar) : \ + kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar))) -#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \ - if(prefvar) { \ - _libssh2_htonu32((buf), (prefvarlen)); \ - buf += 4; \ - memcpy((buf), (prefvar), (prefvarlen)); \ - buf += (prefvarlen); \ - } \ - else { \ - buf += kex_method_list((buf), (prefvarlen), \ - (LIBSSH2_COMMON_METHOD**)(defaultvar)); \ - } +#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \ + do { \ + if(prefvar) { \ + _libssh2_htonu32((buf), (prefvarlen)); \ + buf += 4; \ + memcpy((buf), (prefvar), (prefvarlen)); \ + buf += (prefvarlen); \ + } \ + else { \ + buf += kex_method_list((buf), (prefvarlen), \ + (LIBSSH2_COMMON_METHOD**)(defaultvar)); \ + } \ + } while(0) /* kexinit * Send SSH_MSG_KEXINIT packet @@ -3127,15 +3351,16 @@ static int kexinit(LIBSSH2_SESSION * session) /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) + reserved(4) + length longs(40) */ size_t data_len = 62; - size_t kex_len, hostkey_len = 0; - size_t crypt_cs_len, crypt_sc_len; - size_t comp_cs_len, comp_sc_len; - size_t mac_cs_len, mac_sc_len; - size_t lang_cs_len, lang_sc_len; unsigned char *data, *s; int rc; if(session->kexinit_state == libssh2_NB_state_idle) { + uint32_t kex_len, hostkey_len; + uint32_t crypt_cs_len, crypt_sc_len; + uint32_t comp_cs_len, comp_sc_len; + uint32_t mac_cs_len, mac_sc_len; + uint32_t lang_cs_len, lang_sc_len; + kex_len = LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods); hostkey_len = @@ -3165,8 +3390,8 @@ static int kexinit(LIBSSH2_SESSION * session) LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL); data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len + - comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len + - lang_cs_len + lang_sc_len; + comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len + + lang_cs_len + lang_sc_len; s = data = LIBSSH2_ALLOC(session, data_len); if(!data) { @@ -3222,25 +3447,35 @@ static int kexinit(LIBSSH2_SESSION * session) /* Funnily enough, they'll all "appear" to be '\0' terminated */ unsigned char *p = data + 21; /* type(1) + cookie(16) + len(4) */ - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent KEX: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent KEX: %s", p)); p += kex_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent HOSTKEY: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent HOSTKEY: %s", p)); p += hostkey_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_CS: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent CRYPT_CS: %s", p)); p += crypt_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_SC: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent CRYPT_SC: %s", p)); p += crypt_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_CS: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent MAC_CS: %s", p)); p += mac_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_SC: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent MAC_SC: %s", p)); p += mac_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_CS: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent COMP_CS: %s", p)); p += comp_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_SC: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent COMP_SC: %s", p)); p += comp_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_CS: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent LANG_CS: %s", p)); p += lang_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_SC: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent LANG_SC: %s", p)); p += lang_sc_len + 4; } #endif /* LIBSSH2DEBUG */ @@ -3281,19 +3516,19 @@ static int kexinit(LIBSSH2_SESSION * session) return 0; } -/* kex_agree_instr +/* _libssh2_kex_agree_instr * Kex specific variant of strstr() - * Needle must be precede by BOL or ',', and followed by ',' or EOL + * Needle must be preceded by BOL or ',', and followed by ',' or EOL */ -static unsigned char * -kex_agree_instr(unsigned char *haystack, unsigned long haystack_len, - const unsigned char *needle, unsigned long needle_len) +unsigned char * +_libssh2_kex_agree_instr(unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) { unsigned char *s; unsigned char *end_haystack; - unsigned long left; + size_t left; - if(haystack == NULL || needle == NULL) { + if(!haystack || !needle) { return NULL; } @@ -3314,11 +3549,13 @@ kex_agree_instr(unsigned char *haystack, unsigned long haystack_len, /* Search until we run out of comas or we run out of haystack, whichever comes first */ - while((s = (unsigned char *) memchr((char *) s, ',', left))) { + /* !checksrc! disable EQUALSNULL 1 */ + while((s = (unsigned char *) memchr((char *) s, ',', left)) != NULL) { /* Advance buffer past coma if we can */ left = end_haystack - s; if((left >= 1) && (left <= haystack_len) && (left > needle_len)) { s++; + left--; } else { return NULL; @@ -3359,8 +3596,8 @@ kex_get_method_by_name(const char *name, size_t name_len, * Agree on a Hostkey which works with this kex */ static int kex_agree_hostkey(LIBSSH2_SESSION * session, - unsigned long kex_flags, - unsigned char *hostkey, unsigned long hostkey_len) + size_t kex_flags, + unsigned char *hostkey, size_t hostkey_len) { const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods(); unsigned char *s; @@ -3371,7 +3608,7 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session, while(s && *s) { unsigned char *p = (unsigned char *) strchr((char *) s, ','); size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - if(kex_agree_instr(hostkey, hostkey_len, s, method_len)) { + if(_libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) { const LIBSSH2_HOSTKEY_METHOD *method = (const LIBSSH2_HOSTKEY_METHOD *) kex_get_method_by_name((char *) s, method_len, @@ -3405,9 +3642,9 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session, } while(hostkeyp && (*hostkeyp) && (*hostkeyp)->name) { - s = kex_agree_instr(hostkey, hostkey_len, - (unsigned char *) (*hostkeyp)->name, - strlen((*hostkeyp)->name)); + s = _libssh2_kex_agree_instr(hostkey, hostkey_len, + (unsigned char *) (*hostkeyp)->name, + strlen((*hostkeyp)->name)); if(s) { /* So far so good, but does it suit our purposes? (Encrypting vs Signing) */ @@ -3436,11 +3673,17 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session, * Agree on a Key Exchange method and a hostkey encoding type */ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, - unsigned long kex_len, unsigned char *hostkey, - unsigned long hostkey_len) + size_t kex_len, unsigned char *hostkey, + size_t hostkey_len) { const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods; unsigned char *s; + const unsigned char *strict = + (unsigned char *)"kex-strict-s-v00@openssh.com"; + + if(_libssh2_kex_agree_instr(kex, kex_len, strict, 28)) { + session->kex_strict = 1; + } if(session->kex_prefs) { s = (unsigned char *) session->kex_prefs; @@ -3448,7 +3691,7 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, while(s && *s) { unsigned char *q, *p = (unsigned char *) strchr((char *) s, ','); size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - q = kex_agree_instr(kex, kex_len, s, method_len); + q = _libssh2_kex_agree_instr(kex, kex_len, s, method_len); if(q) { const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *) kex_get_method_by_name((char *) s, method_len, @@ -3464,7 +3707,7 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, * Can we agree on a hostkey that works with this kex? */ if(kex_agree_hostkey(session, method->flags, hostkey, - hostkey_len) == 0) { + hostkey_len) == 0) { session->kex = method; if(session->burn_optimistic_kexinit && (kex == q)) { /* Server sent an optimistic packet, and client agrees @@ -3482,15 +3725,15 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, } while(*kexp && (*kexp)->name) { - s = kex_agree_instr(kex, kex_len, - (unsigned char *) (*kexp)->name, - strlen((*kexp)->name)); + s = _libssh2_kex_agree_instr(kex, kex_len, + (unsigned char *) (*kexp)->name, + strlen((*kexp)->name)); if(s) { /* We've agreed on a key exchange method, * Can we agree on a hostkey that works with this kex? */ if(kex_agree_hostkey(session, (*kexp)->flags, hostkey, - hostkey_len) == 0) { + hostkey_len) == 0) { session->kex = *kexp; if(session->burn_optimistic_kexinit && (kex == s)) { /* Server sent an optimistic packet, and client agrees @@ -3514,12 +3757,12 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, static int kex_agree_crypt(LIBSSH2_SESSION * session, libssh2_endpoint_data *endpoint, unsigned char *crypt, - unsigned long crypt_len) + size_t crypt_len) { const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods(); unsigned char *s; - (void) session; + (void)session; if(endpoint->crypt_prefs) { s = (unsigned char *) endpoint->crypt_prefs; @@ -3528,7 +3771,7 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session, unsigned char *p = (unsigned char *) strchr((char *) s, ','); size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - if(kex_agree_instr(crypt, crypt_len, s, method_len)) { + if(_libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) { const LIBSSH2_CRYPT_METHOD *method = (const LIBSSH2_CRYPT_METHOD *) kex_get_method_by_name((char *) s, method_len, @@ -3550,9 +3793,9 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session, } while(*cryptp && (*cryptp)->name) { - s = kex_agree_instr(crypt, crypt_len, - (unsigned char *) (*cryptp)->name, - strlen((*cryptp)->name)); + s = _libssh2_kex_agree_instr(crypt, crypt_len, + (unsigned char *) (*cryptp)->name, + strlen((*cryptp)->name)); if(s) { endpoint->crypt = *cryptp; return 0; @@ -3570,11 +3813,20 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session, */ static int kex_agree_mac(LIBSSH2_SESSION * session, libssh2_endpoint_data * endpoint, unsigned char *mac, - unsigned long mac_len) + size_t mac_len) { const LIBSSH2_MAC_METHOD **macp = _libssh2_mac_methods(); + const LIBSSH2_MAC_METHOD *override; unsigned char *s; - (void) session; + (void)session; + + override = _libssh2_mac_override(endpoint->crypt); + if(override) { + /* This crypto method has its own hmac method built-in, so a separate + * negotiation (and use) of a separate hmac method is unnecessary */ + endpoint->mac = override; + return 0; + } if(endpoint->mac_prefs) { s = (unsigned char *) endpoint->mac_prefs; @@ -3583,7 +3835,7 @@ static int kex_agree_mac(LIBSSH2_SESSION * session, unsigned char *p = (unsigned char *) strchr((char *) s, ','); size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - if(kex_agree_instr(mac, mac_len, s, method_len)) { + if(_libssh2_kex_agree_instr(mac, mac_len, s, method_len)) { const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *) kex_get_method_by_name((char *) s, method_len, (const LIBSSH2_COMMON_METHOD **) @@ -3604,8 +3856,9 @@ static int kex_agree_mac(LIBSSH2_SESSION * session, } while(*macp && (*macp)->name) { - s = kex_agree_instr(mac, mac_len, (unsigned char *) (*macp)->name, - strlen((*macp)->name)); + s = _libssh2_kex_agree_instr(mac, mac_len, + (unsigned char *) (*macp)->name, + strlen((*macp)->name)); if(s) { endpoint->mac = *macp; return 0; @@ -3623,11 +3876,11 @@ static int kex_agree_mac(LIBSSH2_SESSION * session, */ static int kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *comp, - unsigned long comp_len) + size_t comp_len) { const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session); unsigned char *s; - (void) session; + (void)session; if(endpoint->comp_prefs) { s = (unsigned char *) endpoint->comp_prefs; @@ -3636,7 +3889,7 @@ static int kex_agree_comp(LIBSSH2_SESSION *session, unsigned char *p = (unsigned char *) strchr((char *) s, ','); size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); - if(kex_agree_instr(comp, comp_len, s, method_len)) { + if(_libssh2_kex_agree_instr(comp, comp_len, s, method_len)) { const LIBSSH2_COMP_METHOD *method = (const LIBSSH2_COMP_METHOD *) kex_get_method_by_name((char *) s, method_len, @@ -3658,8 +3911,9 @@ static int kex_agree_comp(LIBSSH2_SESSION *session, } while(*compp && (*compp)->name) { - s = kex_agree_instr(comp, comp_len, (unsigned char *) (*compp)->name, - strlen((*compp)->name)); + s = _libssh2_kex_agree_instr(comp, comp_len, + (unsigned char *) (*compp)->name, + strlen((*compp)->name)); if(s) { endpoint->comp = *compp; return 0; @@ -3679,7 +3933,7 @@ static int kex_agree_comp(LIBSSH2_SESSION *session, * Decide which specific method to use of the methods offered by each party */ static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data, - unsigned data_len) + size_t data_len) { unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc, *mac_cs, *mac_sc; @@ -3733,45 +3987,54 @@ static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data, } if(kex_agree_crypt(session, &session->local, crypt_cs, crypt_cs_len) - || kex_agree_crypt(session, &session->remote, crypt_sc, - crypt_sc_len)) { + || kex_agree_crypt(session, &session->remote, crypt_sc, crypt_sc_len)) { return -1; } - if(kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) || - kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) { + /* This must happen after kex_agree_crypt since some MACs depend on the + negotiated crypto method */ + if(kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) + || kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) { return -1; } - if(kex_agree_comp(session, &session->local, comp_cs, comp_cs_len) || - kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) { + if(kex_agree_comp(session, &session->local, comp_cs, comp_cs_len) + || kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) { return -1; } #if 0 if(libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len) - || libssh2_kex_agree_lang(session, &session->remote, lang_sc, - lang_sc_len)) { + || libssh2_kex_agree_lang(session, &session->remote, lang_sc, + lang_sc_len)) { return -1; } #endif - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on KEX method: %s", - session->kex->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on HOSTKEY method: %s", - session->hostkey->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_CS method: %s", - session->local.crypt->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_SC method: %s", - session->remote.crypt->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_CS method: %s", - session->local.mac->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_SC method: %s", - session->remote.mac->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_CS method: %s", - session->local.comp->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_SC method: %s", - session->remote.comp->name); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on KEX method: %s", + session->kex->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on HOSTKEY method: %s", + session->hostkey->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on CRYPT_CS method: %s", + session->local.crypt->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on CRYPT_SC method: %s", + session->remote.crypt->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on MAC_CS method: %s", + session->local.mac->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on MAC_SC method: %s", + session->remote.mac->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on COMP_CS method: %s", + session->local.comp->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on COMP_SC method: %s", + session->remote.comp->name)); return 0; } @@ -3798,6 +4061,10 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, session->state |= LIBSSH2_STATE_EXCHANGING_KEYS; if(reexchange) { + if(session->kex && session->kex->cleanup) { + session->kex->cleanup(session, &key_state->key_state_low); + } + session->kex = NULL; if(session->hostkey && session->hostkey->dtor) { @@ -3831,6 +4098,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, session->local.kexinit = key_state->oldlocal; session->local.kexinit_len = key_state->oldlocal_len; key_state->state = libssh2_NB_state_idle; + session->state &= ~LIBSSH2_STATE_INITIAL_KEX; session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; return -1; @@ -3856,6 +4124,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, session->local.kexinit = key_state->oldlocal; session->local.kexinit_len = key_state->oldlocal_len; key_state->state = libssh2_NB_state_idle; + session->state &= ~LIBSSH2_STATE_INITIAL_KEX; session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; return -1; @@ -3866,9 +4135,10 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, } session->remote.kexinit = key_state->data; session->remote.kexinit_len = key_state->data_len; + key_state->data = NULL; - if(kex_agree_methods(session, key_state->data, - key_state->data_len)) + if(kex_agree_methods(session, session->remote.kexinit, + session->remote.kexinit_len)) rc = LIBSSH2_ERROR_KEX_FAILURE; key_state->state = libssh2_NB_state_sent2; @@ -3904,6 +4174,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, session->remote.kexinit = NULL; } + session->state &= ~LIBSSH2_STATE_INITIAL_KEX; session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; @@ -3922,50 +4193,61 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, const char *prefs) { char **prefvar, *s, *newprefs; - int prefs_len = strlen(prefs); + char *tmpprefs = NULL; + size_t prefs_len = strlen(prefs); const LIBSSH2_COMMON_METHOD **mlist; + const char *kex_extensions = "ext-info-c,kex-strict-c-v00@openssh.com,"; + size_t kex_extensions_len = strlen(kex_extensions); switch(method_type) { case LIBSSH2_METHOD_KEX: prefvar = &session->kex_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_kex_methods; + tmpprefs = LIBSSH2_ALLOC(session, kex_extensions_len + prefs_len + 1); + if(!tmpprefs) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Error allocated space for kex method" + " preferences"); + } + memcpy(tmpprefs, kex_extensions, kex_extensions_len); + memcpy(tmpprefs + kex_extensions_len, prefs, prefs_len + 1); + prefs = tmpprefs; + prefs_len = strlen(prefs); break; case LIBSSH2_METHOD_HOSTKEY: prefvar = &session->hostkey_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_hostkey_methods(); break; case LIBSSH2_METHOD_CRYPT_CS: prefvar = &session->local.crypt_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_crypt_methods(); break; case LIBSSH2_METHOD_CRYPT_SC: prefvar = &session->remote.crypt_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_crypt_methods(); break; case LIBSSH2_METHOD_MAC_CS: prefvar = &session->local.mac_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_mac_methods(); break; case LIBSSH2_METHOD_MAC_SC: prefvar = &session->remote.mac_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_mac_methods(); break; case LIBSSH2_METHOD_COMP_CS: prefvar = &session->local.comp_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_comp_methods(session); break; case LIBSSH2_METHOD_COMP_SC: prefvar = &session->remote.comp_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_comp_methods(session); break; case LIBSSH2_METHOD_LANG_CS: @@ -3978,6 +4260,11 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, mlist = NULL; break; + case LIBSSH2_METHOD_SIGN_ALGO: + prefvar = &session->sign_algo_prefs; + mlist = NULL; + break; + default: return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type"); @@ -3985,6 +4272,9 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1); if(!newprefs) { + if(tmpprefs) { + LIBSSH2_FREE(session, tmpprefs); + } return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Error allocated space for method preferences"); } @@ -3992,12 +4282,12 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, while(s && *s && mlist) { char *p = strchr(s, ','); - int method_len = p ? (p - s) : (int) strlen(s); + size_t method_len = (p ? (size_t)(p - s) : strlen(s)); if(!kex_get_method_by_name(s, method_len, mlist)) { /* Strip out unsupported method */ if(p) { - memcpy(s, p + 1, strlen(s) - method_len); + memmove(s, p + 1, strlen(s) - method_len); } else { if(s > newprefs) { @@ -4013,6 +4303,10 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, } } + if(tmpprefs) { + LIBSSH2_FREE(session, tmpprefs); + } + if(!*newprefs) { LIBSSH2_FREE(session, newprefs); return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, @@ -4029,7 +4323,7 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, } /* - * libssh2_session_supported_algs() + * libssh2_session_supported_algs * returns a number of returned algorithms (a positive number) on success, * a negative number on failure */ @@ -4044,33 +4338,37 @@ LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, const LIBSSH2_COMMON_METHOD **mlist; /* to prevent coredumps due to dereferencing of NULL */ - if(NULL == algs) + if(!algs) return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, "algs must not be NULL"); switch(method_type) { case LIBSSH2_METHOD_KEX: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_kex_methods; break; case LIBSSH2_METHOD_HOSTKEY: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_hostkey_methods(); break; case LIBSSH2_METHOD_CRYPT_CS: case LIBSSH2_METHOD_CRYPT_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_crypt_methods(); break; case LIBSSH2_METHOD_MAC_CS: case LIBSSH2_METHOD_MAC_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_mac_methods(); break; case LIBSSH2_METHOD_COMP_CS: case LIBSSH2_METHOD_COMP_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_comp_methods(session); + break; + + case LIBSSH2_METHOD_SIGN_ALGO: + /* no built-in supported list due to backend support */ + mlist = NULL; break; default: @@ -4079,7 +4377,7 @@ LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, } /* switch */ /* weird situation */ - if(NULL == mlist) + if(!mlist) return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "No algorithm found"); @@ -4096,28 +4394,28 @@ LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, */ /* count the number of supported algorithms */ - for(i = 0, ialg = 0; NULL != mlist[i]; i++) { + for(i = 0, ialg = 0; mlist[i]; i++) { /* do not count fields with NULL name */ if(mlist[i]->name) ialg++; } /* weird situation, no algorithm found */ - if(0 == ialg) + if(ialg == 0) return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "No algorithm found"); /* allocate buffer */ *algs = (const char **) LIBSSH2_ALLOC(session, ialg*sizeof(const char *)); - if(NULL == *algs) { + if(!*algs) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Memory allocation failed"); } - /* Past this point *algs must be deallocated in case of an error!! */ + /* Past this point *algs must be deallocated in case of an error! */ /* copy non-NULL pointers only */ - for(i = 0, j = 0; NULL != mlist[i] && j < ialg; i++) { - if(NULL == mlist[i]->name) { + for(i = 0, j = 0; mlist[i] && j < ialg; i++) { + if(!mlist[i]->name) { /* maybe a weird situation but if it occurs, do not include NULL pointers */ continue; diff --git a/uppsrc/Core/SSH/libssh2/knownhost.c b/uppsrc/Core/SSH/libssh2/knownhost.c index 77798fbfd..79500ec55 100644 --- a/uppsrc/Core/SSH/libssh2/knownhost.c +++ b/uppsrc/Core/SSH/libssh2/knownhost.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2019 by Daniel Stenberg + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,10 +34,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include "misc.h" struct known_host { struct list_node node; @@ -111,7 +112,7 @@ libssh2_knownhost_init(LIBSSH2_SESSION *session) #define KNOWNHOST_MAGIC 0xdeadcafe /* - * knownhost_to_external() + * knownhost_to_external * * Copies data from the internal to the external representation struct. * @@ -123,7 +124,7 @@ static struct libssh2_knownhost *knownhost_to_external(struct known_host *node) ext->magic = KNOWNHOST_MAGIC; ext->node = node; ext->name = ((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == - LIBSSH2_KNOWNHOST_TYPE_PLAIN)? node->name:NULL; + LIBSSH2_KNOWNHOST_TYPE_PLAIN) ? node->name : NULL; ext->key = node->key; ext->typemask = node->typemask; @@ -142,7 +143,7 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, size_t hostlen = strlen(host); int rc; char *ptr; - unsigned int ptrlen; + size_t ptrlen; /* make sure we have a key type set */ if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK)) @@ -170,15 +171,15 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, entry->name_len = hostlen; break; case LIBSSH2_KNOWNHOST_TYPE_SHA1: - rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, - host, hostlen); + rc = _libssh2_base64_decode(hosts->session, &ptr, &ptrlen, + host, hostlen); if(rc) goto error; entry->name = ptr; entry->name_len = ptrlen; - rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, - salt, strlen(salt)); + rc = _libssh2_base64_decode(hosts->session, &ptr, &ptrlen, + salt, strlen(salt)); if(rc) goto error; entry->salt = ptr; @@ -252,7 +253,7 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, *store = knownhost_to_external(entry); return LIBSSH2_ERROR_NONE; - error: +error: free_host(hosts->session, entry); return rc; } @@ -420,19 +421,23 @@ knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, */ unsigned char hash[SHA_DIGEST_LENGTH]; libssh2_hmac_ctx ctx; - libssh2_hmac_ctx_init(ctx); + if(!_libssh2_hmac_ctx_init(&ctx)) + break; if(SHA_DIGEST_LENGTH != node->name_len) { /* the name hash length must be the sha1 size or we can't match it */ break; } - libssh2_hmac_sha1_init(&ctx, (unsigned char *)node->salt, - node->salt_len); - libssh2_hmac_update(ctx, (unsigned char *)host, - strlen(host)); - libssh2_hmac_final(ctx, hash); - libssh2_hmac_cleanup(&ctx); + if(!_libssh2_hmac_sha1_init(&ctx, + node->salt, node->salt_len)) + break; + if(!_libssh2_hmac_update(&ctx, host, strlen(host)) || + !_libssh2_hmac_final(&ctx, hash)) { + _libssh2_hmac_cleanup(&ctx); + break; + } + _libssh2_hmac_cleanup(&ctx); if(!memcmp(hash, node->name, SHA_DIGEST_LENGTH)) /* this is a node we're interested in */ @@ -727,7 +732,7 @@ static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts, } /* - * hostline() + * hostline * * Parse a single known_host line pre-split into host and key. * @@ -774,18 +779,20 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, } key_type_len = key - key_type_name; - if(!strncmp(key_type_name, "ssh-dss", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS; - else if(!strncmp(key_type_name, "ssh-rsa", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA; + if(!strncmp(key_type_name, "ssh-ed25519", key_type_len)) + key_type = LIBSSH2_KNOWNHOST_KEY_ED25519; else if(!strncmp(key_type_name, "ecdsa-sha2-nistp256", key_type_len)) key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_256; else if(!strncmp(key_type_name, "ecdsa-sha2-nistp384", key_type_len)) key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_384; else if(!strncmp(key_type_name, "ecdsa-sha2-nistp521", key_type_len)) key_type = LIBSSH2_KNOWNHOST_KEY_ECDSA_521; - else if(!strncmp(key_type_name, "ssh-ed25519", key_type_len)) - key_type = LIBSSH2_KNOWNHOST_KEY_ED25519; + else if(!strncmp(key_type_name, "ssh-rsa", key_type_len)) + key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA; +#if LIBSSH2_DSA + else if(!strncmp(key_type_name, "ssh-dss", key_type_len)) + key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS; +#endif else key_type = LIBSSH2_KNOWNHOST_KEY_UNKNOWN; @@ -822,7 +829,7 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, } /* Figure out host format */ - if((hostlen >2) && memcmp(host, "|1|", 3)) { + if((hostlen > 2) && memcmp(host, "|1|", 3)) { /* old style plain text: [name]([,][name])* for the sake of simplicity, we add them as separate hosts with the @@ -841,7 +848,7 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, } /* - * libssh2_knownhost_readline() + * libssh2_knownhost_readline * * Pass in a line of a file of 'type'. * @@ -983,7 +990,7 @@ libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, } /* - * knownhost_writeline() + * knownhost_writeline * * Ask libssh2 to convert a known host to an output line for storage. * @@ -1021,10 +1028,12 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, key_type_name = "ssh-rsa"; key_type_len = 7; break; +#if LIBSSH2_DSA case LIBSSH2_KNOWNHOST_KEY_SSHDSS: key_type_name = "ssh-dss"; key_type_len = 7; break; +#endif case LIBSSH2_KNOWNHOST_KEY_ECDSA_256: key_type_name = "ecdsa-sha2-nistp256"; key_type_len = 19; @@ -1048,7 +1057,7 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, break; } /* otherwise fallback to default and error */ - /* FALL-THROUGH */ + LIBSSH2_FALLTHROUGH(); default: return _libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, @@ -1157,7 +1166,7 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, } /* - * libssh2_knownhost_writeline() + * libssh2_knownhost_writeline * * Ask libssh2 to convert a known host to an output line for storage. * @@ -1183,7 +1192,7 @@ libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, } /* - * libssh2_knownhost_writefile() + * libssh2_knownhost_writefile * * Write hosts+key pairs to the given file. */ @@ -1234,7 +1243,7 @@ libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, /* - * libssh2_knownhost_get() + * libssh2_knownhost_get * * Traverse the internal list of known hosts. Pass NULL to 'prev' to get * the first one. diff --git a/uppsrc/Core/SSH/libssh2/libgcrypt.c b/uppsrc/Core/SSH/libssh2/libgcrypt.c index 0aff176a6..b92ec7c97 100644 --- a/uppsrc/Core/SSH/libssh2/libgcrypt.c +++ b/uppsrc/Core/SSH/libssh2/libgcrypt.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2008, 2009, Simon Josefsson - * Copyright (C) 2006, 2007, The Written Word, Inc. +/* Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,14 +34,112 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include "libssh2_priv.h" +#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */ -#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */ +int _libssh2_hmac_ctx_init(libssh2_hmac_ctx *ctx) +{ + *ctx = NULL; + return 1; +} -#include +#if LIBSSH2_MD5 +int _libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + gcry_error_t err; + err = gcry_md_open(ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + err = gcry_md_setkey(*ctx, key, keylen); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + return 1; +} +#endif +#if LIBSSH2_HMAC_RIPEMD +int _libssh2_hmac_ripemd160_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + gcry_error_t err; + err = gcry_md_open(ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + err = gcry_md_setkey(*ctx, key, keylen); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + return 1; +} +#endif + +int _libssh2_hmac_sha1_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + gcry_error_t err; + err = gcry_md_open(ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + err = gcry_md_setkey(*ctx, key, keylen); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + return 1; +} + +int _libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + gcry_error_t err; + err = gcry_md_open(ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + err = gcry_md_setkey(*ctx, key, keylen); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + return 1; +} + +int _libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + gcry_error_t err; + err = gcry_md_open(ctx, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + err = gcry_md_setkey(*ctx, key, keylen); + if(gcry_err_code(err) != GPG_ERR_NO_ERROR) + return 0; + return 1; +} + +int _libssh2_hmac_update(libssh2_hmac_ctx *ctx, + const void *data, size_t datalen) +{ + gcry_md_write(*ctx, data, datalen); + return 1; +} + +int _libssh2_hmac_final(libssh2_hmac_ctx *ctx, void *data) +{ + unsigned char *res = gcry_md_read(*ctx, 0); + + if(!res) + return 0; + + memcpy(data, res, gcry_md_get_algo_dlen(gcry_md_get_algo(*ctx))); + + return 1; +} + +void _libssh2_hmac_cleanup(libssh2_hmac_ctx *ctx) +{ + gcry_md_close(*ctx); +} + +#if LIBSSH2_RSA int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, const unsigned char *edata, @@ -61,17 +159,17 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, const unsigned char *coeffdata, unsigned long coefflen) { int rc; - (void) e1data; - (void) e1len; - (void) e2data; - (void) e2len; + + (void)e1data; + (void)e1len; + (void)e2data; + (void)e2len; if(ddata) { - rc = gcry_sexp_build - (rsa, NULL, - "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))", - nlen, ndata, elen, edata, dlen, ddata, plen, pdata, - qlen, qdata, coefflen, coeffdata); + rc = gcry_sexp_build(rsa, NULL, + "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))", + nlen, ndata, elen, edata, dlen, ddata, plen, pdata, + qlen, qdata, coefflen, coeffdata); } else { rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))", @@ -85,27 +183,30 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, return 0; } +#if LIBSSH2_RSA_SHA1 int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len) + size_t sig_len, + const unsigned char *m, size_t m_len) { unsigned char hash[SHA_DIGEST_LENGTH]; gcry_sexp_t s_sig, s_hash; int rc = -1; - libssh2_sha1(m, m_len, hash); + if(libssh2_sha1(m, m_len, hash)) { + return -1; + } rc = gcry_sexp_build(&s_hash, NULL, "(data (flags pkcs1) (hash sha1 %b))", SHA_DIGEST_LENGTH, hash); - if(rc != 0) { + if(rc) { return -1; } rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig); - if(rc != 0) { + if(rc) { gcry_sexp_release(s_hash); return -1; } @@ -116,7 +217,10 @@ _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, return (rc == 0) ? 0 : -1; } +#endif +#endif +#if LIBSSH2_DSA int _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, const unsigned char *p, @@ -132,10 +236,9 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, int rc; if(x_len) { - rc = gcry_sexp_build - (dsactx, NULL, - "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))", - p_len, p, q_len, q, g_len, g, y_len, y, x_len, x); + rc = gcry_sexp_build(dsactx, NULL, + "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))", + p_len, p, q_len, q, g_len, g, y_len, y, x_len, x); } else { rc = gcry_sexp_build(dsactx, NULL, @@ -150,16 +253,23 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, return 0; } +#endif +#if LIBSSH2_RSA int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, LIBSSH2_SESSION * session, const char *filedata, size_t filedata_len, unsigned const char *passphrase) { + (void)rsa; + (void)filedata; + (void)filedata_len; + (void)passphrase; + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unimplemented in libgcrypt backend"); + "Unable to extract private key from memory: " + "Method unimplemented in libgcrypt backend"); } int @@ -169,7 +279,7 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, { FILE *fp; unsigned char *data, *save_data; - unsigned int datalen; + size_t datalen; int ret; unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff; unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen; @@ -195,83 +305,91 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, ret = -1; goto fail; } -/* First read Version field (should be 0). */ + + /* First read Version field (should be 0). */ ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); - if(ret != 0 || (nlen != 1 && *n != '\0')) { + if(ret || (nlen != 1 && *n != '\0')) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } if(_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen, - q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) { + q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) { ret = -1; goto fail; } ret = 0; - fail: +fail: LIBSSH2_FREE(session, save_data); return ret; } +#endif +#if LIBSSH2_DSA int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, LIBSSH2_SESSION * session, const char *filedata, size_t filedata_len, unsigned const char *passphrase) { + (void)dsa; + (void)filedata; + (void)filedata_len; + (void)passphrase; + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unimplemented in libgcrypt backend"); + "Unable to extract private key from memory: " + "Method unimplemented in libgcrypt backend"); } int @@ -281,7 +399,7 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, { FILE *fp; unsigned char *data, *save_data; - unsigned int datalen; + size_t datalen; int ret; unsigned char *p, *q, *g, *y, *x; unsigned int plen, qlen, glen, ylen, xlen; @@ -308,44 +426,44 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, goto fail; } -/* First read Version field (should be 0). */ + /* First read Version field (should be 0). */ ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0 || (plen != 1 && *p != '\0')) { + if(ret || (plen != 1 && *p != '\0')) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } - if(datalen != 0) { + if(datalen) { ret = -1; goto fail; } @@ -357,11 +475,14 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, ret = 0; - fail: +fail: LIBSSH2_FREE(session, save_data); return ret; } +#endif +#if LIBSSH2_RSA +#if LIBSSH2_RSA_SHA1 int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, libssh2_rsa_ctx * rsactx, @@ -380,8 +501,8 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, } if(gcry_sexp_build(&data, NULL, - "(data (flags pkcs1) (hash sha1 %b))", - hash_len, hash)) { + "(data (flags pkcs1) (hash sha1 %b))", + hash_len, hash)) { return -1; } @@ -389,7 +510,7 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, gcry_sexp_release(data); - if(rc != 0) { + if(rc) { return -1; } @@ -421,11 +542,14 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, return rc; } +#endif +#endif +#if LIBSSH2_DSA int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, const unsigned char *hash, - unsigned long hash_len, unsigned char *sig) + size_t hash_len, unsigned char *sig) { unsigned char zhash[SHA_DIGEST_LENGTH + 1]; gcry_sexp_t sig_sexp; @@ -442,7 +566,7 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, zhash[0] = 0; if(gcry_sexp_build(&data, NULL, "(data (value %b))", - hash_len + 1, zhash)) { + (int)(hash_len + 1), zhash)) { return -1; } @@ -450,13 +574,13 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, gcry_sexp_release(data); - if(ret != 0) { + if(ret) { return -1; } memset(sig, 0, 40); -/* Extract R. */ + /* Extract R. */ data = gcry_sexp_find_token(sig_sexp, "r", 0); if(!data) @@ -478,7 +602,7 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, gcry_sexp_release(data); -/* Extract S. */ + /* Extract S. */ data = gcry_sexp_find_token(sig_sexp, "s", 0); if(!data) @@ -499,10 +623,10 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, memcpy(sig + 20 + (20 - size), tmp, size); goto out; - err: +err: ret = -1; - out: +out: if(sig_sexp) { gcry_sexp_release(sig_sexp); } @@ -515,22 +639,24 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, const unsigned char *sig, - const unsigned char *m, unsigned long m_len) + const unsigned char *m, size_t m_len) { unsigned char hash[SHA_DIGEST_LENGTH + 1]; gcry_sexp_t s_sig, s_hash; int rc = -1; - libssh2_sha1(m, m_len, hash + 1); + if(libssh2_sha1(m, m_len, hash + 1)) { + return -1; + } hash[0] = 0; if(gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))", - SHA_DIGEST_LENGTH + 1, hash)) { + SHA_DIGEST_LENGTH + 1, hash)) { return -1; } if(gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))", - 20, sig, 20, sig + 20)) { + 20, sig, 20, sig + 20)) { gcry_sexp_release(s_hash); return -1; } @@ -541,6 +667,7 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, return (rc == 0) ? 0 : -1; } +#endif int _libssh2_cipher_init(_libssh2_cipher_ctx * h, @@ -550,9 +677,9 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, int ret; int cipher = _libssh2_gcry_cipher(algo); int mode = _libssh2_gcry_mode(algo); - int keylen = gcry_cipher_get_algo_keylen(cipher); + size_t keylen = gcry_cipher_get_algo_keylen(cipher); - (void) encrypt; + (void)encrypt; ret = gcry_cipher_open(h, cipher, mode, 0); if(ret) { @@ -566,7 +693,7 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, } if(mode != GCRY_CIPHER_MODE_STREAM) { - int blklen = gcry_cipher_get_algo_blklen(cipher); + size_t blklen = gcry_cipher_get_algo_blklen(cipher); if(mode == GCRY_CIPHER_MODE_CTR) ret = gcry_cipher_setctr(*h, iv, blklen); else @@ -583,11 +710,14 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blklen) + int encrypt, unsigned char *block, size_t blklen, + int firstlast) { - int cipher = _libssh2_gcry_cipher(algo); int ret; + (void)algo; + (void)firstlast; + if(encrypt) { ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen); } @@ -607,6 +737,14 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, size_t privatekeydata_len, const char *passphrase) { + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)privatekeydata; + (void)privatekeydata_len; + (void)passphrase; + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, "Unable to extract public key from private " "key in memory: " @@ -622,9 +760,49 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, const char *privatekey, const char *passphrase) { + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)privatekey; + (void)passphrase; + return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "Method unimplemented in libgcrypt backend"); + "Unable to extract public key from private key file: " + "Method unimplemented in libgcrypt backend"); +} + +int +_libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) +{ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)algorithm; + (void)flags; + (void)application; + (void)key_handle; + (void)handle_len; + (void)privatekeydata; + (void)privatekeydata_len; + (void)passphrase; + + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public SK key from private key file: " + "Method unimplemented in libgcrypt backend"); } void _libssh2_init_aes_ctr(void) @@ -664,4 +842,22 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) *dhctx = NULL; } -#endif /* LIBSSH2_LIBGCRYPT */ +/* _libssh2_supported_key_sign_algorithms + * + * Return supported key hash algo upgrades, see crypto.h + * + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len) +{ + (void)session; + (void)key_method; + (void)key_method_len; + + return NULL; +} + +#endif /* LIBSSH2_CRYPTO_C */ diff --git a/uppsrc/Core/SSH/libssh2/libgcrypt.h b/uppsrc/Core/SSH/libssh2/libgcrypt.h index 298c65ed0..e8efc4be4 100644 --- a/uppsrc/Core/SSH/libssh2/libgcrypt.h +++ b/uppsrc/Core/SSH/libssh2/libgcrypt.h @@ -1,8 +1,8 @@ -#ifndef __LIBSSH2_LIBGCRYPT_H -#define __LIBSSH2_LIBGCRYPT_H +#ifndef LIBSSH2_LIBGCRYPT_H +#define LIBSSH2_LIBGCRYPT_H /* - * Copyright (C) 2008, 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007, The Written Word, Inc. + * Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, @@ -37,8 +37,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ +#define LIBSSH2_CRYPTO_ENGINE libssh2_gcrypt + #include #define LIBSSH2_MD5 1 @@ -47,19 +51,26 @@ #define LIBSSH2_HMAC_SHA256 1 #define LIBSSH2_HMAC_SHA512 1 -#define LIBSSH2_AES 1 +#define LIBSSH2_AES_CBC 1 #define LIBSSH2_AES_CTR 1 +#define LIBSSH2_AES_GCM 0 #define LIBSSH2_BLOWFISH 1 #define LIBSSH2_RC4 1 #define LIBSSH2_CAST 1 #define LIBSSH2_3DES 1 #define LIBSSH2_RSA 1 +#define LIBSSH2_RSA_SHA1 1 +#define LIBSSH2_RSA_SHA2 0 #define LIBSSH2_DSA 1 #define LIBSSH2_ECDSA 0 #define LIBSSH2_ED25519 0 +#include "crypto_config.h" + +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM #define MD5_DIGEST_LENGTH 16 +#endif #define SHA_DIGEST_LENGTH 20 #define SHA256_DIGEST_LENGTH 32 #define SHA384_DIGEST_LENGTH 48 @@ -67,103 +78,79 @@ #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) -#define _libssh2_random(buf, len) \ - (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 0) +#define _libssh2_random(buf, len) \ + (gcry_randomize((buf), (len), GCRY_STRONG_RANDOM), 0) #define libssh2_prepare_iovec(vec, len) /* Empty. */ #define libssh2_sha1_ctx gcry_md_hd_t - /* returns 0 in case of failure */ #define libssh2_sha1_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA1, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA1, 0)) #define libssh2_sha1_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + (gcry_md_write(ctx, (unsigned char *) data, len), 1) #define libssh2_sha1_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA_DIGEST_LENGTH), gcry_md_close(ctx) + (memcpy(out, gcry_md_read(ctx, 0), SHA_DIGEST_LENGTH), \ + gcry_md_close(ctx), 1) #define libssh2_sha1(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA1, out, message, len) + (gcry_md_hash_buffer(GCRY_MD_SHA1, out, message, len), 0) #define libssh2_sha256_ctx gcry_md_hd_t - #define libssh2_sha256_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA256, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA256, 0)) #define libssh2_sha256_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + (gcry_md_write(ctx, (unsigned char *) data, len), 1) #define libssh2_sha256_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA256_DIGEST_LENGTH), gcry_md_close(ctx) + (memcpy(out, gcry_md_read(ctx, 0), SHA256_DIGEST_LENGTH), \ + gcry_md_close(ctx), 1) #define libssh2_sha256(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA256, out, message, len) + (gcry_md_hash_buffer(GCRY_MD_SHA256, out, message, len), 0) #define libssh2_sha384_ctx gcry_md_hd_t - #define libssh2_sha384_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA384, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA384, 0)) #define libssh2_sha384_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + (gcry_md_write(ctx, (unsigned char *) data, len), 1) #define libssh2_sha384_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA384_DIGEST_LENGTH), gcry_md_close(ctx) + (memcpy(out, gcry_md_read(ctx, 0), SHA384_DIGEST_LENGTH), \ + gcry_md_close(ctx), 1) #define libssh2_sha384(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA384, out, message, len) + (gcry_md_hash_buffer(GCRY_MD_SHA384, out, message, len), 0) #define libssh2_sha512_ctx gcry_md_hd_t - #define libssh2_sha512_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA512, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA512, 0)) #define libssh2_sha512_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + (gcry_md_write(ctx, (unsigned char *) data, len), 1) #define libssh2_sha512_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA512_DIGEST_LENGTH), gcry_md_close(ctx) + (memcpy(out, gcry_md_read(ctx, 0), SHA512_DIGEST_LENGTH), \ + gcry_md_close(ctx), 1) #define libssh2_sha512(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA512, out, message, len) + (gcry_md_hash_buffer(GCRY_MD_SHA512, out, message, len), 0) +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM #define libssh2_md5_ctx gcry_md_hd_t - -/* returns 0 in case of failure */ #define libssh2_md5_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_MD5, 0)) - + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_MD5, 0)) #define libssh2_md5_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + (gcry_md_write(ctx, (unsigned char *) data, len), 1) #define libssh2_md5_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), MD5_DIGEST_LENGTH), gcry_md_close(ctx) -#define libssh2_md5(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_MD5, out, message, len) + (memcpy(out, gcry_md_read(ctx, 0), MD5_DIGEST_LENGTH), \ + gcry_md_close(ctx), 1) +#endif #define libssh2_hmac_ctx gcry_md_hd_t -#define libssh2_hmac_ctx_init(ctx) -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC), \ - gcry_md_setkey(*ctx, key, keylen) -#define libssh2_hmac_update(ctx, data, datalen) \ - gcry_md_write(ctx, (unsigned char *) data, datalen) -#define libssh2_hmac_final(ctx, data) \ - memcpy(data, gcry_md_read(ctx, 0), \ - gcry_md_get_algo_dlen(gcry_md_get_algo(ctx))) -#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx); -#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM) +#define libssh2_crypto_init() gcry_control(GCRYCTL_DISABLE_SECMEM) #define libssh2_crypto_exit() #define libssh2_rsa_ctx struct gcry_sexp -#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx) +#define _libssh2_rsa_free(rsactx) gcry_sexp_release(rsactx) #define libssh2_dsa_ctx struct gcry_sexp -#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx) +#define _libssh2_dsa_free(dsactx) gcry_sexp_release(dsactx) #if LIBSSH2_ECDSA #else @@ -178,25 +165,27 @@ #define _libssh2_gcry_mode(m) (m & 0xFF) #define _libssh2_cipher_aes256ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR) #define _libssh2_cipher_aes192ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR) #define _libssh2_cipher_aes128ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR) #define _libssh2_cipher_aes256 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_aes192 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_aes128 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_blowfish \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_arcfour \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM) + _libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM) #define _libssh2_cipher_cast5 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_3des \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC) +#define _libssh2_cipher_chacha20 \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_STREAM) #define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx)) @@ -206,26 +195,35 @@ #define _libssh2_bn_ctx_new() 0 #define _libssh2_bn_ctx_free(bnctx) ((void)0) #define _libssh2_bn_init() gcry_mpi_new(0) -#define _libssh2_bn_init_from_bin() NULL /* because gcry_mpi_scan() creates a - new bignum */ +#define _libssh2_bn_init_from_bin() NULL /* because gcry_mpi_scan() creates a + new bignum */ #define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val) -#define _libssh2_bn_from_bin(bn, len, val) \ +#define _libssh2_bn_from_bin(bn, len, val) \ gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL) -#define _libssh2_bn_to_bin(bn, val) \ +#define _libssh2_bn_to_bin(bn, val) \ gcry_mpi_print(GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn) -#define _libssh2_bn_bytes(bn) \ - (gcry_mpi_get_nbits (bn) / 8 + \ - ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1)) -#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn) +#define _libssh2_bn_bytes(bn) \ + (gcry_mpi_get_nbits(bn) / 8 + \ + ((gcry_mpi_get_nbits(bn) % 8 == 0) ? 0 : 1)) +#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits(bn) #define _libssh2_bn_free(bn) gcry_mpi_release(bn) +/* Default generate and safe prime sizes for + diffie-hellman-group-exchange-sha1 */ +#define LIBSSH2_DH_GEX_MINGROUP 2048 +#define LIBSSH2_DH_GEX_OPTGROUP 4096 +#define LIBSSH2_DH_GEX_MAXGROUP 8192 + +#define LIBSSH2_DH_MAX_MODULUS_BITS 16384 + #define _libssh2_dh_ctx struct gcry_mpi * #define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) #define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order) + _libssh2_dh_key_pair(dhctx, public, g, p, group_order) #define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) + _libssh2_dh_secret(dhctx, secret, f, p) #define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) +extern void _libssh2_init_aes_ctr(void); extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx); extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, _libssh2_bn *g, _libssh2_bn *p, @@ -234,4 +232,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 */ +#endif /* LIBSSH2_LIBGCRYPT_H */ diff --git a/uppsrc/Core/SSH/libssh2/libssh2.h b/uppsrc/Core/SSH/libssh2/libssh2.h index 995d83ed0..f47858aed 100644 --- a/uppsrc/Core/SSH/libssh2/libssh2.h +++ b/uppsrc/Core/SSH/libssh2/libssh2.h @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2009, Sara Golemon - * Copyright (c) 2009-2015 Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,27 +35,29 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LIBSSH2_H #define LIBSSH2_H 1 -#define LIBSSH2_COPYRIGHT "2004-2019 The libssh2 project and its contributors." +#define LIBSSH2_COPYRIGHT "The libssh2 project and its contributors." /* We use underscore instead of dash when appending DEV in dev versions just to make the BANNER define (used by src/session.c) be a valid SSH banner. Release versions have no appended strings and may of course not have dashes either. */ -#define LIBSSH2_VERSION "1.10.0" +#define LIBSSH2_VERSION "1.11.1" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBSSH2_VERSION_MAJOR 1 -#define LIBSSH2_VERSION_MINOR 10 -#define LIBSSH2_VERSION_PATCH 0 +#define LIBSSH2_VERSION_MINOR 11 +#define LIBSSH2_VERSION_PATCH 1 /* This is the numeric version of the libssh2 version number, meant for easier - parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will + parsing and comparisons by programs. The LIBSSH2_VERSION_NUM define will always follow this syntax: 0xXXYYZZ @@ -69,7 +71,7 @@ and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. */ -#define LIBSSH2_VERSION_NUM 0x010a00 +#define LIBSSH2_VERSION_NUM 0x010b01 /* * This is the date and time when the full source package was created. The @@ -80,13 +82,14 @@ * * "Mon Feb 12 11:35:33 UTC 2007" */ -#define LIBSSH2_TIMESTAMP "Sun 29 Aug 2021 08:37:50 PM UTC" +#define LIBSSH2_TIMESTAMP "Wed Oct 16 08:03:21 UTC 2024" #ifndef RC_INVOKED #ifdef __cplusplus extern "C" { #endif + #ifdef _WIN32 # include # include @@ -99,8 +102,8 @@ extern "C" { /* Allow alternate API prefix from CFLAGS or calling app */ #ifndef LIBSSH2_API -# ifdef LIBSSH2_WIN32 -# ifdef _WINDLL +# ifdef _WIN32 +# if defined(LIBSSH2_EXPORTS) || defined(_WINDLL) # ifdef LIBSSH2_LIBRARY # define LIBSSH2_API __declspec(dllexport) # else @@ -109,25 +112,15 @@ extern "C" { # else # define LIBSSH2_API # endif -# else /* !LIBSSH2_WIN32 */ +# else /* !_WIN32 */ # define LIBSSH2_API -# endif /* LIBSSH2_WIN32 */ +# endif /* _WIN32 */ #endif /* LIBSSH2_API */ #ifdef HAVE_SYS_UIO_H # include #endif -#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) -# include -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -typedef int int32_t; -typedef unsigned long long uint64_t; -typedef long long int64_t; -#endif - #ifdef _MSC_VER typedef unsigned char uint8_t; typedef unsigned short int uint16_t; @@ -147,13 +140,44 @@ typedef unsigned long long libssh2_uint64_t; typedef long long libssh2_int64_t; #endif -#ifdef WIN32 +#ifdef _WIN32 typedef SOCKET libssh2_socket_t; #define LIBSSH2_INVALID_SOCKET INVALID_SOCKET -#else /* !WIN32 */ +#define LIBSSH2_SOCKET_CLOSE(s) closesocket(s) +#else /* !_WIN32 */ typedef int libssh2_socket_t; #define LIBSSH2_INVALID_SOCKET -1 -#endif /* WIN32 */ +#define LIBSSH2_SOCKET_CLOSE(s) close(s) +#endif /* _WIN32 */ + +/* Compile-time deprecation macros */ +#if !defined(LIBSSH2_DISABLE_DEPRECATION) && !defined(LIBSSH2_LIBRARY) +# if defined(_MSC_VER) +# if _MSC_VER >= 1400 +# define LIBSSH2_DEPRECATED(version, message) \ + __declspec(deprecated("since libssh2 " # version ". " message)) +# elif _MSC_VER >= 1310 +# define LIBSSH2_DEPRECATED(version, message) \ + __declspec(deprecated) +# endif +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (defined(__clang__) && __clang_major__ >= 3) || \ + (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define LIBSSH2_DEPRECATED(version, message) \ + __attribute__((deprecated("since libssh2 " # version ". " message))) +# elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0) +# define LIBSSH2_DEPRECATED(version, message) \ + __attribute__((deprecated)) +# endif +# elif defined(__SUNPRO_C) && __SUNPRO_C >= 0x5130 +# define LIBSSH2_DEPRECATED(version, message) \ + __attribute__((deprecated)) +# endif +#endif + +#ifndef LIBSSH2_DEPRECATED +#define LIBSSH2_DEPRECATED(version, message) +#endif /* * Determine whether there is small or large file support on windows. @@ -190,8 +214,6 @@ typedef int libssh2_socket_t; #ifdef LIBSSH2_USE_WIN32_LARGE_FILES # include -# include -# include # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%I64d" typedef struct _stati64 libssh2_struct_stat; typedef __int64 libssh2_struct_stat_size; @@ -202,8 +224,6 @@ typedef __int64 libssh2_struct_stat_size; */ #ifdef LIBSSH2_USE_WIN32_SMALL_FILES -# include -# include # ifndef _WIN32_WCE # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%d" typedef struct _stat libssh2_struct_stat; @@ -233,14 +253,6 @@ typedef off_t libssh2_struct_stat_size; #define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER #define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n" -/* Default generate and safe prime sizes for - diffie-hellman-group-exchange-sha1 */ -#define LIBSSH2_DH_GEX_MINGROUP 2048 -#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 @@ -272,59 +284,102 @@ typedef off_t libssh2_struct_stat_size; typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT { - char *text; - unsigned int length; + unsigned char *text; + size_t length; unsigned char echo; } LIBSSH2_USERAUTH_KBDINT_PROMPT; typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE { char *text; - unsigned int length; + unsigned int length; /* FIXME: change type to size_t */ } LIBSSH2_USERAUTH_KBDINT_RESPONSE; +typedef struct _LIBSSH2_SK_SIG_INFO { + uint8_t flags; + uint32_t counter; + unsigned char *sig_r; + size_t sig_r_len; + unsigned char *sig_s; + size_t sig_s_len; +} LIBSSH2_SK_SIG_INFO; + /* 'publickey' authentication callback */ #define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \ - int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \ - const unsigned char *data, size_t data_len, void **abstract) + int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \ + const unsigned char *data, size_t data_len, void **abstract) /* 'keyboard-interactive' authentication callback */ +/* FIXME: name_len, instruction_len -> size_t, num_prompts -> unsigned int? */ #define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \ - void name_(const char *name, int name_len, const char *instruction, \ - int instruction_len, int num_prompts, \ - const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, \ - LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) + void name_(const char *name, int name_len, const char *instruction, \ + int instruction_len, int num_prompts, \ + const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, \ + LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) + +/* SK authentication callback */ +#define LIBSSH2_USERAUTH_SK_SIGN_FUNC(name) \ + int name(LIBSSH2_SESSION *session, LIBSSH2_SK_SIG_INFO *sig_info, \ + const unsigned char *data, size_t data_len, \ + int algorithm, uint8_t flags, \ + const char *application, const unsigned char *key_handle, \ + size_t handle_len, \ + void **abstract) + +/* Flags for SK authentication */ +#define LIBSSH2_SK_PRESENCE_REQUIRED 0x01 +#define LIBSSH2_SK_VERIFICATION_REQUIRED 0x04 + +/* FIXME: update lengths to size_t (or ssize_t): */ /* Callbacks for special SSH packets */ #define LIBSSH2_IGNORE_FUNC(name) \ - void name(LIBSSH2_SESSION *session, const char *message, int message_len, \ - void **abstract) + void name(LIBSSH2_SESSION *session, const char *message, int message_len, \ + void **abstract) #define LIBSSH2_DEBUG_FUNC(name) \ - void name(LIBSSH2_SESSION *session, int always_display, const char *message, \ - int message_len, const char *language, int language_len, \ - void **abstract) + void name(LIBSSH2_SESSION *session, int always_display, \ + const char *message, int message_len, \ + const char *language, int language_len, \ + void **abstract) #define LIBSSH2_DISCONNECT_FUNC(name) \ - void name(LIBSSH2_SESSION *session, int reason, const char *message, \ - int message_len, const char *language, int language_len, \ - void **abstract) + void name(LIBSSH2_SESSION *session, int reason, \ + const char *message, int message_len, \ + const char *language, int language_len, \ + void **abstract) #define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) \ - void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \ - void **abstract) + void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \ + void **abstract) #define LIBSSH2_MACERROR_FUNC(name) \ - int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \ - void **abstract) + int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \ + void **abstract) #define LIBSSH2_X11_OPEN_FUNC(name) \ - void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ - const char *shost, int sport, void **abstract) + void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ + const char *shost, int sport, void **abstract) + +#define LIBSSH2_AUTHAGENT_FUNC(name) \ + void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ + void **abstract) + +#define LIBSSH2_ADD_IDENTITIES_FUNC(name) \ + void name(LIBSSH2_SESSION *session, void *buffer, \ + const char *agent_path, void **abstract) + +#define LIBSSH2_AUTHAGENT_SIGN_FUNC(name) \ + int name(LIBSSH2_SESSION* session, \ + unsigned char *blob, unsigned int blen, \ + const unsigned char *data, unsigned int dlen, \ + unsigned char **signature, unsigned int *sigLen, \ + const char *agentPath, \ + void **abstract) #define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \ - void name(LIBSSH2_SESSION *session, void **session_abstract, \ - LIBSSH2_CHANNEL *channel, void **channel_abstract) + void name(LIBSSH2_SESSION *session, void **session_abstract, \ + LIBSSH2_CHANNEL *channel, void **channel_abstract) /* I/O callbacks */ #define LIBSSH2_RECV_FUNC(name) \ @@ -337,13 +392,16 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE int flags, void **abstract) /* libssh2_session_callback_set() constants */ -#define LIBSSH2_CALLBACK_IGNORE 0 -#define LIBSSH2_CALLBACK_DEBUG 1 -#define LIBSSH2_CALLBACK_DISCONNECT 2 -#define LIBSSH2_CALLBACK_MACERROR 3 -#define LIBSSH2_CALLBACK_X11 4 -#define LIBSSH2_CALLBACK_SEND 5 -#define LIBSSH2_CALLBACK_RECV 6 +#define LIBSSH2_CALLBACK_IGNORE 0 +#define LIBSSH2_CALLBACK_DEBUG 1 +#define LIBSSH2_CALLBACK_DISCONNECT 2 +#define LIBSSH2_CALLBACK_MACERROR 3 +#define LIBSSH2_CALLBACK_X11 4 +#define LIBSSH2_CALLBACK_SEND 5 +#define LIBSSH2_CALLBACK_RECV 6 +#define LIBSSH2_CALLBACK_AUTHAGENT 7 +#define LIBSSH2_CALLBACK_AUTHAGENT_IDENTITIES 8 +#define LIBSSH2_CALLBACK_AUTHAGENT_SIGN 9 /* libssh2_session_method_pref() constants */ #define LIBSSH2_METHOD_KEX 0 @@ -356,10 +414,12 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE #define LIBSSH2_METHOD_COMP_SC 7 #define LIBSSH2_METHOD_LANG_CS 8 #define LIBSSH2_METHOD_LANG_SC 9 +#define LIBSSH2_METHOD_SIGN_ALGO 10 /* flags */ #define LIBSSH2_FLAG_SIGPIPE 1 #define LIBSSH2_FLAG_COMPRESS 2 +#define LIBSSH2_FLAG_QUOTE_PATHS 3 typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION; typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL; @@ -367,6 +427,25 @@ typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER; typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS; typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT; +/* SK signature callback */ +typedef struct _LIBSSH2_PRIVKEY_SK { + int algorithm; + uint8_t flags; + const char *application; + const unsigned char *key_handle; + size_t handle_len; + LIBSSH2_USERAUTH_SK_SIGN_FUNC((*sign_callback)); + void **orig_abstract; +} LIBSSH2_PRIVKEY_SK; + +int +libssh2_sign_sk(LIBSSH2_SESSION *session, + unsigned char **sig, + size_t *sig_len, + const unsigned char *data, + size_t data_len, + void **abstract); + typedef struct _LIBSSH2_POLLFD { unsigned char type; /* LIBSSH2_POLLFD_* below */ @@ -423,7 +502,7 @@ typedef struct _LIBSSH2_POLLFD { /* Hostkey Types */ #define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0 #define LIBSSH2_HOSTKEY_TYPE_RSA 1 -#define LIBSSH2_HOSTKEY_TYPE_DSS 2 +#define LIBSSH2_HOSTKEY_TYPE_DSS 2 /* deprecated */ #define LIBSSH2_HOSTKEY_TYPE_ECDSA_256 3 #define LIBSSH2_HOSTKEY_TYPE_ECDSA_384 4 #define LIBSSH2_HOSTKEY_TYPE_ECDSA_521 5 @@ -506,6 +585,11 @@ typedef struct _LIBSSH2_POLLFD { #define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47 #define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48 #define LIBSSH2_ERROR_RANDGEN -49 +#define LIBSSH2_ERROR_MISSING_USERAUTH_BANNER -50 +#define LIBSSH2_ERROR_ALGO_UNSUPPORTED -51 +#define LIBSSH2_ERROR_MAC_FAILURE -52 +#define LIBSSH2_ERROR_HASH_INIT -53 +#define LIBSSH2_ERROR_HASH_CALC -54 /* this is a define to provide the old (<= 1.2.7) name */ #define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV @@ -566,14 +650,25 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session); +typedef void (libssh2_cb_generic)(void); + +LIBSSH2_API libssh2_cb_generic * +libssh2_session_callback_set2(LIBSSH2_SESSION *session, int cbtype, + libssh2_cb_generic *callback); + +LIBSSH2_DEPRECATED(1.11.1, "Use libssh2_session_callback_set2()") LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback); LIBSSH2_API int libssh2_session_banner_set(LIBSSH2_SESSION *session, const char *banner); +#ifndef LIBSSH2_NO_DEPRECATED +LIBSSH2_DEPRECATED(1.4.0, "Use libssh2_session_banner_set()") LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner); +LIBSSH2_DEPRECATED(1.2.8, "Use libssh2_session_handshake()") LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock); +#endif LIBSSH2_API int libssh2_session_handshake(LIBSSH2_SESSION *session, libssh2_socket_t sock); LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, @@ -581,8 +676,8 @@ LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, const char *description, const char *lang); #define libssh2_session_disconnect(session, description) \ - libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \ - (description), "") + libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \ + (description), "") LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session); @@ -614,6 +709,8 @@ LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session); LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len); +LIBSSH2_API int libssh2_userauth_banner(LIBSSH2_SESSION *session, + char **banner); LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); LIBSSH2_API int @@ -623,12 +720,13 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *password, unsigned int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC - ((*passwd_change_cb))); + ((*passwd_change_cb))); #define libssh2_userauth_password(session, username, password) \ - libssh2_userauth_password_ex((session), (username), \ - (unsigned int)strlen(username), \ - (password), (unsigned int)strlen(password), NULL) + libssh2_userauth_password_ex((session), (username), \ + (unsigned int)strlen(username), \ + (password), (unsigned int)strlen(password), \ + NULL) LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, @@ -638,11 +736,11 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *privatekey, const char *passphrase); -#define libssh2_userauth_publickey_fromfile(session, username, publickey, \ - privatekey, passphrase) \ - libssh2_userauth_publickey_fromfile_ex((session), (username), \ +#define libssh2_userauth_publickey_fromfile(session, username, publickey, \ + privatekey, passphrase) \ + libssh2_userauth_publickey_fromfile_ex((session), (username), \ (unsigned int)strlen(username), \ - (publickey), \ + (publickey), \ (privatekey), (passphrase)) LIBSSH2_API int @@ -651,7 +749,7 @@ libssh2_userauth_publickey(LIBSSH2_SESSION *session, const unsigned char *pubkeydata, size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), + ((*sign_callback)), void **abstract); LIBSSH2_API int @@ -666,16 +764,16 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *local_username, unsigned int local_username_len); -#define libssh2_userauth_hostbased_fromfile(session, username, publickey, \ +#define libssh2_userauth_hostbased_fromfile(session, username, publickey, \ privatekey, passphrase, hostname) \ - libssh2_userauth_hostbased_fromfile_ex((session), (username), \ - (unsigned int)strlen(username), \ - (publickey), \ - (privatekey), (passphrase), \ - (hostname), \ - (unsigned int)strlen(hostname), \ - (username), \ - (unsigned int)strlen(username)) + libssh2_userauth_hostbased_fromfile_ex((session), (username), \ + (unsigned int)strlen(username), \ + (publickey), \ + (privatekey), (passphrase), \ + (hostname), \ + (unsigned int)strlen(hostname), \ + (username), \ + (unsigned int)strlen(username)) LIBSSH2_API int libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, @@ -697,15 +795,28 @@ LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, unsigned int username_len, - LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC( - (*response_callback))); + LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC + ((*response_callback))); -#define libssh2_userauth_keyboard_interactive(session, username, \ - response_callback) \ - libssh2_userauth_keyboard_interactive_ex((session), (username), \ +#define libssh2_userauth_keyboard_interactive(session, username, \ + response_callback) \ + libssh2_userauth_keyboard_interactive_ex((session), (username), \ (unsigned int)strlen(username), \ (response_callback)) +LIBSSH2_API int +libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session, + const char *username, + size_t username_len, + const unsigned char *pubkeydata, + size_t pubkeydata_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase, + LIBSSH2_USERAUTH_SK_SIGN_FUNC + ((*sign_callback)), + void **abstract); + LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout); @@ -731,22 +842,27 @@ libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, const char *message, unsigned int message_len); #define libssh2_channel_open_session(session) \ - libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \ - LIBSSH2_CHANNEL_WINDOW_DEFAULT, \ - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) + libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \ + LIBSSH2_CHANNEL_WINDOW_DEFAULT, \ + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) LIBSSH2_API LIBSSH2_CHANNEL * libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, int port, const char *shost, int sport); #define libssh2_channel_direct_tcpip(session, host, port) \ - libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) + libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) + +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_direct_streamlocal_ex(LIBSSH2_SESSION * session, + const char *socket_path, + const char *shost, int sport); LIBSSH2_API LIBSSH2_LISTENER * libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, int port, int *bound_port, int queue_maxsize); #define libssh2_channel_forward_listen(session, port) \ - libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) + libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); @@ -787,7 +903,7 @@ LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, int width_px, int height_px); #define libssh2_channel_request_pty_size(channel, width, height) \ - libssh2_channel_request_pty_size_ex((channel), (width), (height), 0, 0) + libssh2_channel_request_pty_size_ex((channel), (width), (height), 0, 0) LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, @@ -795,7 +911,13 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, const char *auth_cookie, int screen_number); #define libssh2_channel_x11_req(channel, screen_number) \ - libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) + libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) + +LIBSSH2_API int libssh2_channel_signal_ex(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len); +#define libssh2_channel_signal(channel, signame) \ + libssh2_channel_signal_ex((channel), signame, strlen(signame)) LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, @@ -803,23 +925,25 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *message, unsigned int message_len); #define libssh2_channel_shell(channel) \ - libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \ - NULL, 0) + libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \ + NULL, 0) #define libssh2_channel_exec(channel, command) \ - libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \ - (command), (unsigned int)strlen(command)) + libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \ + (command), (unsigned int)strlen(command)) #define libssh2_channel_subsystem(channel, subsystem) \ - libssh2_channel_process_startup((channel), "subsystem", \ - sizeof("subsystem") - 1, (subsystem), \ - (unsigned int)strlen(subsystem)) + libssh2_channel_process_startup((channel), "subsystem", \ + sizeof("subsystem") - 1, (subsystem), \ + (unsigned int)strlen(subsystem)) LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen); #define libssh2_channel_read(channel, buf, buflen) \ - libssh2_channel_read_ex((channel), 0, (buf), (buflen)) + libssh2_channel_read_ex((channel), 0, \ + (buf), (buflen)) #define libssh2_channel_read_stderr(channel, buf, buflen) \ - libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) + libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, \ + (buf), (buflen)) LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended); @@ -829,14 +953,15 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial); #define libssh2_channel_window_read(channel) \ - libssh2_channel_window_read_ex((channel), NULL, NULL) + libssh2_channel_window_read_ex((channel), NULL, NULL) -/* libssh2_channel_receive_window_adjust is DEPRECATED, do not use! */ +#ifndef LIBSSH2_NO_DEPRECATED +LIBSSH2_DEPRECATED(1.1.0, "Use libssh2_channel_receive_window_adjust2()") LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force); - +#endif LIBSSH2_API int libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, unsigned long adjustment, @@ -848,16 +973,17 @@ LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, size_t buflen); #define libssh2_channel_write(channel, buf, buflen) \ - libssh2_channel_write_ex((channel), 0, (buf), (buflen)) -#define libssh2_channel_write_stderr(channel, buf, buflen) \ - libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, \ + libssh2_channel_write_ex((channel), 0, \ + (buf), (buflen)) +#define libssh2_channel_write_stderr(channel, buf, buflen) \ + libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, \ (buf), (buflen)) LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial); #define libssh2_channel_window_write(channel) \ - libssh2_channel_window_write_ex((channel), NULL) + libssh2_channel_window_write_ex((channel), NULL) LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, int blocking); @@ -870,12 +996,19 @@ LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION* session, long timeout); LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION* session); -/* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */ +LIBSSH2_API void libssh2_session_set_read_timeout(LIBSSH2_SESSION* session, + long timeout); +LIBSSH2_API long libssh2_session_get_read_timeout(LIBSSH2_SESSION* session); + +#ifndef LIBSSH2_NO_DEPRECATED +LIBSSH2_DEPRECATED(1.1.0, "libssh2_channel_handle_extended_data2()") LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode); +#endif LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, int ignore_mode); +#ifndef LIBSSH2_NO_DEPRECATED /* libssh2_channel_ignore_extended_data() is defined below for BC with version * 0.1 * @@ -883,12 +1016,12 @@ LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, * LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read * (FIFO) from the standard data channel */ -/* DEPRECATED */ -#define libssh2_channel_ignore_extended_data(channel, ignore) \ - libssh2_channel_handle_extended_data((channel), \ - (ignore) ? \ +/* DEPRECATED since 0.3.0. Use libssh2_channel_handle_extended_data2(). */ +#define libssh2_channel_ignore_extended_data(channel, ignore) \ + libssh2_channel_handle_extended_data((channel), (ignore) ? \ LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : \ LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL) +#endif #define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1 #define LIBSSH2_CHANNEL_FLUSH_ALL -2 @@ -896,7 +1029,7 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid); #define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0) #define libssh2_channel_flush_stderr(channel) \ - libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) + libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel, @@ -913,11 +1046,13 @@ LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel); -/* libssh2_scp_recv is DEPRECATED, do not use! */ +#ifndef LIBSSH2_NO_DEPRECATED +LIBSSH2_DEPRECATED(1.7.0, "Use libssh2_scp_recv2()") LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb); -/* Use libssh2_scp_recv2 for large (> 2GB) file support on windows */ +#endif +/* Use libssh2_scp_recv2() for large (> 2GB) file support on windows */ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, libssh2_struct_stat *sb); @@ -930,8 +1065,9 @@ libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, libssh2_int64_t size, time_t mtime, time_t atime); #define libssh2_scp_send(session, path, mode, size) \ - libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) + libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) +/* DEPRECATED */ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, unsigned int *dest_len, const char *src, unsigned int src_len); @@ -939,8 +1075,22 @@ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, LIBSSH2_API const char *libssh2_version(int req_version_num); +typedef enum { + libssh2_no_crypto = 0, + libssh2_openssl, + libssh2_gcrypt, + libssh2_mbedtls, + libssh2_wincng, + libssh2_os400qc3 +} libssh2_crypto_engine_t; + +LIBSSH2_API +libssh2_crypto_engine_t libssh2_crypto_engine(void); + #define HAVE_LIBSSH2_KNOWNHOST_API 0x010101 /* since 1.1.1 */ #define HAVE_LIBSSH2_VERSION_API 0x010100 /* libssh2_version since 1.1 */ +#define HAVE_LIBSSH2_CRYPTOENGINE_API 0x011100 /* libssh2_crypto_engine + since 1.11 */ struct libssh2_knownhost { unsigned int magic; /* magic stored by the library */ @@ -951,7 +1101,7 @@ struct libssh2_knownhost { }; /* - * libssh2_knownhost_init + * libssh2_knownhost_init() * * Init a collection of known hosts. Returns the pointer to a collection. * @@ -960,7 +1110,7 @@ LIBSSH2_API LIBSSH2_KNOWNHOSTS * libssh2_knownhost_init(LIBSSH2_SESSION *session); /* - * libssh2_knownhost_add + * libssh2_knownhost_add() * * Add a host and its associated key to the collection of known hosts. * @@ -997,7 +1147,7 @@ libssh2_knownhost_init(LIBSSH2_SESSION *session); #define LIBSSH2_KNOWNHOST_KEY_SHIFT 18 #define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18) #define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18) -#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18) +#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18) /* deprecated */ #define LIBSSH2_KNOWNHOST_KEY_ECDSA_256 (4<<18) #define LIBSSH2_KNOWNHOST_KEY_ECDSA_384 (5<<18) #define LIBSSH2_KNOWNHOST_KEY_ECDSA_521 (6<<18) @@ -1012,7 +1162,7 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, struct libssh2_knownhost **store); /* - * libssh2_knownhost_addc + * libssh2_knownhost_addc() * * Add a host and its associated key to the collection of known hosts. * @@ -1030,8 +1180,8 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, * If 'sha1' is selected as type, the salt must be provided to the salt * argument. This too base64 encoded. * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host + * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. + * If a custom type is used, salt is ignored and you must provide the host * pre-hashed when checking for it in the libssh2_knownhost_check() function. * * The keylen parameter may be omitted (zero) if the key is provided as a @@ -1047,7 +1197,7 @@ libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, struct libssh2_knownhost **store); /* - * libssh2_knownhost_check + * libssh2_knownhost_check() * * Check a host and its associated key against the collection of known hosts. * @@ -1086,7 +1236,7 @@ libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, struct libssh2_knownhost **knownhost); /* - * libssh2_knownhost_del + * libssh2_knownhost_del() * * Remove a host from the collection of known hosts. The 'entry' struct is * retrieved by a call to libssh2_knownhost_check(). @@ -1097,7 +1247,7 @@ libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, struct libssh2_knownhost *entry); /* - * libssh2_knownhost_free + * libssh2_knownhost_free() * * Free an entire collection of known hosts. * @@ -1118,7 +1268,7 @@ libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, const char *line, size_t len, int type); /* - * libssh2_knownhost_readfile + * libssh2_knownhost_readfile() * * Add hosts+key pairs from a given file. * @@ -1154,7 +1304,7 @@ libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, int type); /* - * libssh2_knownhost_writefile + * libssh2_knownhost_writefile() * * Write hosts+key pairs to a given file. * @@ -1194,7 +1344,7 @@ struct libssh2_agent_publickey { }; /* - * libssh2_agent_init + * libssh2_agent_init() * * Init an ssh-agent handle. Returns the pointer to the handle. * @@ -1236,8 +1386,8 @@ libssh2_agent_list_identities(LIBSSH2_AGENT *agent); */ LIBSSH2_API int libssh2_agent_get_identity(LIBSSH2_AGENT *agent, - struct libssh2_agent_publickey **store, - struct libssh2_agent_publickey *prev); + struct libssh2_agent_publickey **store, + struct libssh2_agent_publickey *prev); /* * libssh2_agent_userauth() @@ -1248,8 +1398,25 @@ libssh2_agent_get_identity(LIBSSH2_AGENT *agent, */ LIBSSH2_API int libssh2_agent_userauth(LIBSSH2_AGENT *agent, - const char *username, - struct libssh2_agent_publickey *identity); + const char *username, + struct libssh2_agent_publickey *identity); + +/* + * libssh2_agent_sign() + * + * Sign a payload using a system-installed ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_sign(LIBSSH2_AGENT *agent, + struct libssh2_agent_publickey *identity, + unsigned char **sig, + size_t *s_len, + const unsigned char *data, + size_t d_len, + const char *method, + unsigned int method_len); /* * libssh2_agent_disconnect() @@ -1304,7 +1471,7 @@ libssh2_agent_get_identity_path(LIBSSH2_AGENT *agent); */ LIBSSH2_API void libssh2_keepalive_config(LIBSSH2_SESSION *session, int want_reply, - unsigned interval); + unsigned int interval); /* * libssh2_keepalive_send() @@ -1322,15 +1489,15 @@ LIBSSH2_API int libssh2_keepalive_send(LIBSSH2_SESSION *session, enabled */ LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask); -#define LIBSSH2_TRACE_TRANS (1<<1) -#define LIBSSH2_TRACE_KEX (1<<2) -#define LIBSSH2_TRACE_AUTH (1<<3) -#define LIBSSH2_TRACE_CONN (1<<4) -#define LIBSSH2_TRACE_SCP (1<<5) -#define LIBSSH2_TRACE_SFTP (1<<6) -#define LIBSSH2_TRACE_ERROR (1<<7) -#define LIBSSH2_TRACE_PUBLICKEY (1<<8) -#define LIBSSH2_TRACE_SOCKET (1<<9) +#define LIBSSH2_TRACE_TRANS (1<<1) +#define LIBSSH2_TRACE_KEX (1<<2) +#define LIBSSH2_TRACE_AUTH (1<<3) +#define LIBSSH2_TRACE_CONN (1<<4) +#define LIBSSH2_TRACE_SCP (1<<5) +#define LIBSSH2_TRACE_SFTP (1<<6) +#define LIBSSH2_TRACE_ERROR (1<<7) +#define LIBSSH2_TRACE_PUBLICKEY (1<<8) +#define LIBSSH2_TRACE_SOCKET (1<<9) typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION*, void *, diff --git a/uppsrc/Core/SSH/libssh2/libssh2.pc.in b/uppsrc/Core/SSH/libssh2/libssh2.pc.in deleted file mode 100644 index c070988b9..000000000 --- a/uppsrc/Core/SSH/libssh2/libssh2.pc.in +++ /dev/null @@ -1,17 +0,0 @@ -########################################################################### -# libssh2 installation details -########################################################################### - -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ -includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ - -Name: @PROJECT_NAME@ -URL: @PROJECT_URL@ -Description: @PROJECT_DESCRIPTION@ -Version: @LIBSSH2_VERSION@ -Requires.private: @PC_REQUIRES_PRIVATE@ -Libs: -L${libdir} -lssh2 @PC_LIBS@ -Libs.private: @PC_LIBS@ -Cflags: -I${includedir} \ No newline at end of file diff --git a/uppsrc/Core/SSH/libssh2/libssh2.rc b/uppsrc/Core/SSH/libssh2/libssh2.rc new file mode 100644 index 000000000..3021d8e69 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/libssh2.rc @@ -0,0 +1,48 @@ +/*************************************************************************** +* libssh2 Windows resource file +* Copyright (C) The libssh2 project and its contributors. +* +* SPDX-License-Identifier: BSD-3-Clause +***************************************************************************/ +#include +#include "libssh2.h" + +LANGUAGE 0, 0 + +#define RC_VERSION LIBSSH2_VERSION_MAJOR, LIBSSH2_VERSION_MINOR, LIBSSH2_VERSION_PATCH, 0 + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RC_VERSION + PRODUCTVERSION RC_VERSION + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#if defined(LIBSSH2DEBUG) || defined(_DEBUG) + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0 +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" /* 0x0409: en-US, 1200/0x04b0: UTF-16LE */ + BEGIN + VALUE "CompanyName", "The libssh2 library, https://libssh2.org/\0" + VALUE "FileDescription", "libssh2 Shared Library\0" + VALUE "FileVersion", LIBSSH2_VERSION "\0" + VALUE "InternalName", "libssh2\0" + VALUE "OriginalFilename", "libssh2.dll\0" + VALUE "ProductName", "The libssh2 library\0" + VALUE "ProductVersion", LIBSSH2_VERSION "\0" + VALUE "LegalCopyright", "Copyright (C) " LIBSSH2_COPYRIGHT "\0" + VALUE "License", "https://libssh2.org/license.html\0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 0x04b0 /* 0x0409: en-US, 1200/0x04b0: UTF-16LE */ + END +END diff --git a/uppsrc/Core/SSH/libssh2/libssh2_config.h b/uppsrc/Core/SSH/libssh2/libssh2_config.h index baabfcb8f..0de01dcbc 100644 --- a/uppsrc/Core/SSH/libssh2/libssh2_config.h +++ b/uppsrc/Core/SSH/libssh2/libssh2_config.h @@ -41,19 +41,10 @@ /* Package information */ #define PACKAGE "Upp::SSH" #define PACKAGE_BUGREPORT "https://github.com/ultimatepp/ultimatepp/issues" -#define PACKAGE_NAME "Ultimate++ SSH package" -#define PACKAGE_STRING "Ultimate++ SSH package, a libssh2 wrapper, (ver. 2022.2)" +#define PACKAGE_NAME "U++ SSH package" +#define PACKAGE_STRING "U++ SSH package, a libssh2 wrapper, (ver. 2024.1)" #define PACKAGE_URL "https://github.com/ultimatepp/ultimatepp" -#define PACKAGE_VERSION "2022.2 (libssh2 v.1.10.0)" - -/* - OpenSSL version 3.0 deprecated a bunch of api calls. - Until libssh2 adopts the new API calls, we will simply - suppress the deprecation warnings by compiling the library - in compatibility mode. -*/ - -#define OPENSSL_API_COMPAT 0x10100000L +#define PACKAGE_VERSION "2024.1b (libssh2 v.1.11.1)" /* Headers */ #define HAVE_INTTYPES_H @@ -99,6 +90,9 @@ /* Let us enable Z compression. */ #define LIBSSH2_HAVE_ZLIB +// enable DSS (this is actually deprecated, but we want to keep bw-compat, until the next release. +#define LIBSSH2_DSA_ENABLE + /* Upp-SSH package uses OpenSSL by default. */ #define LIBSSH2_OPENSSL @@ -190,4 +184,4 @@ static int snprintf(char * cp, int cp_max_len, const char * fmt, ...) } #define HAVE_SNPRINTF -#endif \ No newline at end of file +#endif diff --git a/uppsrc/Core/SSH/libssh2/libssh2_config.h.in b/uppsrc/Core/SSH/libssh2/libssh2_config.h.in deleted file mode 100644 index 94adf4283..000000000 --- a/uppsrc/Core/SSH/libssh2/libssh2_config.h.in +++ /dev/null @@ -1,252 +0,0 @@ -/* src/libssh2_config.h.in. Generated from configure.ac by autoheader. */ - -/* Define if building universal (internal helper macro) */ -#undef AC_APPLE_UNIVERSAL_BUILD - -/* Define to 1 if using 'alloca.c'. */ -#undef C_ALLOCA - -/* Define to 1 if you have 'alloca', as a function or macro. */ -#undef HAVE_ALLOCA - -/* Define to 1 if works. */ -#undef HAVE_ALLOCA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* Define to 1 if you have the declaration of `SecureZeroMemory', and to 0 if - you don't. */ -#undef HAVE_DECL_SECUREZEROMEMORY - -/* disabled non-blocking sockets */ -#undef HAVE_DISABLED_NONBLOCKING - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ERRNO_H - -/* Define to 1 if you have the `EVP_aes_128_ctr' function. */ -#undef HAVE_EVP_AES_128_CTR - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* use FIONBIO for non-blocking sockets */ -#undef HAVE_FIONBIO - -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* use ioctlsocket() for non-blocking sockets */ -#undef HAVE_IOCTLSOCKET - -/* use Ioctlsocket() for non-blocking sockets */ -#undef HAVE_IOCTLSOCKET_CASE - -/* Define if you have the bcrypt library. */ -#undef HAVE_LIBBCRYPT - -/* Define if you have the crypt32 library. */ -#undef HAVE_LIBCRYPT32 - -/* Define if you have the gcrypt library. */ -#undef HAVE_LIBGCRYPT - -/* Define if you have the mbedcrypto library. */ -#undef HAVE_LIBMBEDCRYPTO - -/* Define if you have the ssl library. */ -#undef HAVE_LIBSSL - -/* Define if you have the z library. */ -#undef HAVE_LIBZ - -/* Define to 1 if the compiler supports the 'long long' data type. */ -#undef HAVE_LONGLONG - -/* Define to 1 if you have the `memset_s' function. */ -#undef HAVE_MEMSET_S - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NTDEF_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NTSTATUS_H - -/* use O_NONBLOCK for non-blocking sockets */ -#undef HAVE_O_NONBLOCK - -/* Define to 1 if you have the `poll' function. */ -#undef HAVE_POLL - -/* Define to 1 if you have the select function. */ -#undef HAVE_SELECT - -/* use SO_NONBLOCK for non-blocking sockets */ -#undef HAVE_SO_NONBLOCK - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the `strtoll' function. */ -#undef HAVE_STRTOLL - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SELECT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WINDOWS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WINSOCK2_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_WS2TCPIP_H - -/* to make a symbol visible */ -#undef LIBSSH2_API - -/* Enable clearing of memory before being freed */ -#undef LIBSSH2_CLEAR_MEMORY - -/* Enable "none" cipher -- NOT RECOMMENDED */ -#undef LIBSSH2_CRYPT_NONE - -/* Enable newer diffie-hellman-group-exchange-sha1 syntax */ -#undef LIBSSH2_DH_GEX_NEW - -/* Compile in zlib support */ -#undef LIBSSH2_HAVE_ZLIB - -/* Use libgcrypt */ -#undef LIBSSH2_LIBGCRYPT - -/* Enable "none" MAC -- NOT RECOMMENDED */ -#undef LIBSSH2_MAC_NONE - -/* Use mbedtls */ -#undef LIBSSH2_MBEDTLS - -/* Use openssl */ -#undef LIBSSH2_OPENSSL - -/* Use wincng */ -#undef LIBSSH2_WINCNG - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ -#undef LT_OBJDIR - -/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ -#undef NEED_REENTRANT - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* If using the C implementation of alloca, define if you know the - direction of stack growth for your system; otherwise it will be - automatically deduced at runtime. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ -#undef STACK_DIRECTION - -/* Define to 1 if all of the C90 standard headers exist (not just the ones - required in a freestanding environment). This macro is provided for - backward compatibility; new code need not use it. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION - -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -# undef WORDS_BIGENDIAN -# endif -#endif - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Define for large files, on AIX-style hosts. */ -#undef _LARGE_FILES - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif - -/* Define to `unsigned int' if does not define. */ -#undef size_t diff --git a/uppsrc/Core/SSH/libssh2/libssh2_config_cmake.h.in b/uppsrc/Core/SSH/libssh2/libssh2_config_cmake.h.in index 62723ede8..3f0bc1388 100644 --- a/uppsrc/Core/SSH/libssh2/libssh2_config_cmake.h.in +++ b/uppsrc/Core/SSH/libssh2/libssh2_config_cmake.h.in @@ -1,5 +1,6 @@ -/* Copyright (c) 2014 Alexander Lamaison - * Copyright (c) 1999-2011 Douglas Gilbert. All rights reserved. +/* Copyright (C) Alexander Lamaison + * Copyright (C) Douglas Gilbert + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -33,73 +34,43 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* Headers */ #cmakedefine HAVE_UNISTD_H #cmakedefine HAVE_INTTYPES_H -#cmakedefine HAVE_STDLIB_H #cmakedefine HAVE_SYS_SELECT_H #cmakedefine HAVE_SYS_UIO_H #cmakedefine HAVE_SYS_SOCKET_H #cmakedefine HAVE_SYS_IOCTL_H #cmakedefine HAVE_SYS_TIME_H #cmakedefine HAVE_SYS_UN_H -#cmakedefine HAVE_WINDOWS_H -#cmakedefine HAVE_WS2TCPIP_H -#cmakedefine HAVE_WINSOCK2_H -#cmakedefine HAVE_NTDEF_H -#cmakedefine HAVE_NTSTATUS_H -/* Libraries */ -#cmakedefine HAVE_LIBCRYPT32 - -/* Types */ -#cmakedefine HAVE_LONGLONG +/* for example and tests */ +#cmakedefine HAVE_ARPA_INET_H +#cmakedefine HAVE_NETINET_IN_H /* Functions */ #cmakedefine HAVE_GETTIMEOFDAY -#cmakedefine HAVE_INET_ADDR -#cmakedefine HAVE_POLL -#cmakedefine HAVE_SELECT -#cmakedefine HAVE_SOCKET #cmakedefine HAVE_STRTOLL #cmakedefine HAVE_STRTOI64 #cmakedefine HAVE_SNPRINTF +#cmakedefine HAVE_EXPLICIT_BZERO +#cmakedefine HAVE_EXPLICIT_MEMSET +#cmakedefine HAVE_MEMSET_S -/* OpenSSL functions */ -#cmakedefine HAVE_EVP_AES_128_CTR +#cmakedefine HAVE_POLL +#cmakedefine HAVE_SELECT /* Socket non-blocking support */ #cmakedefine HAVE_O_NONBLOCK #cmakedefine HAVE_FIONBIO -#cmakedefine HAVE_IOCTLSOCKET #cmakedefine HAVE_IOCTLSOCKET_CASE #cmakedefine HAVE_SO_NONBLOCK -#cmakedefine HAVE_DISABLED_NONBLOCKING -/* snprintf not in Visual Studio CRT and _snprintf dangerously incompatible. - We provide a safe wrapper if snprintf not found */ -#ifndef HAVE_SNPRINTF -#include -#include -/* Want safe, 'n += snprintf(b + n ...)' like function. If cp_max_len is 1 -* then assume cp is pointing to a null char and do nothing. Returns number -* number of chars placed in cp excluding the trailing null char. So for -* cp_max_len > 0 the return value is always < cp_max_len; for cp_max_len -* <= 0 the return value is 0 (and no chars are written to cp). */ -static int snprintf(char * cp, int cp_max_len, const char * fmt, ...) -{ - va_list args; - int n; - - if (cp_max_len < 2) - return 0; - va_start(args, fmt); - n = vsnprintf(cp, cp_max_len, fmt, args); - va_end(args); - return (n < cp_max_len) ? n : (cp_max_len - 1); -} - -#define HAVE_SNPRINTF +/* attribute to export symbol */ +#if defined(LIBSSH2_EXPORTS) && defined(LIBSSH2_LIBRARY) +#cmakedefine LIBSSH2_API ${LIBSSH2_API} #endif diff --git a/uppsrc/Core/SSH/libssh2/libssh2_priv.h b/uppsrc/Core/SSH/libssh2/libssh2_priv.h index da488b744..9b8866dcc 100644 --- a/uppsrc/Core/SSH/libssh2/libssh2_priv.h +++ b/uppsrc/Core/SSH/libssh2/libssh2_priv.h @@ -1,8 +1,8 @@ -#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 +#ifndef LIBSSH2_PRIV_H +#define LIBSSH2_PRIV_H +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -37,25 +37,28 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ +/* Header used by 'src' and 'tests' */ + +/* FIXME: Disable warnings for 'src' */ +#if !defined(LIBSSH2_TESTS) && !defined(LIBSSH2_WARN_SIGN_CONVERSION) +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif +#endif + #define LIBSSH2_LIBRARY -#include "libssh2_config.h" -#ifdef HAVE_WINDOWS_H -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#undef WIN32_LEAN_AND_MEAN -#endif - -#ifdef HAVE_WS2TCPIP_H -#include -#endif +/* platform/compiler-specific setup */ +#include "libssh2_setup.h" #include +#include #include +#include /* The following CPP block should really only be in session.c and packet.c. However, AIX have #define's for 'events' and 'revents' and we are using @@ -66,15 +69,8 @@ */ #ifdef HAVE_POLL # include -#else -# if defined(HAVE_SELECT) && !defined(WIN32) -# ifdef HAVE_SYS_SELECT_H +#elif defined(HAVE_SELECT) && defined(HAVE_SYS_SELECT_H) # include -# else -# include -# include -# endif -# endif #endif /* Needed for struct iovec on some platforms */ @@ -83,10 +79,10 @@ #endif #ifdef HAVE_SYS_SOCKET_H -# include +#include #endif #ifdef HAVE_SYS_IOCTL_H -# include +#include #endif #ifdef HAVE_INTTYPES_H #include @@ -95,7 +91,20 @@ #include "libssh2.h" #include "libssh2_publickey.h" #include "libssh2_sftp.h" -#include "misc.h" /* for the linked list stuff */ +#include "misc.h" + +#ifdef _WIN32 +/* Detect Windows App environment which has a restricted access + to the Win32 APIs. */ +# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \ + defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ + !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define LIBSSH2_WINDOWS_UWP +# endif +# endif +#endif #ifndef FALSE #define FALSE 0 @@ -104,13 +113,64 @@ #define TRUE 1 #endif -#ifdef _MSC_VER +#ifndef UINT32_MAX +#define UINT32_MAX 0xffffffffU +#endif + +#if (defined(__GNUC__) || defined(__clang__)) && \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(LIBSSH2_NO_FMT_CHECKS) +#ifdef __MINGW_PRINTF_FORMAT +#define LIBSSH2_PRINTF(fmt, arg) \ + __attribute__((format(__MINGW_PRINTF_FORMAT, fmt, arg))) +#elif !defined(__MINGW32__) +#define LIBSSH2_PRINTF(fmt, arg) \ + __attribute__((format(printf, fmt, arg))) +#endif +#endif +#ifndef LIBSSH2_PRINTF +#define LIBSSH2_PRINTF(fmt, arg) +#endif + +/* Use local implementation when not available */ +#if !defined(HAVE_SNPRINTF) +#undef snprintf +#define snprintf _libssh2_snprintf +#define LIBSSH2_SNPRINTF +int _libssh2_snprintf(char *cp, size_t cp_max_len, const char *fmt, ...) + LIBSSH2_PRINTF(3, 4); +#endif + +#if !defined(HAVE_GETTIMEOFDAY) +#define HAVE_GETTIMEOFDAY +#undef gettimeofday +#define gettimeofday _libssh2_gettimeofday +#define LIBSSH2_GETTIMEOFDAY +int _libssh2_gettimeofday(struct timeval *tp, void *tzp); +#elif defined(HAVE_SYS_TIME_H) +#include +#endif + +#if !defined(LIBSSH2_FALLTHROUGH) +#if (defined(__GNUC__) && __GNUC__ >= 7) || \ + (defined(__clang__) && __clang_major__ >= 10) +# define LIBSSH2_FALLTHROUGH() __attribute__((fallthrough)) +#else +# define LIBSSH2_FALLTHROUGH() do {} while (0) +#endif +#endif + /* "inline" keyword is valid only with C++ engine! */ +#ifdef __GNUC__ +#undef inline +#define inline __inline__ +#elif defined(_MSC_VER) +#undef inline #define inline __inline #endif /* 3DS doesn't seem to have iovec */ -#if defined(WIN32) || defined(_3DS) +#if defined(_WIN32) || defined(_3DS) struct iovec { size_t iov_len; @@ -119,20 +179,6 @@ struct iovec { #endif -/* Provide iovec / writev on WIN32 platform. */ -#ifdef WIN32 - -static inline int writev(int sock, struct iovec *iov, int nvecs) -{ - DWORD ret; - if(WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) { - return ret; - } - return -1; -} - -#endif /* WIN32 */ - #ifdef __OS400__ /* Force parameter type. */ #define send(s, b, l, f) send((s), (unsigned char *) (b), (l), (f)) @@ -140,13 +186,6 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #include "crypto.h" -#ifdef HAVE_WINSOCK2_H - -#include -#include - -#endif - #ifndef SIZE_MAX #if _WIN64 #define SIZE_MAX 0xFFFFFFFFFFFFFFFF @@ -159,6 +198,12 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #define UINT_MAX 0xFFFFFFFF #endif +#define LIBSSH2_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define LIBSSH2_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */ +#define MAX_MACSIZE 64 /* MUST fit biggest MAC length we support */ + /* RFC4253 section 6.1 Maximum Packet Length says: * * "All implementations MUST be able to process packets with @@ -170,33 +215,51 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #define MAX_SHA_DIGEST_LEN SHA512_DIGEST_LENGTH #define LIBSSH2_ALLOC(session, count) \ - session->alloc((count), &(session)->abstract) + session->alloc((count), &(session)->abstract) #define LIBSSH2_CALLOC(session, count) _libssh2_calloc(session, count) #define LIBSSH2_REALLOC(session, ptr, count) \ - ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : \ - session->alloc((count), &(session)->abstract)) + ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : \ + session->alloc((count), &(session)->abstract)) #define LIBSSH2_FREE(session, ptr) \ - session->free((ptr), &(session)->abstract) + session->free((ptr), &(session)->abstract) #define LIBSSH2_IGNORE(session, data, datalen) \ - session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract) + session->ssh_msg_ignore((session), (data), (int)(datalen), \ + &(session)->abstract) #define LIBSSH2_DEBUG(session, always_display, message, message_len, \ - language, language_len) \ - session->ssh_msg_debug((session), (always_display), (message), \ - (message_len), (language), (language_len), \ + language, language_len) \ + session->ssh_msg_debug((session), (always_display), \ + (message), (int)(message_len), \ + (language), (int)(language_len), \ &(session)->abstract) #define LIBSSH2_DISCONNECT(session, reason, message, message_len, \ - language, language_len) \ - session->ssh_msg_disconnect((session), (reason), (message), \ - (message_len), (language), (language_len), \ + language, language_len) \ + session->ssh_msg_disconnect((session), (reason), \ + (message), (int)(message_len), \ + (language), (int)(language_len), \ &(session)->abstract) -#define LIBSSH2_MACERROR(session, data, datalen) \ - session->macerror((session), (data), (datalen), &(session)->abstract) -#define LIBSSH2_X11_OPEN(channel, shost, sport) \ +#define LIBSSH2_MACERROR(session, data, datalen) \ + session->macerror((session), (data), (int)(datalen), &(session)->abstract) +#define LIBSSH2_X11_OPEN(channel, shost, sport) \ channel->session->x11(((channel)->session), (channel), \ (shost), (sport), (&(channel)->session->abstract)) -#define LIBSSH2_CHANNEL_CLOSE(session, channel) \ +#define LIBSSH2_AUTHAGENT(channel) \ + channel->session->authagent(((channel)->session), (channel), \ + (&(channel)->session->abstract)) + +#define LIBSSH2_ADD_IDENTITIES(session, buffer, agentPath) \ + session->addLocalIdentities((session), (buffer), \ + (agentPath), (&(session->abstract))) + +#define LIBSSH2_AUTHAGENT_SIGN(session, blob, blen, \ + data, dlen, sig, sigLen, \ + agentPath) \ + session->agentSignCallback((session), (blob), (blen), \ + (data), (dlen), (sig), (sigLen), \ + (agentPath), (&(session->abstract))) + +#define LIBSSH2_CHANNEL_CLOSE(session, channel) \ channel->close_cb((session), &(session)->abstract, \ (channel), &(channel)->abstract) @@ -205,9 +268,9 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #define LIBSSH2_RECV_FD(session, fd, buffer, length, flags) \ (session->recv)(fd, buffer, length, flags, &session->abstract) -#define LIBSSH2_SEND(session, buffer, length, flags) \ +#define LIBSSH2_SEND(session, buffer, length, flags) \ LIBSSH2_SEND_FD(session, session->socket_fd, buffer, length, flags) -#define LIBSSH2_RECV(session, buffer, length, flags) \ +#define LIBSSH2_RECV(session, buffer, length, flags) \ LIBSSH2_RECV_FD(session, session->socket_fd, buffer, length, flags) typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD; @@ -235,7 +298,9 @@ typedef enum libssh2_NB_state_jump3, libssh2_NB_state_jump4, libssh2_NB_state_jump5, - libssh2_NB_state_end + libssh2_NB_state_error_closing, + libssh2_NB_state_end, + libssh2_NB_state_jumpauthagent } libssh2_nonblocking_states; typedef struct packet_require_state_t @@ -341,6 +406,18 @@ typedef struct packet_x11_open_state_t LIBSSH2_CHANNEL *channel; } packet_x11_open_state_t; +#define AuthAgentUnavail "Auth Agent unavailable" + +typedef struct packet_authagent_state_t +{ + libssh2_nonblocking_states state; + unsigned char packet[17 + (sizeof(AuthAgentUnavail) - 1)]; + uint32_t sender_channel; + uint32_t initial_window_size; + uint32_t packet_size; + LIBSSH2_CHANNEL *channel; +} packet_authagent_state_t; + struct _LIBSSH2_PACKET { struct list_node node; /* linked list header */ @@ -371,7 +448,7 @@ struct _LIBSSH2_CHANNEL struct list_node node; unsigned char *channel_type; - unsigned channel_type_len; + size_t channel_type_len; /* channel's program exit status */ int exit_status; @@ -383,7 +460,7 @@ struct _LIBSSH2_CHANNEL /* Amount of bytes to be refunded to receive window (but not yet sent) */ uint32_t adjust_queue; /* Data immediately available for reading */ - uint32_t read_avail; + size_t read_avail; LIBSSH2_SESSION *session; @@ -424,7 +501,7 @@ struct _LIBSSH2_CHANNEL size_t flush_refund_bytes; size_t flush_flush_bytes; - /* State variables used in libssh2_channel_receive_window_adjust() */ + /* State variables used in libssh2_channel_receive_window_adjust2() */ libssh2_nonblocking_states adjust_state; unsigned char adjust_adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */ @@ -463,6 +540,11 @@ struct _LIBSSH2_CHANNEL size_t req_auth_agent_packet_len; unsigned char req_auth_agent_local_channel[4]; packet_requirev_state_t req_auth_agent_requirev_state; + + /* State variables used in libssh2_channel_signal_ex() */ + libssh2_nonblocking_states sendsignal_state; + unsigned char *sendsignal_packet; + size_t sendsignal_packet_len; }; struct _LIBSSH2_LISTENER @@ -510,7 +592,7 @@ typedef struct _libssh2_endpoint_data char *lang_prefs; } libssh2_endpoint_data; -#define PACKETBUFSIZE (1024*16) +#define PACKETBUFSIZE MAX_SSH_PACKET_LEN struct transportpacket { @@ -533,14 +615,15 @@ struct transportpacket packet_length + padding_length + 4 + mac_length. */ unsigned char *payload; /* this is a pointer to a LIBSSH2_ALLOC() - area to which we write decrypted data */ + area to which we write incoming packet data + which is not yet decrypted in etm mode. */ unsigned char *wptr; /* write pointer into the payload to where we are currently writing decrypted data */ /* ------------- for outgoing data --------------- */ unsigned char outbuf[MAX_SSH_PACKET_LEN]; /* area for the outgoing data */ - int ototal_num; /* size of outbuf in number of bytes */ + ssize_t ototal_num; /* size of outbuf in number of bytes */ const unsigned char *odata; /* original pointer to the data */ size_t olen; /* original size of the data we stored in outbuf */ @@ -578,26 +661,31 @@ struct _LIBSSH2_PUBLICKEY #define LIBSSH2_SCP_RESPONSE_BUFLEN 256 struct flags { - int sigpipe; /* LIBSSH2_FLAG_SIGPIPE */ - int compress; /* LIBSSH2_FLAG_COMPRESS */ + int sigpipe; /* LIBSSH2_FLAG_SIGPIPE */ + int compress; /* LIBSSH2_FLAG_COMPRESS */ + int quote_paths; /* LIBSSH2_FLAG_QUOTE_PATHS */ }; struct _LIBSSH2_SESSION { /* Memory management callbacks */ void *abstract; - LIBSSH2_ALLOC_FUNC((*alloc)); - LIBSSH2_REALLOC_FUNC((*realloc)); - LIBSSH2_FREE_FUNC((*free)); + + LIBSSH2_ALLOC_FUNC((*alloc)); + LIBSSH2_REALLOC_FUNC((*realloc)); + LIBSSH2_FREE_FUNC((*free)); /* Other callbacks */ - LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore)); - LIBSSH2_DEBUG_FUNC((*ssh_msg_debug)); - LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); - LIBSSH2_MACERROR_FUNC((*macerror)); - LIBSSH2_X11_OPEN_FUNC((*x11)); - LIBSSH2_SEND_FUNC((*send)); - LIBSSH2_RECV_FUNC((*recv)); + LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore)); + LIBSSH2_DEBUG_FUNC((*ssh_msg_debug)); + LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); + LIBSSH2_MACERROR_FUNC((*macerror)); + LIBSSH2_X11_OPEN_FUNC((*x11)); + LIBSSH2_AUTHAGENT_FUNC((*authagent)); + LIBSSH2_ADD_IDENTITIES_FUNC((*addLocalIdentities)); + LIBSSH2_AUTHAGENT_SIGN_FUNC((*agentSignCallback)); + LIBSSH2_SEND_FUNC((*send)); + LIBSSH2_RECV_FUNC((*recv)); /* Method preferences -- NULL yields "load order" */ char *kex_prefs; @@ -610,7 +698,7 @@ struct _LIBSSH2_SESSION /* Agreed Key Exchange Method */ const LIBSSH2_KEX_METHOD *kex; - unsigned int burn_optimistic_kexinit:1; + unsigned int burn_optimistic_kexinit; unsigned char *session_id; uint32_t session_id_len; @@ -633,13 +721,22 @@ struct _LIBSSH2_SESSION #if LIBSSH2_MD5 unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH]; int server_hostkey_md5_valid; -#endif /* ! LIBSSH2_MD5 */ +#endif /* ! LIBSSH2_MD5 */ unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH]; int server_hostkey_sha1_valid; unsigned char server_hostkey_sha256[SHA256_DIGEST_LENGTH]; int server_hostkey_sha256_valid; + /* public key algorithms accepted as comma separated list */ + char *server_sign_algorithms; + + /* key signing algorithm preferences -- NULL yields server order */ + char *sign_algo_prefs; + + /* Whether to use the OpenSSH Strict KEX extension */ + int kex_strict; + /* (remote as source of data -- packet_read ) */ libssh2_endpoint_data remote; @@ -662,7 +759,8 @@ struct _LIBSSH2_SESSION int socket_state; int socket_block_directions; int socket_prev_blockstate; /* stores the state of the socket blockiness - when libssh2_session_startup() is called */ + when libssh2_session_handshake() + is called */ /* Error tracking */ const char *err_msg; @@ -680,7 +778,7 @@ struct _LIBSSH2_SESSION /* State variables used in libssh2_banner_send() */ libssh2_nonblocking_states banner_TxRx_state; - char banner_TxRx_banner[256]; + char banner_TxRx_banner[8192]; ssize_t banner_TxRx_total_send; /* State variables used in libssh2_kexinit() */ @@ -688,7 +786,7 @@ struct _LIBSSH2_SESSION unsigned char *kexinit_data; size_t kexinit_data_len; - /* State variables used in libssh2_session_startup() */ + /* State variables used in libssh2_session_handshake() */ libssh2_nonblocking_states startup_state; unsigned char *startup_data; size_t startup_data_len; @@ -713,6 +811,7 @@ struct _LIBSSH2_SESSION libssh2_nonblocking_states userauth_list_state; unsigned char *userauth_list_data; size_t userauth_list_data_len; + char *userauth_banner; packet_requirev_state_t userauth_list_packet_requirev_state; /* State variables used in libssh2_userauth_password_ex() */ @@ -753,10 +852,10 @@ struct _LIBSSH2_SESSION size_t userauth_kybd_data_len; unsigned char *userauth_kybd_packet; size_t userauth_kybd_packet_len; - unsigned int userauth_kybd_auth_name_len; - char *userauth_kybd_auth_name; - unsigned userauth_kybd_auth_instruction_len; - char *userauth_kybd_auth_instruction; + size_t userauth_kybd_auth_name_len; + unsigned char *userauth_kybd_auth_name; + size_t userauth_kybd_auth_instruction_len; + unsigned char *userauth_kybd_auth_instruction; unsigned int userauth_kybd_num_prompts; int userauth_kybd_auth_failure; LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts; @@ -803,12 +902,14 @@ struct _LIBSSH2_SESSION states */ packet_queue_listener_state_t packAdd_Qlstn_state; packet_x11_open_state_t packAdd_x11open_state; + packet_authagent_state_t packAdd_authagent_state; /* State variables used in fullpacket() */ libssh2_nonblocking_states fullpacket_state; int fullpacket_macstate; size_t fullpacket_payload_len; int fullpacket_packet_type; + uint32_t fullpacket_required_type; /* State variables used in libssh2_sftp_init() */ libssh2_nonblocking_states sftpInit_state; @@ -816,27 +917,17 @@ struct _LIBSSH2_SESSION LIBSSH2_CHANNEL *sftpInit_channel; unsigned char sftpInit_buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */ - int sftpInit_sent; /* number of bytes from the buffer that have been - sent */ + size_t sftpInit_sent; /* number of bytes from the buffer that have been + sent */ - /* State variables used in libssh2_scp_recv() / libssh_scp_recv2() */ + /* State variables used in libssh2_scp_recv2() */ libssh2_nonblocking_states scpRecv_state; unsigned char *scpRecv_command; size_t scpRecv_command_len; unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN]; size_t scpRecv_response_len; long scpRecv_mode; -#if defined(HAVE_LONGLONG) && defined(HAVE_STRTOLL) - /* we have the type and we can parse such numbers */ - long long scpRecv_size; -#define scpsize_strtol strtoll -#elif defined(HAVE_STRTOI64) - __int64 scpRecv_size; -#define scpsize_strtol _strtoi64 -#else - long scpRecv_size; -#define scpsize_strtol strtol -#endif + libssh2_int64_t scpRecv_size; long scpRecv_mtime; long scpRecv_atime; LIBSSH2_CHANNEL *scpRecv_channel; @@ -853,19 +944,23 @@ struct _LIBSSH2_SESSION int keepalive_interval; int keepalive_want_reply; time_t keepalive_last_sent; + + /* Configurable timeout for packets. Replaces LIBSSH2_READ_TIMEOUT */ + long packet_read_timeout; }; /* session.state bits */ -#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001 -#define LIBSSH2_STATE_NEWKEYS 0x00000002 -#define LIBSSH2_STATE_AUTHENTICATED 0x00000004 -#define LIBSSH2_STATE_KEX_ACTIVE 0x00000008 +#define LIBSSH2_STATE_INITIAL_KEX 0x00000001 +#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000002 +#define LIBSSH2_STATE_NEWKEYS 0x00000004 +#define LIBSSH2_STATE_AUTHENTICATED 0x00000008 +#define LIBSSH2_STATE_KEX_ACTIVE 0x00000010 /* session.flag helpers */ #ifdef MSG_NOSIGNAL -#define LIBSSH2_SOCKET_SEND_FLAGS(session) \ +#define LIBSSH2_SOCKET_SEND_FLAGS(session) \ (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) -#define LIBSSH2_SOCKET_RECV_FLAGS(session) \ +#define LIBSSH2_SOCKET_RECV_FLAGS(session) \ (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) #else /* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */ @@ -887,13 +982,16 @@ struct _LIBSSH2_KEX_METHOD int (*exchange_keys) (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state); + void (*cleanup) (LIBSSH2_SESSION * session, + key_exchange_state_low_t * key_state); + long flags; }; struct _LIBSSH2_HOSTKEY_METHOD { const char *name; - unsigned long hash_len; + size_t hash_len; int (*init) (LIBSSH2_SESSION * session, const unsigned char *hostkey_data, size_t hostkey_data_len, void **abstract); @@ -927,19 +1025,52 @@ struct _LIBSSH2_CRYPT_METHOD int iv_len; int secret_len; + /* length of the authentication tag */ + int auth_len; + long flags; int (*init) (LIBSSH2_SESSION * session, const LIBSSH2_CRYPT_METHOD * method, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, int encrypt, void **abstract); - int (*crypt) (LIBSSH2_SESSION * session, unsigned char *block, - size_t blocksize, void **abstract); + int (*get_len) (LIBSSH2_SESSION * session, unsigned int seqno, + unsigned char *data, size_t data_size, unsigned int *len, + void **abstract); + int (*crypt) (LIBSSH2_SESSION * session, unsigned int seqno, + unsigned char *block, size_t blocksize, void **abstract, + int firstlast); int (*dtor) (LIBSSH2_SESSION * session, void **abstract); - _libssh2_cipher_type(algo); + _libssh2_cipher_type(algo); }; +/* Bit flags for _LIBSSH2_CRYPT_METHOD */ + +/* Crypto method has integrated message authentication */ +#define LIBSSH2_CRYPT_FLAG_INTEGRATED_MAC 1 +/* Crypto method does not encrypt the packet length */ +#define LIBSSH2_CRYPT_FLAG_PKTLEN_AAD 2 +/* Crypto method must encrypt and decrypt entire messages */ +#define LIBSSH2_CRYPT_FLAG_REQUIRES_FULL_PACKET 4 + +/* Convenience macros for accessing crypt flags */ +/* Local crypto flags */ +#define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \ + ((session)->local.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag)) +/* Remote crypto flags */ +#define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \ + ((session)->remote.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag)) + +/* Values for firstlast */ +#define FIRST_BLOCK 1 +#define MIDDLE_BLOCK 0 +#define LAST_BLOCK 2 + +/* Convenience macros for accessing firstlast */ +#define IS_FIRST(firstlast) (firstlast & FIRST_BLOCK) +#define IS_LAST(firstlast) (firstlast & LAST_BLOCK) + struct _LIBSSH2_COMP_METHOD { const char *name; @@ -963,23 +1094,12 @@ struct _LIBSSH2_COMP_METHOD }; #ifdef LIBSSH2DEBUG -void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, - ...); +void +_libssh2_debug_low(LIBSSH2_SESSION * session, int context, const char *format, + ...) LIBSSH2_PRINTF(3, 4); +#define _libssh2_debug(x) _libssh2_debug_low x #else -#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__GNUC__) -/* C99 supported and also by older GCC */ -#define _libssh2_debug(x,y,z,...) do {} while (0) -#else -/* no gcc and not C99, do static and hopefully inline */ -static inline void -_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) -{ - (void)session; - (void)context; - (void)format; -} -#endif +#define _libssh2_debug(x) do {} while(0) #endif #define LIBSSH2_SOCKET_UNKNOWN 1 @@ -1006,6 +1126,7 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) #define SSH_MSG_DEBUG 4 #define SSH_MSG_SERVICE_REQUEST 5 #define SSH_MSG_SERVICE_ACCEPT 6 +#define SSH_MSG_EXT_INFO 7 #define SSH_MSG_KEXINIT 20 #define SSH_MSG_NEWKEYS 21 @@ -1069,18 +1190,22 @@ ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, size_t length, int flags, void **abstract); -#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when - waiting for more data to arrive */ +#define LIBSSH2_DEFAULT_READ_TIMEOUT 60 /* generic timeout in seconds used when + waiting for more data to arrive */ int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, key_exchange_state_t * state); +unsigned char *_libssh2_kex_agree_instr(unsigned char *haystack, + size_t haystack_len, + const unsigned char *needle, + size_t needle_len); + /* Let crypt.c/hostkey.c expose their method structs */ const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void); const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void); -/* misc.c */ int _libssh2_bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, @@ -1094,12 +1219,12 @@ int _libssh2_pem_parse(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const unsigned char *passphrase, - FILE * fp, unsigned char **data, unsigned int *datalen); + FILE * fp, unsigned char **data, size_t *datalen); int _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const char *filedata, size_t filedata_len, - unsigned char **data, unsigned int *datalen); + unsigned char **data, size_t *datalen); /* OpenSSL keys */ int _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, @@ -1111,37 +1236,41 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, const char *filedata, size_t filedata_len, struct string_buf **decrypted_buf); -int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen); -int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, +int _libssh2_pem_decode_sequence(unsigned char **data, size_t *datalen); +int _libssh2_pem_decode_integer(unsigned char **data, size_t *datalen, unsigned char **i, unsigned int *ilen); /* global.c */ void _libssh2_init_if_needed(void); +/* Utility function for certificate auth */ +size_t plain_method(char *method, size_t method_len); #define ARRAY_SIZE(a) (sizeof ((a)) / sizeof ((a)[0])) /* define to output the libssh2_int64_t type in a *printf() */ -#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__) +#if defined(__BORLANDC__) || defined(_MSC_VER) #define LIBSSH2_INT64_T_FORMAT "I64d" +#elif defined(__MINGW32__) +#define LIBSSH2_INT64_T_FORMAT PRId64 #else #define LIBSSH2_INT64_T_FORMAT "lld" #endif /* In Windows the default file mode is text but an application can override it. -Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 -*/ -#if defined(WIN32) || defined(MSDOS) + Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 + */ +#if defined(_WIN32) || defined(MSDOS) #define FOPEN_READTEXT "rt" #define FOPEN_WRITETEXT "wt" #define FOPEN_APPENDTEXT "at" #elif defined(__CYGWIN__) -/* Cygwin has specific behavior we need to address when WIN32 is not defined. -https://cygwin.com/cygwin-ug-net/using-textbinary.html -For write we want our output to have line endings of LF and be compatible with -other Cygwin utilities. For read we want to handle input that may have line -endings either CRLF or LF so 't' is appropriate. -*/ +/* Cygwin has specific behavior we need to address when _WIN32 is not defined. + https://cygwin.com/cygwin-ug-net/using-textbinary.html + For write we want our output to have line endings of LF and be compatible + with other Cygwin utilities. For read we want to handle input that may have + line endings either CRLF or LF so 't' is appropriate. + */ #define FOPEN_READTEXT "rt" #define FOPEN_WRITETEXT "w" #define FOPEN_APPENDTEXT "a" @@ -1151,4 +1280,4 @@ endings either CRLF or LF so 't' is appropriate. #define FOPEN_APPENDTEXT "a" #endif -#endif /* __LIBSSH2_PRIV_H */ +#endif /* LIBSSH2_PRIV_H */ diff --git a/uppsrc/Core/SSH/libssh2/libssh2_publickey.h b/uppsrc/Core/SSH/libssh2/libssh2_publickey.h index 5dbdcf925..566acd653 100644 --- a/uppsrc/Core/SSH/libssh2/libssh2_publickey.h +++ b/uppsrc/Core/SSH/libssh2/libssh2_publickey.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2004-2006, Sara Golemon +/* Copyright (C) Sara Golemon * All rights reserved. * * Redistribution and use in source and binary forms, @@ -41,6 +41,8 @@ * * For more information on the publickey subsystem, * refer to IETF draft: secsh-publickey + * + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LIBSSH2_PUBLICKEY_H @@ -72,9 +74,9 @@ typedef struct _libssh2_publickey_list { /* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */ #define libssh2_publickey_attribute(name, value, mandatory) \ - { (name), strlen(name), (value), strlen(value), (mandatory) }, + { (name), strlen(name), (value), strlen(value), (mandatory) }, #define libssh2_publickey_attribute_fast(name, value, mandatory) \ - { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) }, + { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) }, #ifdef __cplusplus extern "C" { @@ -92,10 +94,12 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, unsigned long blob_len, char overwrite, unsigned long num_attrs, const libssh2_publickey_attribute attrs[]); -#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \ - num_attrs, attrs) \ - libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \ - (overwrite), (num_attrs), (attrs)) +#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \ + num_attrs, attrs) \ + libssh2_publickey_add_ex((pkey), \ + (name), strlen(name), \ + (blob), (blob_len), \ + (overwrite), (num_attrs), (attrs)) LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, @@ -103,7 +107,9 @@ LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *blob, unsigned long blob_len); #define libssh2_publickey_remove(pkey, name, blob, blob_len) \ - libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len)) + libssh2_publickey_remove_ex((pkey), \ + (name), strlen(name), \ + (blob), (blob_len)) LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, @@ -119,4 +125,4 @@ LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey); } /* extern "C" */ #endif -#endif /* ifndef: LIBSSH2_PUBLICKEY_H */ +#endif /* LIBSSH2_PUBLICKEY_H */ diff --git a/uppsrc/Core/SSH/libssh2/libssh2_setup.h b/uppsrc/Core/SSH/libssh2/libssh2_setup.h new file mode 100644 index 000000000..dda14bbb4 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/libssh2_setup.h @@ -0,0 +1,103 @@ +/* Copyright (C) Viktor Szakats + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef LIBSSH2_SETUP_H +#define LIBSSH2_SETUP_H +/* Header for platform/compiler-specific initialization. + Used by 'src', 'example', 'tests' */ + +/* Define mingw-w64 version macros, eg __MINGW{32,64}_{MINOR,MAJOR}_VERSION */ +#ifdef __MINGW32__ +#include <_mingw.h> +#endif + +/* Configuration provided by build tools (autotools and CMake), + and via platform-specific directories for os400 and vms */ +#define HAVE_CONFIG_H 1 +#if defined(HAVE_CONFIG_H) || defined(__OS400__) || defined(__VMS) + +#include "libssh2_config.h" + +/* Hand-crafted configuration for platforms which lack config tool. + Keep this synced with root CMakeLists.txt */ +#elif defined(_WIN32) + +#define HAVE_SELECT +#define HAVE_SNPRINTF + +#ifdef __MINGW32__ +# define HAVE_UNISTD_H +# define HAVE_INTTYPES_H +# define HAVE_SYS_TIME_H +# define HAVE_GETTIMEOFDAY +# define HAVE_STRTOLL +#elif defined(_MSC_VER) +# if _MSC_VER >= 1800 +# define HAVE_INTTYPES_H +# define HAVE_STRTOLL +# else +# define HAVE_STRTOI64 +# endif +# if _MSC_VER < 1900 +# undef HAVE_SNPRINTF +# endif +#endif + +#endif /* defined(HAVE_CONFIG_H) */ + +/* Below applies to both auto-detected and hand-crafted configs */ + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOGDI +#define NOGDI +#endif +#ifndef NONLS +#define NONLS +#endif + +#ifdef __MINGW32__ +# ifdef __MINGW64_VERSION_MAJOR +/* Number of bits in a file offset, on hosts where this is settable. */ +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# endif +#elif defined(_MSC_VER) +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS /* for fopen(), getenv() */ +# endif +# if !defined(LIBSSH2_LIBRARY) || defined(LIBSSH2_TESTS) + /* apply to examples and tests only */ +# ifndef _CRT_NONSTDC_NO_DEPRECATE +# define _CRT_NONSTDC_NO_DEPRECATE /* for strdup(), write() */ +# endif +# ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +# define _WINSOCK_DEPRECATED_NO_WARNINGS /* for inet_addr() */ +# endif + /* we cannot access our internal snprintf() implementation in examples and + tests when linking to a shared libssh2. */ +# if _MSC_VER < 1900 +# undef HAVE_SNPRINTF +# define HAVE_SNPRINTF +# define snprintf _snprintf +# endif +# endif +# if _MSC_VER < 1500 +# define vsnprintf _vsnprintf +# endif +# if _MSC_VER < 1900 +# define strdup _strdup +/* Silence bogus warning C4127: conditional expression is constant */ +# pragma warning(disable:4127) +# endif +#endif + +#endif /* _WIN32 */ + +#endif /* LIBSSH2_SETUP_H */ diff --git a/uppsrc/Core/SSH/libssh2/libssh2_sftp.h b/uppsrc/Core/SSH/libssh2/libssh2_sftp.h index 476ea8704..ab7b0af4d 100644 --- a/uppsrc/Core/SSH/libssh2/libssh2_sftp.h +++ b/uppsrc/Core/SSH/libssh2/libssh2_sftp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2004-2008, Sara Golemon +/* Copyright (C) Sara Golemon * All rights reserved. * * Redistribution and use in source and binary forms, @@ -33,6 +33,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LIBSSH2_SFTP_H @@ -40,7 +42,7 @@ #include "libssh2.h" -#ifndef WIN32 +#ifndef _WIN32 #include #endif @@ -165,19 +167,19 @@ struct _LIBSSH2_SFTP_STATVFS { /* macros to check for specific file types, added in 1.2.5 */ #define LIBSSH2_SFTP_S_ISLNK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) #define LIBSSH2_SFTP_S_ISREG(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG) #define LIBSSH2_SFTP_S_ISDIR(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) #define LIBSSH2_SFTP_S_ISCHR(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) #define LIBSSH2_SFTP_S_ISBLK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) #define LIBSSH2_SFTP_S_ISFIFO(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO) #define LIBSSH2_SFTP_S_ISSOCK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) /* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */ @@ -230,12 +232,25 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, unsigned int filename_len, unsigned long flags, long mode, int open_type); -#define libssh2_sftp_open(sftp, filename, flags, mode) \ - libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \ - (mode), LIBSSH2_SFTP_OPENFILE) +#define libssh2_sftp_open(sftp, filename, flags, mode) \ + libssh2_sftp_open_ex((sftp), \ + (filename), (unsigned int)strlen(filename), \ + (flags), (mode), LIBSSH2_SFTP_OPENFILE) #define libssh2_sftp_opendir(sftp, path) \ - libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \ - LIBSSH2_SFTP_OPENDIR) + libssh2_sftp_open_ex((sftp), \ + (path), (unsigned int)strlen(path), \ + 0, 0, LIBSSH2_SFTP_OPENDIR) +LIBSSH2_API LIBSSH2_SFTP_HANDLE * +libssh2_sftp_open_ex_r(LIBSSH2_SFTP *sftp, + const char *filename, + size_t filename_len, + unsigned long flags, + long mode, int open_type, + LIBSSH2_SFTP_ATTRIBUTES *attrs); +#define libssh2_sftp_open_r(sftp, filename, flags, mode, attrs) \ + libssh2_sftp_open_ex_r((sftp), (filename), strlen(filename), \ + (flags), (mode), LIBSSH2_SFTP_OPENFILE, \ + (attrs)) LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen); @@ -245,7 +260,7 @@ LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \ char *longentry, size_t longentry_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs); -#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ +#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \ (attrs)) @@ -281,17 +296,27 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, unsigned int dest_filename_len, long flags); #define libssh2_sftp_rename(sftp, sourcefile, destfile) \ - libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \ - (destfile), strlen(destfile), \ + libssh2_sftp_rename_ex((sftp), \ + (sourcefile), (unsigned int)strlen(sourcefile), \ + (destfile), (unsigned int)strlen(destfile), \ LIBSSH2_SFTP_RENAME_OVERWRITE | \ LIBSSH2_SFTP_RENAME_ATOMIC | \ LIBSSH2_SFTP_RENAME_NATIVE) +LIBSSH2_API int libssh2_sftp_posix_rename_ex(LIBSSH2_SFTP *sftp, + const char *source_filename, + size_t srouce_filename_len, + const char *dest_filename, + size_t dest_filename_len); +#define libssh2_sftp_posix_rename(sftp, sourcefile, destfile) \ + libssh2_sftp_posix_rename_ex((sftp), (sourcefile), strlen(sourcefile), \ + (destfile), strlen(destfile)) + LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, unsigned int filename_len); #define libssh2_sftp_unlink(sftp, filename) \ - libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename)) + libssh2_sftp_unlink_ex((sftp), (filename), (unsigned int)strlen(filename)) LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st); @@ -305,13 +330,13 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode); #define libssh2_sftp_mkdir(sftp, path, mode) \ - libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode)) + libssh2_sftp_mkdir_ex((sftp), (path), (unsigned int)strlen(path), (mode)) LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len); #define libssh2_sftp_rmdir(sftp, path) \ - libssh2_sftp_rmdir_ex((sftp), (path), strlen(path)) + libssh2_sftp_rmdir_ex((sftp), (path), (unsigned int)strlen(path)) LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, @@ -319,14 +344,14 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs); #define libssh2_sftp_stat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \ - (attrs)) + libssh2_sftp_stat_ex((sftp), (path), (unsigned int)strlen(path), \ + LIBSSH2_SFTP_STAT, (attrs)) #define libssh2_sftp_lstat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \ - (attrs)) + libssh2_sftp_stat_ex((sftp), (path), (unsigned int)strlen(path), \ + LIBSSH2_SFTP_LSTAT, (attrs)) #define libssh2_sftp_setstat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \ - (attrs)) + libssh2_sftp_stat_ex((sftp), (path), (unsigned int)strlen(path), \ + LIBSSH2_SFTP_SETSTAT, (attrs)) LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, @@ -335,13 +360,19 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, unsigned int target_len, int link_type); #define libssh2_sftp_symlink(sftp, orig, linkpath) \ - libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \ - strlen(linkpath), LIBSSH2_SFTP_SYMLINK) + libssh2_sftp_symlink_ex((sftp), \ + (orig), (unsigned int)strlen(orig), \ + (linkpath), (unsigned int)strlen(linkpath), \ + LIBSSH2_SFTP_SYMLINK) #define libssh2_sftp_readlink(sftp, path, target, maxlen) \ - libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ - LIBSSH2_SFTP_READLINK) + libssh2_sftp_symlink_ex((sftp), \ + (path), (unsigned int)strlen(path), \ + (target), (maxlen), \ + LIBSSH2_SFTP_READLINK) #define libssh2_sftp_realpath(sftp, path, target, maxlen) \ - libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ + libssh2_sftp_symlink_ex((sftp), \ + (path), (unsigned int)strlen(path), \ + (target), (maxlen), \ LIBSSH2_SFTP_REALPATH) #ifdef __cplusplus diff --git a/uppsrc/Core/SSH/libssh2/mac.c b/uppsrc/Core/SSH/libssh2/mac.c index 5ac71df4c..00d3c21fb 100644 --- a/uppsrc/Core/SSH/libssh2/mac.c +++ b/uppsrc/Core/SSH/libssh2/mac.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004-2007, Sara Golemon +/* Copyright (C) Sara Golemon * All rights reserved. * * Redistribution and use in source and binary forms, @@ -33,20 +33,33 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #include "mac.h" -#ifdef LIBSSH2_MAC_NONE +#if defined(LIBSSH2DEBUG) && defined(LIBSSH2_MAC_NONE_INSECURE) /* mac_none_MAC - * Minimalist MAC: No MAC + * + * Minimalist MAC: No MAC. DO NOT USE. + * + * The SSH2 Transport allows implementations to forego a message + * authentication code. While this is less of a security risk than using + * a "none" cipher, it is still not recommended as disabling MAC hashes + * removes a layer of security. + * + * Enabling this option will allow for "none" as a negotiable method, + * however it still requires that the method be advertised by the remote + * end and that no more-preferable methods are available. + * */ static int mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t packet_len, const unsigned char *addtl, + size_t addtl_len, void **abstract) { return 0; } @@ -60,9 +73,10 @@ static LIBSSH2_MAC_METHOD mac_method_none = { 0, NULL, mac_none_MAC, - NULL + NULL, + 0 }; -#endif /* LIBSSH2_MAC_NONE */ +#endif /* defined(LIBSSH2DEBUG) && defined(LIBSSH2_MAC_NONE_INSECURE) */ /* mac_method_common_init * Initialize simple mac methods @@ -73,7 +87,7 @@ mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key, { *abstract = key; *free_key = 0; - (void) session; + (void)session; return 0; } @@ -102,29 +116,31 @@ mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract) */ static int mac_method_hmac_sha2_512_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + size_t packet_len, + const unsigned char *addtl, + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + int res; + (void)session; _libssh2_htonu32(seqno_buf, seqno); - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_sha512_init(&ctx, *abstract, 64); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); + if(!_libssh2_hmac_ctx_init(&ctx)) + return 1; + res = _libssh2_hmac_sha512_init(&ctx, *abstract, 64) && + _libssh2_hmac_update(&ctx, seqno_buf, 4) && + _libssh2_hmac_update(&ctx, packet, packet_len); + if(res && addtl && addtl_len) + res = _libssh2_hmac_update(&ctx, addtl, addtl_len); + if(res) + res = _libssh2_hmac_final(&ctx, buf); + _libssh2_hmac_cleanup(&ctx); - return 0; + return !res; } @@ -136,7 +152,19 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512 = { mac_method_common_init, mac_method_hmac_sha2_512_hash, mac_method_common_dtor, + 0 }; + +static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512_etm = { + "hmac-sha2-512-etm@openssh.com", + 64, + 64, + mac_method_common_init, + mac_method_hmac_sha2_512_hash, + mac_method_common_dtor, + 1 +}; + #endif @@ -147,29 +175,31 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512 = { */ static int mac_method_hmac_sha2_256_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + size_t packet_len, + const unsigned char *addtl, + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + int res; + (void)session; _libssh2_htonu32(seqno_buf, seqno); - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_sha256_init(&ctx, *abstract, 32); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); + if(!_libssh2_hmac_ctx_init(&ctx)) + return 1; + res = _libssh2_hmac_sha256_init(&ctx, *abstract, 32) && + _libssh2_hmac_update(&ctx, seqno_buf, 4) && + _libssh2_hmac_update(&ctx, packet, packet_len); + if(res && addtl && addtl_len) + res = _libssh2_hmac_update(&ctx, addtl, addtl_len); + if(res) + res = _libssh2_hmac_final(&ctx, buf); + _libssh2_hmac_cleanup(&ctx); - return 0; + return !res; } @@ -181,7 +211,19 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_256 = { mac_method_common_init, mac_method_hmac_sha2_256_hash, mac_method_common_dtor, + 0 }; + +static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_256_etm = { + "hmac-sha2-256-etm@openssh.com", + 32, + 32, + mac_method_common_init, + mac_method_hmac_sha2_256_hash, + mac_method_common_dtor, + 1 +}; + #endif @@ -194,27 +236,29 @@ static int mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + int res; + (void)session; _libssh2_htonu32(seqno_buf, seqno); - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_sha1_init(&ctx, *abstract, 20); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); + if(!_libssh2_hmac_ctx_init(&ctx)) + return 1; + res = _libssh2_hmac_sha1_init(&ctx, *abstract, 20) && + _libssh2_hmac_update(&ctx, seqno_buf, 4) && + _libssh2_hmac_update(&ctx, packet, packet_len); + if(res && addtl && addtl_len) + res = _libssh2_hmac_update(&ctx, addtl, addtl_len); + if(res) + res = _libssh2_hmac_final(&ctx, buf); + _libssh2_hmac_cleanup(&ctx); - return 0; + return !res; } @@ -226,6 +270,17 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1 = { mac_method_common_init, mac_method_hmac_sha1_hash, mac_method_common_dtor, + 0 +}; + +static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_etm = { + "hmac-sha1-etm@openssh.com", + 20, + 20, + mac_method_common_init, + mac_method_hmac_sha1_hash, + mac_method_common_dtor, + 1 }; /* mac_method_hmac_sha1_96_hash @@ -235,16 +290,17 @@ static int mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t addtl_len, void **abstract) { unsigned char temp[SHA_DIGEST_LENGTH]; - mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len, - addtl, addtl_len, abstract); - memcpy(buf, (char *) temp, 96 / 8); + if(mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len, + addtl, addtl_len, abstract)) + return 1; + memcpy(buf, (char *) temp, 96 / 8); return 0; } @@ -257,6 +313,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = { mac_method_common_init, mac_method_hmac_sha1_96_hash, mac_method_common_dtor, + 0 }; #if LIBSSH2_MD5 @@ -267,27 +324,29 @@ static int mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + int res; + (void)session; _libssh2_htonu32(seqno_buf, seqno); - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_md5_init(&ctx, *abstract, 16); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); + if(!_libssh2_hmac_ctx_init(&ctx)) + return 1; + res = _libssh2_hmac_md5_init(&ctx, *abstract, 16) && + _libssh2_hmac_update(&ctx, seqno_buf, 4) && + _libssh2_hmac_update(&ctx, packet, packet_len); + if(res && addtl && addtl_len) + res = _libssh2_hmac_update(&ctx, addtl, addtl_len); + if(res) + res = _libssh2_hmac_final(&ctx, buf); + _libssh2_hmac_cleanup(&ctx); - return 0; + return !res; } @@ -299,6 +358,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_md5 = { mac_method_common_init, mac_method_hmac_md5_hash, mac_method_common_dtor, + 0 }; /* mac_method_hmac_md5_96_hash @@ -308,13 +368,16 @@ static int mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t addtl_len, void **abstract) { unsigned char temp[MD5_DIGEST_LENGTH]; - mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len, - addtl, addtl_len, abstract); + + if(mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len, + addtl, addtl_len, abstract)) + return 1; + memcpy(buf, (char *) temp, 96 / 8); return 0; } @@ -328,6 +391,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = { mac_method_common_init, mac_method_hmac_md5_96_hash, mac_method_common_dtor, + 0 }; #endif /* LIBSSH2_MD5 */ @@ -339,28 +403,30 @@ static int mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + int res; + (void)session; _libssh2_htonu32(seqno_buf, seqno); - libssh2_hmac_ctx_init(ctx); - libssh2_hmac_ripemd160_init(&ctx, *abstract, 20); - libssh2_hmac_update(ctx, seqno_buf, 4); - libssh2_hmac_update(ctx, packet, packet_len); - if(addtl && addtl_len) { - libssh2_hmac_update(ctx, addtl, addtl_len); - } - libssh2_hmac_final(ctx, buf); - libssh2_hmac_cleanup(&ctx); + if(!_libssh2_hmac_ctx_init(&ctx)) + return 1; + res = _libssh2_hmac_ripemd160_init(&ctx, *abstract, 20) && + _libssh2_hmac_update(&ctx, seqno_buf, 4) && + _libssh2_hmac_update(&ctx, packet, packet_len); + if(res && addtl && addtl_len) + res = _libssh2_hmac_update(&ctx, addtl, addtl_len); + if(res) + res = _libssh2_hmac_final(&ctx, buf); + _libssh2_hmac_cleanup(&ctx); - return 0; + return !res; } @@ -372,6 +438,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160 = { mac_method_common_init, mac_method_hmac_ripemd160_hash, mac_method_common_dtor, + 0 }; static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = { @@ -381,17 +448,21 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = { mac_method_common_init, mac_method_hmac_ripemd160_hash, mac_method_common_dtor, + 0 }; #endif /* LIBSSH2_HMAC_RIPEMD */ static const LIBSSH2_MAC_METHOD *mac_methods[] = { #if LIBSSH2_HMAC_SHA256 &mac_method_hmac_sha2_256, + &mac_method_hmac_sha2_256_etm, #endif #if LIBSSH2_HMAC_SHA512 &mac_method_hmac_sha2_512, + &mac_method_hmac_sha2_512_etm, #endif &mac_method_hmac_sha1, + &mac_method_hmac_sha1_etm, &mac_method_hmac_sha1_96, #if LIBSSH2_MD5 &mac_method_hmac_md5, @@ -401,9 +472,9 @@ static const LIBSSH2_MAC_METHOD *mac_methods[] = { &mac_method_hmac_ripemd160, &mac_method_hmac_ripemd160_openssh_com, #endif /* LIBSSH2_HMAC_RIPEMD */ -#ifdef LIBSSH2_MAC_NONE +#if defined(LIBSSH2DEBUG) && defined(LIBSSH2_MAC_NONE_INSECURE) &mac_method_none, -#endif /* LIBSSH2_MAC_NONE */ +#endif NULL }; @@ -412,3 +483,71 @@ _libssh2_mac_methods(void) { return mac_methods; } + +#if LIBSSH2_AES_GCM +static int +mac_method_none_init(LIBSSH2_SESSION * session, unsigned char *key, + int *free_key, void **abstract) +{ + (void)session; + (void)key; + (void)free_key; + (void)abstract; + return 0; +} + +static int +mac_method_hmac_none_hash(LIBSSH2_SESSION * session, + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + size_t packet_len, + const unsigned char *addtl, + size_t addtl_len, void **abstract) +{ + (void)session; + (void)buf; + (void)seqno; + (void)packet; + (void)packet_len; + (void)addtl; + (void)addtl_len; + (void)abstract; + return 0; +} + +static int +mac_method_none_dtor(LIBSSH2_SESSION * session, void **abstract) +{ + (void)session; + (void)abstract; + return 0; +} + +/* Stub for aes256-gcm@openssh.com crypto type, which has an integrated + HMAC method. This must not be added to mac_methods[] since it cannot be + negotiated separately. */ +static const LIBSSH2_MAC_METHOD mac_method_hmac_aesgcm = { + "INTEGRATED-AES-GCM", /* made up name for display only */ + 16, + 16, + mac_method_none_init, + mac_method_hmac_none_hash, + mac_method_none_dtor, + 0 +}; +#endif /* LIBSSH2_AES_GCM */ + +/* See if the negotiated crypto method has its own authentication scheme that + * obviates the need for a separate negotiated hmac method */ +const LIBSSH2_MAC_METHOD * +_libssh2_mac_override(const LIBSSH2_CRYPT_METHOD *crypt) +{ +#if LIBSSH2_AES_GCM + if(!strcmp(crypt->name, "aes256-gcm@openssh.com") || + !strcmp(crypt->name, "aes128-gcm@openssh.com")) + return &mac_method_hmac_aesgcm; +#else + (void) crypt; +#endif /* LIBSSH2_AES_GCM */ + return NULL; +} diff --git a/uppsrc/Core/SSH/libssh2/mac.h b/uppsrc/Core/SSH/libssh2/mac.h index 46fce5424..8e5b8c280 100644 --- a/uppsrc/Core/SSH/libssh2/mac.h +++ b/uppsrc/Core/SSH/libssh2/mac.h @@ -1,6 +1,7 @@ -#ifndef __LIBSSH2_MAC_H -#define __LIBSSH2_MAC_H -/* Copyright (C) 2009-2010 by Daniel Stenberg +#ifndef LIBSSH2_MAC_H +#define LIBSSH2_MAC_H +/* Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -35,6 +36,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -54,13 +56,17 @@ struct _LIBSSH2_MAC_METHOD void **abstract); int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract); + size_t packet_len, const unsigned char *addtl, + size_t addtl_len, void **abstract); int (*dtor) (LIBSSH2_SESSION * session, void **abstract); + + int etm; /* encrypt-then-mac */ }; typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD; const LIBSSH2_MAC_METHOD **_libssh2_mac_methods(void); +const LIBSSH2_MAC_METHOD *_libssh2_mac_override( + const LIBSSH2_CRYPT_METHOD *crypt); -#endif /* __LIBSSH2_MAC_H */ +#endif /* LIBSSH2_MAC_H */ diff --git a/uppsrc/Core/SSH/libssh2/mbedtls.c b/uppsrc/Core/SSH/libssh2/mbedtls.c index 4629ce4a9..a66e36c5a 100644 --- a/uppsrc/Core/SSH/libssh2/mbedtls.c +++ b/uppsrc/Core/SSH/libssh2/mbedtls.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, Art +/* Copyright (C) Art * All rights reserved. * * Redistribution and use in source and binary forms, @@ -33,11 +33,21 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include "libssh2_priv.h" +#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */ -#ifdef LIBSSH2_MBEDTLS /* compile only if we build with mbedtls */ +#include + +#if MBEDTLS_VERSION_NUMBER < 0x03000000 +#define mbedtls_cipher_info_get_key_bitlen(c) (c->key_bitlen) +#define mbedtls_cipher_info_get_iv_size(c) (c->iv_size) +#define mbedtls_rsa_get_len(rsa) (rsa->len) + +#define MBEDTLS_PRIVATE(m) m +#endif /*******************************************************************/ /* @@ -63,7 +73,7 @@ _libssh2_mbedtls_init(void) ret = mbedtls_ctr_drbg_seed(&_libssh2_mbedtls_ctr_drbg, mbedtls_entropy_func, &_libssh2_mbedtls_entropy, NULL, 0); - if(ret != 0) + if(ret) mbedtls_ctr_drbg_free(&_libssh2_mbedtls_ctr_drbg); } @@ -75,7 +85,7 @@ _libssh2_mbedtls_free(void) } int -_libssh2_mbedtls_random(unsigned char *buf, int len) +_libssh2_mbedtls_random(unsigned char *buf, size_t len) { int ret; ret = mbedtls_ctr_drbg_random(&_libssh2_mbedtls_ctr_drbg, buf, len); @@ -83,19 +93,13 @@ _libssh2_mbedtls_random(unsigned char *buf, int len) } static void -_libssh2_mbedtls_safe_free(void *buf, int len) +_libssh2_mbedtls_safe_free(void *buf, size_t len) { -#ifndef LIBSSH2_CLEAR_MEMORY - (void)len; -#endif - if(!buf) return; -#ifdef LIBSSH2_CLEAR_MEMORY if(len > 0) _libssh2_explicit_zero(buf, len); -#endif mbedtls_free(buf); } @@ -122,10 +126,14 @@ _libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx, mbedtls_cipher_init(ctx); ret = mbedtls_cipher_setup(ctx, cipher_info); if(!ret) - ret = mbedtls_cipher_setkey(ctx, secret, cipher_info->key_bitlen, op); + ret = mbedtls_cipher_setkey(ctx, + secret, + (int)mbedtls_cipher_info_get_key_bitlen(cipher_info), + op); if(!ret) - ret = mbedtls_cipher_set_iv(ctx, iv, cipher_info->iv_size); + ret = mbedtls_cipher_set_iv(ctx, iv, + mbedtls_cipher_info_get_iv_size(cipher_info)); return ret == 0 ? 0 : -1; } @@ -135,14 +143,15 @@ _libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx, _libssh2_cipher_type(algo), int encrypt, unsigned char *block, - size_t blocklen) + size_t blocklen, int firstlast) { int ret; unsigned char *output; size_t osize, olen, finish_olen; - (void) encrypt; - (void) algo; + (void)encrypt; + (void)algo; + (void)firstlast; osize = blocklen + mbedtls_cipher_get_block_size(ctx); @@ -178,8 +187,8 @@ _libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx) int _libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, - mbedtls_md_type_t mdtype, - const unsigned char *key, unsigned long keylen) + mbedtls_md_type_t mdtype, + const unsigned char *key, size_t keylen) { const mbedtls_md_info_t *md_info; int ret, hmac; @@ -188,7 +197,7 @@ _libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, if(!md_info) return 0; - hmac = key == NULL ? 0 : 1; + hmac = key ? 1 : 0; mbedtls_md_init(ctx); ret = mbedtls_md_setup(ctx, md_info, hmac); @@ -210,11 +219,11 @@ _libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash) ret = mbedtls_md_finish(ctx, hash); mbedtls_md_free(ctx); - return ret == 0 ? 0 : -1; + return ret == 0 ? 1 : 0; } int -_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, +_libssh2_mbedtls_hash(const unsigned char *data, size_t datalen, mbedtls_md_type_t mdtype, unsigned char *hash) { const mbedtls_md_info_t *md_info; @@ -229,6 +238,66 @@ _libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, return ret == 0 ? 0 : -1; } +int _libssh2_hmac_ctx_init(libssh2_hmac_ctx *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + return 1; +} + +#if LIBSSH2_MD5 +int _libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_MD5, key, keylen); +} +#endif + +#if LIBSSH2_HMAC_RIPEMD +int _libssh2_hmac_ripemd160_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_RIPEMD160, key, keylen); +} +#endif + +int _libssh2_hmac_sha1_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_SHA1, key, keylen); +} + +int _libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_SHA256, key, keylen); +} + +int _libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_SHA512, key, keylen); +} + +int _libssh2_hmac_update(libssh2_hmac_ctx *ctx, + const void *data, size_t datalen) +{ + int ret = mbedtls_md_hmac_update(ctx, data, datalen); + + return ret == 0 ? 1 : 0; +} + +int _libssh2_hmac_final(libssh2_hmac_ctx *ctx, void *data) +{ + int ret = mbedtls_md_hmac_finish(ctx, data); + + return ret == 0 ? 1 : 0; +} + +void _libssh2_hmac_cleanup(libssh2_hmac_ctx *ctx) +{ + mbedtls_md_free(ctx); +} + /*******************************************************************/ /* * mbedTLS backend: BigNumber functions @@ -261,7 +330,7 @@ _libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom) { size_t len; int err; - int i; + size_t i; if(!bn || bits <= 0) return -1; @@ -272,8 +341,8 @@ _libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom) if(err) return -1; - /* Zero unused bits above the most significant bit*/ - for(i = len*8 - 1; bits <= i; --i) { + /* Zero unused bits above the most significant bit */ + for(i = len*8 - 1; (size_t)bits <= i; --i) { err = mbedtls_mpi_set_bit(bn, i, 0); if(err) return -1; @@ -285,10 +354,12 @@ _libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom) will be set to 1, so that the product of two such random numbers will always have 2*bits length. */ - for(i = 0; i <= top; ++i) { - err = mbedtls_mpi_set_bit(bn, bits-i-1, 1); - if(err) - return -1; + if(top >= 0) { + for(i = 0; i <= (size_t)top; ++i) { + err = mbedtls_mpi_set_bit(bn, bits-i-1, 1); + if(err) + return -1; + } } /* make odd by setting first bit in least significant byte */ @@ -309,52 +380,64 @@ _libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom) int _libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen) + const unsigned char *edata, + unsigned long elen, + const unsigned char *ndata, + unsigned long nlen, + const unsigned char *ddata, + unsigned long dlen, + const unsigned char *pdata, + unsigned long plen, + const unsigned char *qdata, + unsigned long qlen, + const unsigned char *e1data, + unsigned long e1len, + const unsigned char *e2data, + unsigned long e2len, + const unsigned char *coeffdata, + unsigned long coefflen) { int ret; libssh2_rsa_ctx *ctx; ctx = (libssh2_rsa_ctx *) mbedtls_calloc(1, sizeof(libssh2_rsa_ctx)); - if(ctx != NULL) { + if(ctx) { +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + mbedtls_rsa_init(ctx); +#else mbedtls_rsa_init(ctx, MBEDTLS_RSA_PKCS_V15, 0); +#endif } else return -1; /* !checksrc! disable ASSIGNWITHINCONDITION 1 */ - if((ret = mbedtls_mpi_read_binary(&(ctx->E), edata, elen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->N), ndata, nlen) ) != 0) { + if((ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(E)), + edata, elen)) || + (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(N)), + ndata, nlen))) { ret = -1; } if(!ret) { - ctx->len = mbedtls_mpi_size(&(ctx->N)); + ctx->MBEDTLS_PRIVATE(len) = + mbedtls_mpi_size(&(ctx->MBEDTLS_PRIVATE(N))); } if(!ret && ddata) { /* !checksrc! disable ASSIGNWITHINCONDITION 1 */ - if((ret = mbedtls_mpi_read_binary(&(ctx->D), ddata, dlen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->P), pdata, plen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->Q), qdata, qlen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->DP), e1data, e1len) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->DQ), e2data, e2len) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->QP), coeffdata, coefflen) ) - != 0) { + if((ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(D)), + ddata, dlen)) || + (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(P)), + pdata, plen)) || + (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(Q)), + qdata, qlen)) || + (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(DP)), + e1data, e1len)) || + (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(DQ)), + e2data, e2len)) || + (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(QP)), + coeffdata, coefflen))) { ret = -1; } ret = mbedtls_rsa_check_privkey(ctx); @@ -373,23 +456,33 @@ _libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa, int _libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) + LIBSSH2_SESSION *session, + const char *filename, + const unsigned char *passphrase) { int ret; mbedtls_pk_context pkey; mbedtls_rsa_context *pk_rsa; *rsa = (libssh2_rsa_ctx *) LIBSSH2_ALLOC(session, sizeof(libssh2_rsa_ctx)); - if(*rsa == NULL) + if(!*rsa) return -1; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + mbedtls_rsa_init(*rsa); +#else mbedtls_rsa_init(*rsa, MBEDTLS_RSA_PKCS_V15, 0); +#endif mbedtls_pk_init(&pkey); +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_keyfile(&pkey, filename, (char *)passphrase, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg); +#else ret = mbedtls_pk_parse_keyfile(&pkey, filename, (char *)passphrase); - if(ret != 0 || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { +#endif + if(ret || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { mbedtls_pk_free(&pkey); mbedtls_rsa_free(*rsa); LIBSSH2_FREE(session, *rsa); @@ -406,10 +499,10 @@ _libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa, int _libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) + LIBSSH2_SESSION *session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase) { int ret; mbedtls_pk_context pkey; @@ -418,7 +511,7 @@ _libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, size_t pwd_len; *rsa = (libssh2_rsa_ctx *) mbedtls_calloc(1, sizeof(libssh2_rsa_ctx)); - if(*rsa == NULL) + if(!*rsa) return -1; /* @@ -426,20 +519,28 @@ _libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, private-key from memory will fail if the last byte is not a null byte */ filedata_nullterm = mbedtls_calloc(filedata_len + 1, 1); - if(filedata_nullterm == NULL) { + if(!filedata_nullterm) { return -1; } memcpy(filedata_nullterm, filedata, filedata_len); mbedtls_pk_init(&pkey); - pwd_len = passphrase != NULL ? strlen((const char *)passphrase) : 0; + pwd_len = passphrase ? strlen((const char *)passphrase) : 0; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_key(&pkey, (unsigned char *)filedata_nullterm, + filedata_len + 1, + passphrase, pwd_len, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg); +#else ret = mbedtls_pk_parse_key(&pkey, (unsigned char *)filedata_nullterm, filedata_len + 1, passphrase, pwd_len); +#endif _libssh2_mbedtls_safe_free(filedata_nullterm, filedata_len); - if(ret != 0 || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { + if(ret || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { mbedtls_pk_free(&pkey); mbedtls_rsa_free(*rsa); LIBSSH2_FREE(session, *rsa); @@ -455,49 +556,115 @@ _libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, } int -_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len) +_libssh2_mbedtls_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, + size_t hash_len, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len) { - unsigned char hash[SHA_DIGEST_LENGTH]; int ret; + int md_type; + unsigned char *hash; - ret = _libssh2_mbedtls_hash(m, m_len, MBEDTLS_MD_SHA1, hash); - if(ret) + if(sig_len < mbedtls_rsa_get_len(rsactx)) + return -1; + + hash = malloc(hash_len); + if(!hash) + return -1; + + if(hash_len == SHA_DIGEST_LENGTH) { + md_type = MBEDTLS_MD_SHA1; + } + else if(hash_len == SHA256_DIGEST_LENGTH) { + md_type = MBEDTLS_MD_SHA256; + } + else if(hash_len == SHA512_DIGEST_LENGTH) { + md_type = MBEDTLS_MD_SHA512; + } + else{ + free(hash); + return -1; /* unsupported digest */ + } + ret = _libssh2_mbedtls_hash(m, m_len, md_type, hash); + + if(ret) { + free(hash); return -1; /* failure */ + } - ret = mbedtls_rsa_pkcs1_verify(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, - MBEDTLS_MD_SHA1, SHA_DIGEST_LENGTH, +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_rsa_pkcs1_verify(rsactx, + md_type, (unsigned int)hash_len, hash, sig); +#else + ret = mbedtls_rsa_pkcs1_verify(rsactx, NULL, NULL, MBEDTLS_RSA_PUBLIC, + md_type, (unsigned int)hash_len, + hash, sig); +#endif + free(hash); return (ret == 0) ? 0 : -1; } int -_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len) +_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len) +{ + return _libssh2_mbedtls_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH, + sig, sig_len, m, m_len); +} + +int +_libssh2_mbedtls_rsa_sha2_sign(LIBSSH2_SESSION *session, + libssh2_rsa_ctx *rsa, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, + size_t *signature_len) { int ret; unsigned char *sig; - unsigned int sig_len; + size_t sig_len; + int md_type; - (void)hash_len; - - sig_len = rsa->len; + sig_len = mbedtls_rsa_get_len(rsa); sig = LIBSSH2_ALLOC(session, sig_len); if(!sig) { return -1; } - - ret = mbedtls_rsa_pkcs1_sign(rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, - MBEDTLS_MD_SHA1, SHA_DIGEST_LENGTH, - hash, sig); + ret = 0; + if(hash_len == SHA_DIGEST_LENGTH) { + md_type = MBEDTLS_MD_SHA1; + } + else if(hash_len == SHA256_DIGEST_LENGTH) { + md_type = MBEDTLS_MD_SHA256; + } + else if(hash_len == SHA512_DIGEST_LENGTH) { + md_type = MBEDTLS_MD_SHA512; + } + else { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unsupported hash digest length"); + ret = -1; + } + if(ret == 0) { +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_rsa_pkcs1_sign(rsa, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg, + md_type, (unsigned int)hash_len, + hash, sig); +#else + ret = mbedtls_rsa_pkcs1_sign(rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, + md_type, (unsigned int)hash_len, + hash, sig); +#endif + } if(ret) { LIBSSH2_FREE(session, sig); return -1; @@ -509,6 +676,18 @@ _libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session, return (ret == 0) ? 0 : -1; } +int +_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION * session, + libssh2_rsa_ctx * rsactx, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, + size_t *signature_len) +{ + return _libssh2_mbedtls_rsa_sha2_sign(session, rsactx, hash, hash_len, + signature, signature_len); +} + void _libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *ctx) { @@ -518,16 +697,16 @@ _libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *ctx) static unsigned char * gen_publickey_from_rsa(LIBSSH2_SESSION *session, - mbedtls_rsa_context *rsa, - size_t *keylen) + mbedtls_rsa_context *rsa, + size_t *keylen) { - int e_bytes, n_bytes; - unsigned long len; + uint32_t e_bytes, n_bytes; + uint32_t len; unsigned char *key; unsigned char *p; - e_bytes = mbedtls_mpi_size(&rsa->E); - n_bytes = mbedtls_mpi_size(&rsa->N); + e_bytes = (uint32_t)mbedtls_mpi_size(&rsa->MBEDTLS_PRIVATE(E)); + n_bytes = (uint32_t)mbedtls_mpi_size(&rsa->MBEDTLS_PRIVATE(N)); /* Key form is "ssh-rsa" + e + n. */ len = 4 + 7 + 4 + e_bytes + 4 + n_bytes; @@ -547,11 +726,11 @@ gen_publickey_from_rsa(LIBSSH2_SESSION *session, _libssh2_htonu32(p, e_bytes); p += 4; - mbedtls_mpi_write_binary(&rsa->E, p, e_bytes); + mbedtls_mpi_write_binary(&rsa->MBEDTLS_PRIVATE(E), p, e_bytes); _libssh2_htonu32(p, n_bytes); p += 4; - mbedtls_mpi_write_binary(&rsa->N, p, n_bytes); + mbedtls_mpi_write_binary(&rsa->MBEDTLS_PRIVATE(N), p, n_bytes); *keylen = (size_t)(p - key); return key; @@ -559,11 +738,11 @@ gen_publickey_from_rsa(LIBSSH2_SESSION *session, static int _libssh2_mbedtls_pub_priv_key(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - mbedtls_pk_context *pkey) + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + mbedtls_pk_context *pkey) { unsigned char *key = NULL, *mth = NULL; size_t keylen = 0, mthlen = 0; @@ -588,7 +767,7 @@ _libssh2_mbedtls_pub_priv_key(LIBSSH2_SESSION *session, rsa = mbedtls_pk_rsa(*pkey); key = gen_publickey_from_rsa(session, rsa, &keylen); - if(key == NULL) { + if(!key) { ret = -1; } @@ -611,27 +790,33 @@ _libssh2_mbedtls_pub_priv_key(LIBSSH2_SESSION *session, int _libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privatekey, + const char *passphrase) { mbedtls_pk_context pkey; char buf[1024]; int ret; mbedtls_pk_init(&pkey); +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_keyfile(&pkey, privatekey, passphrase, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg); +#else ret = mbedtls_pk_parse_keyfile(&pkey, privatekey, passphrase); - if(ret != 0) { +#endif + if(ret) { mbedtls_strerror(ret, (char *)buf, sizeof(buf)); mbedtls_pk_free(&pkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, buf); } ret = _libssh2_mbedtls_pub_priv_key(session, method, method_len, - pubkeydata, pubkeydata_len, &pkey); + pubkeydata, pubkeydata_len, &pkey); mbedtls_pk_free(&pkey); @@ -640,13 +825,13 @@ _libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session, int _libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) { mbedtls_pk_context pkey; char buf[1024]; @@ -659,34 +844,76 @@ _libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session, private-key from memory will fail if the last byte is not a null byte */ privatekeydata_nullterm = mbedtls_calloc(privatekeydata_len + 1, 1); - if(privatekeydata_nullterm == NULL) { + if(!privatekeydata_nullterm) { return -1; } memcpy(privatekeydata_nullterm, privatekeydata, privatekeydata_len); mbedtls_pk_init(&pkey); - pwd_len = passphrase != NULL ? strlen((const char *)passphrase) : 0; + pwd_len = passphrase ? strlen((const char *)passphrase) : 0; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_key(&pkey, + (unsigned char *)privatekeydata_nullterm, + privatekeydata_len + 1, + (const unsigned char *)passphrase, pwd_len, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg); +#else ret = mbedtls_pk_parse_key(&pkey, (unsigned char *)privatekeydata_nullterm, privatekeydata_len + 1, (const unsigned char *)passphrase, pwd_len); +#endif _libssh2_mbedtls_safe_free(privatekeydata_nullterm, privatekeydata_len); - if(ret != 0) { + if(ret) { mbedtls_strerror(ret, (char *)buf, sizeof(buf)); mbedtls_pk_free(&pkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, buf); } ret = _libssh2_mbedtls_pub_priv_key(session, method, method_len, - pubkeydata, pubkeydata_len, &pkey); + pubkeydata, pubkeydata_len, &pkey); mbedtls_pk_free(&pkey); return ret; } +int +_libssh2_mbedtls_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) +{ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)algorithm; + (void)flags; + (void)application; + (void)key_handle; + (void)handle_len; + (void)privatekeydata; + (void)privatekeydata_len; + (void)passphrase; + + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public SK key from private key file: " + "Method unimplemented in mbedTLS backend"); +} + void _libssh2_init_aes_ctr(void) { /* no implementation */ @@ -756,23 +983,24 @@ _libssh2_mbedtls_ecdsa_create_key(LIBSSH2_SESSION *session, *privkey = LIBSSH2_ALLOC(session, sizeof(mbedtls_ecp_keypair)); - if(*privkey == NULL) + if(!*privkey) 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) + &_libssh2_mbedtls_ctr_drbg)) goto failed; - plen = 2 * mbedtls_mpi_size(&(*privkey)->grp.P) + 1; + plen = 2 * mbedtls_mpi_size(&(*privkey)->MBEDTLS_PRIVATE(grp).P) + 1; *pubkey_oct = LIBSSH2_ALLOC(session, plen); - if(*pubkey_oct == NULL) + if(!*pubkey_oct) goto failed; - if(mbedtls_ecp_point_write_binary(&(*privkey)->grp, &(*privkey)->Q, + if(mbedtls_ecp_point_write_binary(&(*privkey)->MBEDTLS_PRIVATE(grp), + &(*privkey)->MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, pubkey_oct_len, *pubkey_oct, plen) == 0) return 0; @@ -800,18 +1028,22 @@ _libssh2_mbedtls_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ctx, { *ctx = mbedtls_calloc(1, sizeof(mbedtls_ecp_keypair)); - if(*ctx == NULL) + if(!*ctx) goto failed; mbedtls_ecdsa_init(*ctx); - if(mbedtls_ecp_group_load(&(*ctx)->grp, (mbedtls_ecp_group_id)curve) != 0) + if(mbedtls_ecp_group_load(&(*ctx)->MBEDTLS_PRIVATE(grp), + (mbedtls_ecp_group_id)curve)) goto failed; - if(mbedtls_ecp_point_read_binary(&(*ctx)->grp, &(*ctx)->Q, k, k_len) != 0) + if(mbedtls_ecp_point_read_binary(&(*ctx)->MBEDTLS_PRIVATE(grp), + &(*ctx)->MBEDTLS_PRIVATE(Q), + k, k_len)) goto failed; - if(mbedtls_ecp_check_pubkey(&(*ctx)->grp, &(*ctx)->Q) == 0) + if(mbedtls_ecp_check_pubkey(&(*ctx)->MBEDTLS_PRIVATE(grp), + &(*ctx)->MBEDTLS_PRIVATE(Q)) == 0) return 0; failed: @@ -837,26 +1069,28 @@ _libssh2_mbedtls_ecdh_gen_k(_libssh2_bn **k, mbedtls_ecp_point pubkey; int rc = 0; - if(*k == NULL) + if(!*k) return -1; mbedtls_ecp_point_init(&pubkey); - if(mbedtls_ecp_point_read_binary(&privkey->grp, &pubkey, - server_pubkey, server_pubkey_len) != 0) { + if(mbedtls_ecp_point_read_binary(&privkey->MBEDTLS_PRIVATE(grp), + &pubkey, + server_pubkey, server_pubkey_len)) { rc = -1; goto cleanup; } - if(mbedtls_ecdh_compute_shared(&privkey->grp, *k, - &pubkey, &privkey->d, + if(mbedtls_ecdh_compute_shared(&privkey->MBEDTLS_PRIVATE(grp), *k, + &pubkey, + &privkey->MBEDTLS_PRIVATE(d), mbedtls_ctr_drbg_random, - &_libssh2_mbedtls_ctr_drbg) != 0) { + &_libssh2_mbedtls_ctr_drbg)) { rc = -1; goto cleanup; } - if(mbedtls_ecp_check_privkey(&privkey->grp, *k) != 0) + if(mbedtls_ecp_check_privkey(&privkey->MBEDTLS_PRIVATE(grp), *k)) rc = -1; cleanup: @@ -866,19 +1100,18 @@ cleanup: 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); \ - } \ - \ -} +#define LIBSSH2_MBEDTLS_ECDSA_VERIFY(digest_type) \ + do { \ + unsigned char hsh[SHA##digest_type##_DIGEST_LENGTH]; \ + \ + if(libssh2_sha##digest_type(m, m_len, hsh) == 0) { \ + rc = mbedtls_ecdsa_verify(&ctx->MBEDTLS_PRIVATE(grp), hsh, \ + SHA##digest_type##_DIGEST_LENGTH, \ + &ctx->MBEDTLS_PRIVATE(Q), &pr, &ps); \ + } \ + } while(0) -/* _libssh2_ecdsa_sign +/* _libssh2_ecdsa_verify * * Verifies the ECDSA signature of a hashed message * @@ -896,10 +1129,10 @@ _libssh2_mbedtls_ecdsa_verify(libssh2_ecdsa_ctx *ctx, mbedtls_mpi_init(&pr); mbedtls_mpi_init(&ps); - if(mbedtls_mpi_read_binary(&pr, r, r_len) != 0) + if(mbedtls_mpi_read_binary(&pr, r, r_len)) goto cleanup; - if(mbedtls_mpi_read_binary(&ps, s, s_len) != 0) + if(mbedtls_mpi_read_binary(&ps, s, s_len)) goto cleanup; switch(_libssh2_ecdsa_get_curve_type(ctx)) { @@ -936,15 +1169,23 @@ _libssh2_mbedtls_parse_eckey(libssh2_ecdsa_ctx **ctx, pwd_len = pwd ? strlen((const char *) pwd) : 0; - if(mbedtls_pk_parse_key(pkey, data, data_len, pwd, pwd_len) != 0) +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + if(mbedtls_pk_parse_key(pkey, data, data_len, pwd, pwd_len, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg)) + goto failed; +#else + if(mbedtls_pk_parse_key(pkey, data, data_len, pwd, pwd_len)) + goto failed; +#endif if(mbedtls_pk_get_type(pkey) != MBEDTLS_PK_ECKEY) goto failed; *ctx = LIBSSH2_ALLOC(session, sizeof(libssh2_ecdsa_ctx)); - if(*ctx == NULL) + if(!*ctx) goto failed; mbedtls_ecdsa_init(*ctx); @@ -975,45 +1216,50 @@ _libssh2_mbedtls_parse_openssh_key(libssh2_ecdsa_ctx **ctx, if(_libssh2_openssh_pem_parse_memory(session, pwd, (const char *)data, data_len, - &decrypted) != 0) + &decrypted)) goto failed; - if(_libssh2_get_string(decrypted, &name, NULL) != 0) + if(_libssh2_get_string(decrypted, &name, NULL)) goto failed; if(_libssh2_mbedtls_ecdsa_curve_type_from_name((const char *)name, - &type) != 0) + &type)) goto failed; - if(_libssh2_get_string(decrypted, &curve, &curvelen) != 0) + if(_libssh2_get_string(decrypted, &curve, &curvelen)) goto failed; - if(_libssh2_get_string(decrypted, &point_buf, &pointlen) != 0) + if(_libssh2_get_string(decrypted, &point_buf, &pointlen)) goto failed; - if(_libssh2_get_bignum_bytes(decrypted, &exponent, &exponentlen) != 0) + if(_libssh2_get_bignum_bytes(decrypted, &exponent, &exponentlen)) goto failed; *ctx = LIBSSH2_ALLOC(session, sizeof(libssh2_ecdsa_ctx)); - if(*ctx == NULL) + if(!*ctx) goto failed; mbedtls_ecdsa_init(*ctx); - if(mbedtls_ecp_group_load(&(*ctx)->grp, (mbedtls_ecp_group_id)type) != 0) + if(mbedtls_ecp_group_load(&(*ctx)->MBEDTLS_PRIVATE(grp), + (mbedtls_ecp_group_id)type)) goto failed; - if(mbedtls_mpi_read_binary(&(*ctx)->d, exponent, exponentlen) != 0) + if(mbedtls_mpi_read_binary(&(*ctx)->MBEDTLS_PRIVATE(d), + exponent, exponentlen)) goto failed; - if(mbedtls_ecp_mul(&(*ctx)->grp, &(*ctx)->Q, - &(*ctx)->d, &(*ctx)->grp.G, + if(mbedtls_ecp_mul(&(*ctx)->MBEDTLS_PRIVATE(grp), + &(*ctx)->MBEDTLS_PRIVATE(Q), + &(*ctx)->MBEDTLS_PRIVATE(d), + &(*ctx)->MBEDTLS_PRIVATE(grp).G, mbedtls_ctr_drbg_random, - &_libssh2_mbedtls_ctr_drbg) != 0) + &_libssh2_mbedtls_ctr_drbg)) goto failed; - if(mbedtls_ecp_check_privkey(&(*ctx)->grp, &(*ctx)->d) == 0) + if(mbedtls_ecp_check_privkey(&(*ctx)->MBEDTLS_PRIVATE(grp), + &(*ctx)->MBEDTLS_PRIVATE(d)) == 0) goto cleanup; failed: @@ -1027,9 +1273,14 @@ cleanup: _libssh2_string_buf_free(session, decrypted); } - return (*ctx == NULL) ? -1 : 0; + return *ctx ? 0 : -1; } +/* Force-expose internal mbedTLS function */ +#if MBEDTLS_VERSION_NUMBER >= 0x03060000 +int mbedtls_pk_load_file(const char *path, unsigned char **buf, size_t *n); +#endif + /* _libssh2_ecdsa_new_private * * Creates a new private key given a file path and password @@ -1043,14 +1294,15 @@ _libssh2_mbedtls_ecdsa_new_private(libssh2_ecdsa_ctx **ctx, 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; + unsigned char *data = NULL; + size_t data_len = 0; mbedtls_pk_init(&pkey); + /* FIXME: Reimplement this functionality via a public API. */ + if(mbedtls_pk_load_file(filename, &data, &data_len)) + goto cleanup; + if(_libssh2_mbedtls_parse_eckey(ctx, &pkey, session, data, data_len, pwd) == 0) goto cleanup; @@ -1063,7 +1315,7 @@ cleanup: _libssh2_mbedtls_safe_free(data, data_len); - return (*ctx == NULL) ? -1 : 0; + return *ctx ? 0 : -1; } /* _libssh2_ecdsa_new_private @@ -1086,7 +1338,7 @@ _libssh2_mbedtls_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx **ctx, ntdata = LIBSSH2_ALLOC(session, data_len + 1); - if(ntdata == NULL) + if(!ntdata) goto cleanup; memcpy(ntdata, data, data_len); @@ -1104,7 +1356,7 @@ cleanup: _libssh2_mbedtls_safe_free(ntdata, data_len); - return (*ctx == NULL) ? -1 : 0; + return *ctx ? 0 : -1; } static unsigned char * @@ -1113,6 +1365,7 @@ _libssh2_mbedtls_mpi_write_binary(unsigned char *buf, size_t bytes) { unsigned char *p = buf; + uint32_t size = (uint32_t)bytes; if(sizeof(&p) / sizeof(p[0]) < 4) { goto done; @@ -1121,19 +1374,19 @@ _libssh2_mbedtls_mpi_write_binary(unsigned char *buf, p += 4; *p = 0; - if(bytes > 0) { - mbedtls_mpi_write_binary(mpi, p + 1, bytes - 1); + if(size > 0) { + mbedtls_mpi_write_binary(mpi, p + 1, size - 1); } - if(bytes > 0 && !(*(p + 1) & 0x80)) { - memmove(p, p + 1, --bytes); + if(size > 0 && !(*(p + 1) & 0x80)) { + memmove(p, p + 1, --size); } - _libssh2_htonu32(p - 4, bytes); + _libssh2_htonu32(p - 4, size); done: - return p + bytes; + return p + size; } /* _libssh2_ecdsa_sign @@ -1146,7 +1399,7 @@ int _libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session, libssh2_ecdsa_ctx *ctx, const unsigned char *hash, - unsigned long hash_len, + size_t hash_len, unsigned char **sign, size_t *sign_len) { @@ -1157,10 +1410,11 @@ _libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session, mbedtls_mpi_init(&pr); mbedtls_mpi_init(&ps); - if(mbedtls_ecdsa_sign(&ctx->grp, &pr, &ps, &ctx->d, + if(mbedtls_ecdsa_sign(&ctx->MBEDTLS_PRIVATE(grp), &pr, &ps, + &ctx->MBEDTLS_PRIVATE(d), hash, hash_len, mbedtls_ctr_drbg_random, - &_libssh2_mbedtls_ctr_drbg) != 0) + &_libssh2_mbedtls_ctr_drbg)) goto cleanup; r_len = mbedtls_mpi_size(&pr) + 1; @@ -1169,7 +1423,7 @@ _libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session, tmp_sign = LIBSSH2_CALLOC(session, tmp_sign_len); - if(tmp_sign == NULL) + if(!tmp_sign) goto cleanup; sp = tmp_sign; @@ -1180,7 +1434,7 @@ _libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session, *sign = LIBSSH2_CALLOC(session, *sign_len); - if(*sign == NULL) + if(!*sign) goto cleanup; memcpy(*sign, tmp_sign, *sign_len); @@ -1192,7 +1446,7 @@ cleanup: _libssh2_mbedtls_safe_free(tmp_sign, tmp_sign_len); - return (*sign == NULL) ? -1 : 0; + return *sign ? 0 : -1; } /* _libssh2_ecdsa_get_curve_type @@ -1204,7 +1458,7 @@ cleanup: libssh2_curve_type _libssh2_mbedtls_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ctx) { - return (libssh2_curve_type) ctx->grp.id; + return (libssh2_curve_type) ctx->MBEDTLS_PRIVATE(grp).id; } /* _libssh2_ecdsa_curve_type_from_name @@ -1220,7 +1474,7 @@ _libssh2_mbedtls_ecdsa_curve_type_from_name(const char *name, int ret = 0; libssh2_curve_type type; - if(name == NULL || strlen(name) != 19) + if(!name || strlen(name) != 19) return -1; if(strcmp(name, "ecdsa-sha2-nistp256") == 0) @@ -1246,6 +1500,34 @@ _libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx) mbedtls_ecdsa_free(ctx); mbedtls_free(ctx); } - #endif /* LIBSSH2_ECDSA */ -#endif /* LIBSSH2_MBEDTLS */ + + +/* _libssh2_supported_key_sign_algorithms + * + * Return supported key hash algo upgrades, see crypto.h + * + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len) +{ + (void)session; + +#if LIBSSH2_RSA_SHA2 + if(key_method_len == 7 && + memcmp(key_method, "ssh-rsa", key_method_len) == 0) { + return "rsa-sha2-512,rsa-sha2-256" +#if LIBSSH2_RSA_SHA1 + ",ssh-rsa" +#endif + ; + } +#endif + + return NULL; +} + +#endif /* LIBSSH2_CRYPTO_C */ diff --git a/uppsrc/Core/SSH/libssh2/mbedtls.h b/uppsrc/Core/SSH/libssh2/mbedtls.h index 671932c58..b1e6726eb 100644 --- a/uppsrc/Core/SSH/libssh2/mbedtls.h +++ b/uppsrc/Core/SSH/libssh2/mbedtls.h @@ -1,6 +1,6 @@ -#ifndef __LIBSSH2_MBEDTLS_H -#define __LIBSSH2_MBEDTLS_H -/* Copyright (c) 2016, Art +#ifndef LIBSSH2_MBEDTLS_H +#define LIBSSH2_MBEDTLS_H +/* Copyright (C) Art * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,11 +35,28 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include -#include +#define LIBSSH2_CRYPTO_ENGINE libssh2_mbedtls +#ifdef __GNUC__ +#pragma GCC diagnostic push +/* mbedTLS (as of v3.5.1) has a `[-Werror=arith-conversion]` + warning in its public headers. */ +#if !defined(__clang__) && __GNUC__ >= 10 +#pragma GCC diagnostic ignored "-Warith-conversion" +#endif +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif +/* mbedTLS (as of v3.5.1) has a duplicate function declaration + in its public headers. Disable the warning that detects it. */ +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + +#include #include #include #include @@ -56,6 +73,10 @@ #include #include +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + /* Define which features are supported. */ #define LIBSSH2_MD5 1 @@ -63,14 +84,25 @@ #define LIBSSH2_HMAC_SHA256 1 #define LIBSSH2_HMAC_SHA512 1 -#define LIBSSH2_AES 1 +#define LIBSSH2_AES_CBC 1 #define LIBSSH2_AES_CTR 1 -#define LIBSSH2_BLOWFISH 1 -#define LIBSSH2_RC4 1 +#define LIBSSH2_AES_GCM 0 +#ifdef MBEDTLS_CIPHER_BLOWFISH_CBC +# define LIBSSH2_BLOWFISH 1 +#else +# define LIBSSH2_BLOWFISH 0 +#endif +#ifdef MBEDTLS_CIPHER_ARC4_128 +# define LIBSSH2_RC4 1 +#else +# define LIBSSH2_RC4 0 +#endif #define LIBSSH2_CAST 0 #define LIBSSH2_3DES 1 #define LIBSSH2_RSA 1 +#define LIBSSH2_RSA_SHA1 1 +#define LIBSSH2_RSA_SHA2 1 #define LIBSSH2_DSA 0 #ifdef MBEDTLS_ECDSA_C # define LIBSSH2_ECDSA 1 @@ -79,7 +111,11 @@ #endif #define LIBSSH2_ED25519 0 +#include "crypto_config.h" + +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM #define MD5_DIGEST_LENGTH 16 +#endif #define SHA_DIGEST_LENGTH 20 #define SHA256_DIGEST_LENGTH 32 #define SHA384_DIGEST_LENGTH 48 @@ -94,12 +130,12 @@ */ #define libssh2_crypto_init() \ - _libssh2_mbedtls_init() + _libssh2_mbedtls_init() #define libssh2_crypto_exit() \ - _libssh2_mbedtls_free() + _libssh2_mbedtls_free() #define _libssh2_random(buf, len) \ - _libssh2_mbedtls_random(buf, len) + _libssh2_mbedtls_random(buf, len) #define libssh2_prepare_iovec(vec, len) /* Empty. */ @@ -111,27 +147,6 @@ #define libssh2_hmac_ctx mbedtls_md_context_t -#define libssh2_hmac_ctx_init(ctx) -#define libssh2_hmac_cleanup(pctx) \ - mbedtls_md_free(pctx) -#define libssh2_hmac_update(ctx, data, datalen) \ - mbedtls_md_hmac_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_hmac_final(ctx, hash) \ - mbedtls_md_hmac_finish(&ctx, hash) - -#define libssh2_hmac_sha1_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, key, keylen) -#define libssh2_hmac_md5_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, key, keylen) -#define libssh2_hmac_ripemd160_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_RIPEMD160, key, keylen) -#define libssh2_hmac_sha256_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, key, keylen) -#define libssh2_hmac_sha384_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, key, keylen) -#define libssh2_hmac_sha512_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, key, keylen) - /*******************************************************************/ /* @@ -141,13 +156,14 @@ #define libssh2_sha1_ctx mbedtls_md_context_t #define libssh2_sha1_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, NULL, 0) + _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, NULL, 0) #define libssh2_sha1_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) + (mbedtls_md_update(&ctx, (const unsigned char *) data, datalen) == 0) #define libssh2_sha1_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) + _libssh2_mbedtls_hash_final(&ctx, hash) #define libssh2_sha1(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA1, hash) + _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA1, hash) + /*******************************************************************/ /* @@ -157,13 +173,13 @@ #define libssh2_sha256_ctx mbedtls_md_context_t #define libssh2_sha256_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, NULL, 0) + _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, NULL, 0) #define libssh2_sha256_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) + (mbedtls_md_update(&ctx, (const unsigned char *) data, datalen) == 0) #define libssh2_sha256_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) + _libssh2_mbedtls_hash_final(&ctx, hash) #define libssh2_sha256(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA256, hash) + _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA256, hash) /*******************************************************************/ @@ -174,13 +190,13 @@ #define libssh2_sha384_ctx mbedtls_md_context_t #define libssh2_sha384_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, NULL, 0) + _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, NULL, 0) #define libssh2_sha384_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) + (mbedtls_md_update(&ctx, (const unsigned char *) data, datalen) == 0) #define libssh2_sha384_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) + _libssh2_mbedtls_hash_final(&ctx, hash) #define libssh2_sha384(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA384, hash) + _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA384, hash) /*******************************************************************/ @@ -191,13 +207,13 @@ #define libssh2_sha512_ctx mbedtls_md_context_t #define libssh2_sha512_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, NULL, 0) + _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, NULL, 0) #define libssh2_sha512_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) + (mbedtls_md_update(&ctx, (const unsigned char *) data, datalen) == 0) #define libssh2_sha512_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) + _libssh2_mbedtls_hash_final(&ctx, hash) #define libssh2_sha512(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA512, hash) + _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA512, hash) /*******************************************************************/ @@ -205,17 +221,16 @@ * mbedTLS backend: MD5 functions */ +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM #define libssh2_md5_ctx mbedtls_md_context_t #define libssh2_md5_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, NULL, 0) + _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, NULL, 0) #define libssh2_md5_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) + (mbedtls_md_update(&ctx, (const unsigned char *) data, datalen) == 0) #define libssh2_md5_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_md5(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_MD5, hash) - + _libssh2_mbedtls_hash_final(&ctx, hash) +#endif /*******************************************************************/ /* @@ -227,26 +242,33 @@ #define _libssh2_rsa_new(rsactx, e, e_len, n, n_len, \ d, d_len, p, p_len, q, q_len, \ e1, e1_len, e2, e2_len, c, c_len) \ - _libssh2_mbedtls_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) + _libssh2_mbedtls_rsa_new(rsactx, e, e_len, n, n_len, \ + d, d_len, p, p_len, q, q_len, \ + e1, e1_len, e2, e2_len, c, c_len) #define _libssh2_rsa_new_private(rsactx, s, filename, passphrase) \ - _libssh2_mbedtls_rsa_new_private(rsactx, s, filename, passphrase) + _libssh2_mbedtls_rsa_new_private(rsactx, s, filename, passphrase) #define _libssh2_rsa_new_private_frommemory(rsactx, s, filedata, \ filedata_len, passphrase) \ - _libssh2_mbedtls_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) + _libssh2_mbedtls_rsa_new_private_frommemory(rsactx, s, filedata, \ + filedata_len, passphrase) #define _libssh2_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) \ - _libssh2_mbedtls_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) + _libssh2_mbedtls_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) + +#define _libssh2_rsa_sha2_sign(s, rsactx, hash, hash_len, sig, sig_len) \ + _libssh2_mbedtls_rsa_sha2_sign(s, rsactx, hash, hash_len, sig, sig_len) + #define _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) \ - _libssh2_mbedtls_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) + _libssh2_mbedtls_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) + +#define _libssh2_rsa_sha2_verify(rsactx, hash_len, sig, sig_len, m, m_len) \ + _libssh2_mbedtls_rsa_sha2_verify(rsactx, hash_len, sig, sig_len, m, m_len) #define _libssh2_rsa_free(rsactx) \ - _libssh2_mbedtls_rsa_free(rsactx) + _libssh2_mbedtls_rsa_free(rsactx) /*******************************************************************/ @@ -291,34 +313,34 @@ typedef enum { #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) + _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) + _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) + _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) + _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) + _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) + _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) + _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) + _libssh2_mbedtls_ecdsa_get_curve_type(ctx) #define _libssh2_ecdsa_free(ctx) \ - _libssh2_mbedtls_ecdsa_free(ctx) + _libssh2_mbedtls_ecdsa_free(ctx) #endif /* LIBSSH2_ECDSA */ @@ -329,11 +351,15 @@ typedef enum { */ #define _libssh2_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) \ - _libssh2_mbedtls_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) + _libssh2_mbedtls_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) #define _libssh2_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) \ - _libssh2_mbedtls_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) + pk, pk_len, pw) \ + _libssh2_mbedtls_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ + pk, pk_len, pw) +#define _libssh2_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \ + f, kh, kh_len, pk, pk_len, pw) \ + _libssh2_mbedtls_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \ + f, kh, kh_len, pk, pk_len, pw) /*******************************************************************/ @@ -351,10 +377,14 @@ typedef enum { #define _libssh2_cipher_aes256 MBEDTLS_CIPHER_AES_256_CBC #define _libssh2_cipher_aes192 MBEDTLS_CIPHER_AES_192_CBC #define _libssh2_cipher_aes128 MBEDTLS_CIPHER_AES_128_CBC +#ifdef MBEDTLS_CIPHER_BLOWFISH_CBC #define _libssh2_cipher_blowfish MBEDTLS_CIPHER_BLOWFISH_CBC +#endif +#ifdef MBEDTLS_CIPHER_ARC4_128 #define _libssh2_cipher_arcfour MBEDTLS_CIPHER_ARC4_128 -#define _libssh2_cipher_cast5 MBEDTLS_CIPHER_NULL +#endif #define _libssh2_cipher_3des MBEDTLS_CIPHER_DES_EDE3_CBC +#define _libssh2_cipher_chacha20 MBEDTLS_CIPHER_CHACHA20_POLY1305 /*******************************************************************/ @@ -363,11 +393,11 @@ typedef enum { */ #define _libssh2_cipher_init(ctx, type, iv, secret, encrypt) \ - _libssh2_mbedtls_cipher_init(ctx, type, iv, secret, encrypt) -#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen) \ - _libssh2_mbedtls_cipher_crypt(ctx, type, encrypt, block, blocklen) + _libssh2_mbedtls_cipher_init(ctx, type, iv, secret, encrypt) +#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen, fl) \ + _libssh2_mbedtls_cipher_crypt(ctx, type, encrypt, block, blocklen, fl) #define _libssh2_cipher_dtor(ctx) \ - _libssh2_mbedtls_cipher_dtor(ctx) + _libssh2_mbedtls_cipher_dtor(ctx) /*******************************************************************/ @@ -382,21 +412,21 @@ typedef enum { #define _libssh2_bn mbedtls_mpi #define _libssh2_bn_init() \ - _libssh2_mbedtls_bignum_init() + _libssh2_mbedtls_bignum_init() #define _libssh2_bn_init_from_bin() \ - _libssh2_mbedtls_bignum_init() + _libssh2_mbedtls_bignum_init() #define _libssh2_bn_set_word(bn, word) \ - mbedtls_mpi_lset(bn, word) + mbedtls_mpi_lset(bn, word) #define _libssh2_bn_from_bin(bn, len, bin) \ - mbedtls_mpi_read_binary(bn, bin, len) + mbedtls_mpi_read_binary(bn, bin, len) #define _libssh2_bn_to_bin(bn, bin) \ - mbedtls_mpi_write_binary(bn, bin, mbedtls_mpi_size(bn)) + mbedtls_mpi_write_binary(bn, bin, mbedtls_mpi_size(bn)) #define _libssh2_bn_bytes(bn) \ - mbedtls_mpi_size(bn) + mbedtls_mpi_size(bn) #define _libssh2_bn_bits(bn) \ - mbedtls_mpi_bitlen(bn) + mbedtls_mpi_bitlen(bn) #define _libssh2_bn_free(bn) \ - _libssh2_mbedtls_bignum_free(bn) + _libssh2_mbedtls_bignum_free(bn) /*******************************************************************/ @@ -404,12 +434,20 @@ typedef enum { * mbedTLS backend: Diffie-Hellman support. */ +/* Default generate and safe prime sizes for + diffie-hellman-group-exchange-sha1 */ +#define LIBSSH2_DH_GEX_MINGROUP 2048 +#define LIBSSH2_DH_GEX_OPTGROUP 4096 +#define LIBSSH2_DH_GEX_MAXGROUP 8192 + +#define LIBSSH2_DH_MAX_MODULUS_BITS 16384 + #define _libssh2_dh_ctx mbedtls_mpi * #define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) #define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order) + _libssh2_dh_key_pair(dhctx, public, g, p, group_order) #define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) + _libssh2_dh_secret(dhctx, secret, f, p) #define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) @@ -425,32 +463,20 @@ void _libssh2_mbedtls_free(void); int -_libssh2_mbedtls_random(unsigned char *buf, int len); +_libssh2_mbedtls_random(unsigned char *buf, size_t len); -int -_libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt); -int -_libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen); void _libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx); int _libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, - mbedtls_md_type_t mdtype, - const unsigned char *key, unsigned long keylen); + mbedtls_md_type_t mdtype, + const unsigned char *key, size_t keylen); int _libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash); int -_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, +_libssh2_mbedtls_hash(const unsigned char *data, size_t datalen, mbedtls_md_type_t mdtype, unsigned char *hash); _libssh2_bn * @@ -459,110 +485,10 @@ _libssh2_mbedtls_bignum_init(void); void _libssh2_mbedtls_bignum_free(_libssh2_bn *bn); -int -_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen); - -int -_libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); - -int -_libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len); void _libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *rsa); -int -_libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); -int -_libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase); #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 @@ -572,15 +498,17 @@ void _libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx); #endif /* LIBSSH2_ECDSA */ +extern void +_libssh2_init_aes_ctr(void); extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx); extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order); + _libssh2_bn *g, _libssh2_bn *p, int group_order); extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p); + _libssh2_bn *f, _libssh2_bn *p); extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); -#endif /* __LIBSSH2_MBEDTLS_H */ +#endif /* LIBSSH2_MBEDTLS_H */ diff --git a/uppsrc/Core/SSH/libssh2/misc.c b/uppsrc/Core/SSH/libssh2/misc.c index 594b2d1f7..6c28327c2 100644 --- a/uppsrc/Core/SSH/libssh2/misc.c +++ b/uppsrc/Core/SSH/libssh2/misc.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2009-2019 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,43 +35,65 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include "misc.h" -#include "blf.h" - -#ifdef HAVE_STDLIB_H -#include -#endif #ifdef HAVE_UNISTD_H #include #endif -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#if defined(HAVE_DECL_SECUREZEROMEMORY) && HAVE_DECL_SECUREZEROMEMORY -#ifdef HAVE_WINDOWS_H -#include -#endif -#endif - -#include #include +#include + +#ifdef _WIN32 +/* Force parameter type. */ +#define recv(s, b, l, f) recv((s), (b), (int)(l), (f)) +#define send(s, b, l, f) send((s), (b), (int)(l), (f)) +#endif + +/* snprintf not in Visual Studio CRT and _snprintf dangerously incompatible. + We provide a safe wrapper if snprintf not found */ +#ifdef LIBSSH2_SNPRINTF +#include + +/* Want safe, 'n += snprintf(b + n ...)' like function. If cp_max_len is 1 +* then assume cp is pointing to a null char and do nothing. Returns number +* number of chars placed in cp excluding the trailing null char. So for +* cp_max_len > 0 the return value is always < cp_max_len; for cp_max_len +* <= 0 the return value is 0 (and no chars are written to cp). */ +int _libssh2_snprintf(char *cp, size_t cp_max_len, const char *fmt, ...) +{ + va_list args; + int n; + + if(cp_max_len < 2) + return 0; + va_start(args, fmt); + n = vsnprintf(cp, cp_max_len, fmt, args); + va_end(args); + return (n < (int)cp_max_len) ? n : (int)(cp_max_len - 1); +} +#endif int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, const char *errmsg, int errflags) { + if(!session) { + if(errmsg) + fprintf(stderr, "Session is NULL, error: %s\n", errmsg); + return errcode; + } + if(session->err_flags & LIBSSH2_ERR_FLAG_DUP) LIBSSH2_FREE(session, (char *)session->err_msg); session->err_code = errcode; session->err_flags = 0; - if((errmsg != NULL) && ((errflags & LIBSSH2_ERR_FLAG_DUP) != 0)) { + if(errmsg && ((errflags & LIBSSH2_ERR_FLAG_DUP) != 0)) { size_t len = strlen(errmsg); char *copy = LIBSSH2_ALLOC(session, len + 1); if(copy) { @@ -91,8 +113,8 @@ int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, /* if this is EAGAIN and we're in non-blocking mode, don't generate a debug output for this */ return errcode; - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code, - session->err_msg); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code, + session->err_msg)); #endif return errcode; @@ -103,8 +125,8 @@ int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char *errmsg) return _libssh2_error_flags(session, errcode, errmsg, 0); } -#ifdef WIN32 -static int wsa2errno(void) +#ifdef _WIN32 +int _libssh2_wsa2errno(void) { switch(WSAGetLastError()) { case WSAEWOULDBLOCK: @@ -135,26 +157,32 @@ _libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, { ssize_t rc; - (void) abstract; + (void)abstract; rc = recv(sock, buffer, length, flags); -#ifdef WIN32 - if(rc < 0) - return -wsa2errno(); -#else if(rc < 0) { + int err; +#ifdef _WIN32 + err = _libssh2_wsa2errno(); +#else + err = errno; +#endif + /* Profiling tools that use SIGPROF can cause EINTR responses. + recv() does not modify its arguments when it returns EINTR, + but there may be data waiting, so the caller should try again */ + if(err == EINTR) + return -EAGAIN; /* Sometimes the first recv() function call sets errno to ENOENT on Solaris and HP-UX */ - if(errno == ENOENT) + if(err == ENOENT) return -EAGAIN; #ifdef EWOULDBLOCK /* For VMS and other special unixes */ - else if(errno == EWOULDBLOCK) - return -EAGAIN; + else if(err == EWOULDBLOCK) + return -EAGAIN; #endif else - return -errno; + return -err; } -#endif return rc; } @@ -168,33 +196,39 @@ _libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length, { ssize_t rc; - (void) abstract; + (void)abstract; rc = send(sock, buffer, length, flags); -#ifdef WIN32 - if(rc < 0) - return -wsa2errno(); -#else if(rc < 0) { + int err; +#ifdef _WIN32 + err = _libssh2_wsa2errno(); +#else + err = errno; +#endif + /* Profiling tools that use SIGPROF can cause EINTR responses. + send() is defined as not yet sending any data when it returns EINTR, + so the caller should try again */ + if(err == EINTR) + return -EAGAIN; #ifdef EWOULDBLOCK /* For VMS and other special unixes */ - if(errno == EWOULDBLOCK) - return -EAGAIN; + if(err == EWOULDBLOCK) + return -EAGAIN; #endif - return -errno; + return -err; } -#endif return rc; } /* libssh2_ntohu32 */ -unsigned int +uint32_t _libssh2_ntohu32(const unsigned char *buf) { - return (((unsigned int)buf[0] << 24) - | ((unsigned int)buf[1] << 16) - | ((unsigned int)buf[2] << 8) - | ((unsigned int)buf[3])); + return ((uint32_t)buf[0] << 24) + | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[2] << 8) + | ((uint32_t)buf[3]); } @@ -203,14 +237,14 @@ _libssh2_ntohu32(const unsigned char *buf) libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf) { - unsigned long msl, lsl; - - msl = ((libssh2_uint64_t)buf[0] << 24) | ((libssh2_uint64_t)buf[1] << 16) - | ((libssh2_uint64_t)buf[2] << 8) | (libssh2_uint64_t)buf[3]; - lsl = ((libssh2_uint64_t)buf[4] << 24) | ((libssh2_uint64_t)buf[5] << 16) - | ((libssh2_uint64_t)buf[6] << 8) | (libssh2_uint64_t)buf[7]; - - return ((libssh2_uint64_t)msl <<32) | lsl; + return ((libssh2_uint64_t)buf[0] << 56) + | ((libssh2_uint64_t)buf[1] << 48) + | ((libssh2_uint64_t)buf[2] << 40) + | ((libssh2_uint64_t)buf[3] << 32) + | ((libssh2_uint64_t)buf[4] << 24) + | ((libssh2_uint64_t)buf[5] << 16) + | ((libssh2_uint64_t)buf[6] << 8) + | ((libssh2_uint64_t)buf[7]); } /* _libssh2_htonu32 @@ -218,7 +252,7 @@ _libssh2_ntohu64(const unsigned char *buf) void _libssh2_htonu32(unsigned char *buf, uint32_t value) { - buf[0] = (value >> 24) & 0xFF; + buf[0] = (unsigned char)((value >> 24) & 0xFF); buf[1] = (value >> 16) & 0xFF; buf[2] = (value >> 8) & 0xFF; buf[3] = value & 0xFF; @@ -232,15 +266,70 @@ void _libssh2_store_u32(unsigned char **buf, uint32_t value) *buf += sizeof(uint32_t); } +/* _libssh2_store_u64 + */ +void _libssh2_store_u64(unsigned char **buf, libssh2_uint64_t value) +{ + unsigned char *ptr = *buf; + + ptr[0] = (unsigned char)((value >> 56) & 0xFF); + ptr[1] = (unsigned char)((value >> 48) & 0xFF); + ptr[2] = (unsigned char)((value >> 40) & 0xFF); + ptr[3] = (unsigned char)((value >> 32) & 0xFF); + ptr[4] = (unsigned char)((value >> 24) & 0xFF); + ptr[5] = (unsigned char)((value >> 16) & 0xFF); + ptr[6] = (unsigned char)((value >> 8) & 0xFF); + ptr[7] = (unsigned char)(value & 0xFF); + + *buf += sizeof(libssh2_uint64_t); +} + /* _libssh2_store_str */ -void _libssh2_store_str(unsigned char **buf, const char *str, size_t len) +int _libssh2_store_str(unsigned char **buf, const char *str, size_t len) { - _libssh2_store_u32(buf, (uint32_t)len); - if(len) { - memcpy(*buf, str, len); - *buf += len; + uint32_t len_stored = (uint32_t)len; + + _libssh2_store_u32(buf, len_stored); + if(len_stored) { + memcpy(*buf, str, len_stored); + *buf += len_stored; } + + assert(len_stored == len); + return len_stored == len; +} + +/* _libssh2_store_bignum2_bytes + */ +int _libssh2_store_bignum2_bytes(unsigned char **buf, + const unsigned char *bytes, + size_t len) +{ + uint32_t len_stored; + uint32_t extraByte; + const unsigned char *p; + + for(p = bytes; len > 0 && *p == 0; --len, ++p) {} + + extraByte = (len > 0 && (p[0] & 0x80) != 0); + len_stored = (uint32_t)len; + if(extraByte && len_stored == UINT32_MAX) + len_stored--; + _libssh2_store_u32(buf, len_stored + extraByte); + + if(extraByte) { + *buf[0] = 0; + *buf += 1; + } + + if(len_stored) { + memcpy(*buf, p, len_stored); + *buf += len_stored; + } + + assert(len_stored == len); + return len_stored == len; } /* Base64 Conversion */ @@ -266,26 +355,46 @@ static const short base64_reverse_table[256] = { /* libssh2_base64_decode * - * Decode a base64 chunk and store it into a newly alloc'd buffer + * Legacy public function. DEPRECATED. */ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, unsigned int *datalen, const char *src, unsigned int src_len) { - unsigned char *s, *d; - short v; - int i = 0, len = 0; + int rc; + size_t dlen; - *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1); + rc = _libssh2_base64_decode(session, data, &dlen, src, src_len); + + if(datalen) + *datalen = (unsigned int)dlen; + + return rc; +} + +/* _libssh2_base64_decode + * + * Decode a base64 chunk and store it into a newly alloc'd buffer + */ +int _libssh2_base64_decode(LIBSSH2_SESSION *session, + char **data, size_t *datalen, + const char *src, size_t src_len) +{ + unsigned char *d; + const char *s; + short v; + ssize_t i = 0, len = 0; + + *data = LIBSSH2_ALLOC(session, ((src_len / 4) * 3) + 1); d = (unsigned char *) *data; if(!d) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for base64 decoding"); } - for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) { - v = base64_reverse_table[*s]; + for(s = src; s < (src + src_len); s++) { + v = base64_reverse_table[(unsigned char)*s]; if(v < 0) continue; switch(i % 4) { @@ -293,15 +402,15 @@ libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, d[len] = (unsigned char)(v << 2); break; case 1: - d[len++] |= v >> 4; + d[len++] |= (unsigned char)(v >> 4); d[len] = (unsigned char)(v << 4); break; case 2: - d[len++] |= v >> 2; + d[len++] |= (unsigned char)(v >> 2); d[len] = (unsigned char)(v << 6); break; case 3: - d[len++] |= v; + d[len++] |= (unsigned char)v; break; } i++; @@ -320,10 +429,10 @@ libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, /* ---- Base64 Encoding/Decoding Table --- */ static const char table64[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* - * _libssh2_base64_encode() + * _libssh2_base64_encode * * Returns the length of the newly created base64 string. The third argument * is a pointer to an allocated area holding the base64 data. If something @@ -344,11 +453,11 @@ size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, *outptr = NULL; /* set to NULL in case of failure before we reach the end */ - if(0 == insize) + if(insize == 0) insize = strlen(indata); base64data = output = LIBSSH2_ALLOC(session, insize * 4 / 3 + 4); - if(NULL == output) + if(!output) return 0; while(insize > 0) { @@ -372,22 +481,22 @@ size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, switch(inputparts) { case 1: /* only one byte read */ - snprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); + output[0] = table64[obuf[0]]; + output[1] = table64[obuf[1]]; + output[2] = '='; + output[3] = '='; break; case 2: /* two bytes read */ - snprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); + output[0] = table64[obuf[0]]; + output[1] = table64[obuf[1]]; + output[2] = table64[obuf[2]]; + output[3] = '='; break; default: - snprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]]); + output[0] = table64[obuf[0]]; + output[1] = table64[obuf[1]]; + output[2] = table64[obuf[2]]; + output[3] = table64[obuf[3]]; break; } output += 4; @@ -425,13 +534,14 @@ libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context, } void -_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) +_libssh2_debug_low(LIBSSH2_SESSION * session, int context, const char *format, + ...) { char buffer[1536]; int len, msglen, buflen = sizeof(buffer); va_list vargs; struct timeval now; - static int firstsec; + static long firstsec; static const char *const contexts[] = { "Unknown", "Transport", @@ -461,7 +571,7 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) } } - _libssh2_gettimeofday(&now, NULL); + gettimeofday(&now, NULL); if(!firstsec) { firstsec = now.tv_sec; } @@ -492,8 +602,8 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION * session, int bitmask) { - (void) session; - (void) bitmask; + (void)session; + (void)bitmask; return 0; } @@ -501,9 +611,9 @@ LIBSSH2_API int libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context, libssh2_trace_handler_func callback) { - (void) session; - (void) handler_context; - (void) callback; + (void)session; + (void)handler_context; + (void)callback; return 0; } #endif @@ -600,10 +710,10 @@ void _libssh2_list_insert(struct list_node *after, /* insert before this */ #endif -/* this define is defined in misc.h for the correct platforms */ -#ifdef LIBSSH2_GETTIMEOFDAY_WIN32 +/* Defined in libssh2_priv.h for the correct platforms */ +#ifdef LIBSSH2_GETTIMEOFDAY /* - * gettimeofday + * _libssh2_gettimeofday * Implementation according to: * The Open Group Base Specifications Issue 6 * IEEE Std 1003.1, 2004 Edition @@ -624,27 +734,31 @@ void _libssh2_list_insert(struct list_node *after, /* insert before this */ * Danny Smith */ -/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ -#define _W32_FT_OFFSET (116444736000000000) - -int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp) +int _libssh2_gettimeofday(struct timeval *tp, void *tzp) { - union { - unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; (void)tzp; if(tp) { +#ifdef _WIN32 + /* Offset between 1601-01-01 and 1970-01-01 in 100 nanosec units */ + #define _WIN32_FT_OFFSET (116444736000000000) + + union { + libssh2_uint64_t ns100; /* time since 1 Jan 1601 in 100ns units */ + FILETIME ft; + } _now; GetSystemTimeAsFileTime(&_now.ft); tp->tv_usec = (long)((_now.ns100 / 10) % 1000000); - tp->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000); + tp->tv_sec = (long)((_now.ns100 - _WIN32_FT_OFFSET) / 10000000); +#else + /* Platforms without a native implementation or local replacement */ + tp->tv_usec = 0; + tp->tv_sec = 0; +#endif } /* Always return 0 as per Open Group Base Specifications Issue 6. Do not set errno on error. */ return 0; } - - #endif void *_libssh2_calloc(LIBSSH2_SESSION* session, size_t size) @@ -687,34 +801,23 @@ void _libssh2_aes_ctr_increment(unsigned char *ctr, } } -#ifdef WIN32 -static void * (__cdecl * const volatile memset_libssh)(void *, int, size_t) = - memset; -#else +#ifdef LIBSSH2_MEMZERO static void * (* const volatile memset_libssh)(void *, int, size_t) = memset; -#endif -void _libssh2_explicit_zero(void *buf, size_t size) +void _libssh2_memzero(void *buf, size_t size) { -#if defined(HAVE_DECL_SECUREZEROMEMORY) && HAVE_DECL_SECUREZEROMEMORY - SecureZeroMemory(buf, size); - (void)memset_libssh; /* Silence unused variable warning */ -#elif defined(HAVE_MEMSET_S) - (void)memset_s(buf, size, 0, size); - (void)memset_libssh; /* Silence unused variable warning */ -#else memset_libssh(buf, 0, size); -#endif } +#endif /* String buffer */ -struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session) +struct string_buf *_libssh2_string_buf_new(LIBSSH2_SESSION *session) { struct string_buf *ret; ret = _libssh2_calloc(session, sizeof(*ret)); - if(ret == NULL) + if(!ret) return NULL; return ret; @@ -722,16 +825,39 @@ struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session) void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf) { - if(buf == NULL) + if(!buf) return; - if(buf->data != NULL) + if(buf->data) LIBSSH2_FREE(session, buf->data); LIBSSH2_FREE(session, buf); buf = NULL; } +int _libssh2_get_byte(struct string_buf *buf, unsigned char *out) +{ + if(!_libssh2_check_length(buf, 1)) { + return -1; + } + + *out = buf->dataptr[0]; + buf->dataptr += 1; + return 0; +} + +int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out) +{ + if(!_libssh2_check_length(buf, 1)) { + return -1; + } + + + *out = buf->dataptr[0] == 0 ? 0 : 1; + buf->dataptr += 1; + return 0; +} + int _libssh2_get_u32(struct string_buf *buf, uint32_t *out) { if(!_libssh2_check_length(buf, 4)) { @@ -769,7 +895,7 @@ int _libssh2_get_string(struct string_buf *buf, unsigned char **outbuf, size_t *outlen) { uint32_t data_len; - if(_libssh2_get_u32(buf, &data_len) != 0) { + if(!buf || _libssh2_get_u32(buf, &data_len) != 0) { return -1; } if(!_libssh2_check_length(buf, data_len)) { @@ -794,12 +920,17 @@ int _libssh2_copy_string(LIBSSH2_SESSION *session, struct string_buf *buf, return -1; } - *outbuf = LIBSSH2_ALLOC(session, str_len); - if(*outbuf) { - memcpy(*outbuf, str, str_len); + if(str_len) { + *outbuf = LIBSSH2_ALLOC(session, str_len); + if(*outbuf) { + memcpy(*outbuf, str, str_len); + } + else { + return -1; + } } else { - return -1; + *outbuf = NULL; } if(outlen) @@ -848,25 +979,11 @@ int _libssh2_check_length(struct string_buf *buf, size_t len) { unsigned char *endp = &buf->data[buf->len]; size_t left = endp - buf->dataptr; - return ((len <= left) && (left <= buf->len)); + return (len <= left) && (left <= buf->len); } -/* Wrappers */ - -int _libssh2_bcrypt_pbkdf(const char *pass, - size_t passlen, - const uint8_t *salt, - size_t saltlen, - uint8_t *key, - size_t keylen, - unsigned int rounds) +int _libssh2_eob(struct string_buf *buf) { - /* defined in bcrypt_pbkdf.c */ - return bcrypt_pbkdf(pass, - passlen, - salt, - saltlen, - key, - keylen, - rounds); + unsigned char *endp = &buf->data[buf->len]; + return buf->dataptr >= endp; } diff --git a/uppsrc/Core/SSH/libssh2/misc.h b/uppsrc/Core/SSH/libssh2/misc.h index 5481e666c..eac2e064b 100644 --- a/uppsrc/Core/SSH/libssh2/misc.h +++ b/uppsrc/Core/SSH/libssh2/misc.h @@ -1,7 +1,6 @@ -#ifndef __LIBSSH2_MISC_H -#define __LIBSSH2_MISC_H -/* Copyright (c) 2009-2019 by Daniel Stenberg - * +#ifndef LIBSSH2_MISC_H +#define LIBSSH2_MISC_H +/* Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,8 +35,29 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ +#ifdef LIBSSH2_NO_CLEAR_MEMORY +#define _libssh2_explicit_zero(buf, size) do { \ + (void)(buf); \ + (void)(size); \ + } while(0) +#elif defined(_WIN32) +#define _libssh2_explicit_zero(buf, size) SecureZeroMemory(buf, size) +#elif defined(HAVE_EXPLICIT_BZERO) +#define _libssh2_explicit_zero(buf, size) explicit_bzero(buf, size) +#elif defined(HAVE_EXPLICIT_MEMSET) +#define _libssh2_explicit_zero(buf, size) (void)explicit_memset(buf, 0, size) +#elif defined(HAVE_MEMSET_S) +#define _libssh2_explicit_zero(buf, size) (void)memset_s(buf, size, 0, size) +#else +#define LIBSSH2_MEMZERO +void _libssh2_memzero(void *buf, size_t size); +#define _libssh2_explicit_zero(buf, size) _libssh2_memzero(buf, size) +#endif + struct list_head { struct list_node *last; struct list_node *first; @@ -59,6 +79,11 @@ int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, const char *errmsg, int errflags); int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char *errmsg); +#ifdef _WIN32 +/* Convert Win32 WSAGetLastError to errno equivalent */ +int _libssh2_wsa2errno(void); +#endif + void _libssh2_list_init(struct list_head *head); /* add a node last in the list */ @@ -77,20 +102,28 @@ void *_libssh2_list_prev(struct list_node *node); /* remove this node from the list */ void _libssh2_list_remove(struct list_node *entry); +int _libssh2_base64_decode(LIBSSH2_SESSION *session, + char **data, size_t *datalen, + const char *src, size_t src_len); size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, const char *inp, size_t insize, char **outptr); -unsigned int _libssh2_ntohu32(const unsigned char *buf); +uint32_t _libssh2_ntohu32(const unsigned char *buf); libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf); void _libssh2_htonu32(unsigned char *buf, uint32_t val); void _libssh2_store_u32(unsigned char **buf, uint32_t value); -void _libssh2_store_str(unsigned char **buf, const char *str, size_t len); +void _libssh2_store_u64(unsigned char **buf, libssh2_uint64_t value); +int _libssh2_store_str(unsigned char **buf, const char *str, size_t len); +int _libssh2_store_bignum2_bytes(unsigned char **buf, + const unsigned char *bytes, + size_t len); void *_libssh2_calloc(LIBSSH2_SESSION *session, size_t size); -void _libssh2_explicit_zero(void *buf, size_t size); -struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session); +struct string_buf *_libssh2_string_buf_new(LIBSSH2_SESSION *session); void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf); +int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out); +int _libssh2_get_byte(struct string_buf *buf, unsigned char *out); int _libssh2_get_u32(struct string_buf *buf, uint32_t *out); int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out); int _libssh2_match_string(struct string_buf *buf, const char *match); @@ -101,19 +134,7 @@ int _libssh2_copy_string(LIBSSH2_SESSION* session, struct string_buf *buf, int _libssh2_get_bignum_bytes(struct string_buf *buf, unsigned char **outbuf, size_t *outlen); int _libssh2_check_length(struct string_buf *buf, size_t requested_len); - -#if defined(LIBSSH2_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) -/* provide a private one */ -#undef HAVE_GETTIMEOFDAY -int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp); -#define HAVE_LIBSSH2_GETTIMEOFDAY -#define LIBSSH2_GETTIMEOFDAY_WIN32 /* enable the win32 implementation */ -#else -#ifdef HAVE_GETTIMEOFDAY -#define _libssh2_gettimeofday(x,y) gettimeofday(x,y) -#define HAVE_LIBSSH2_GETTIMEOFDAY -#endif -#endif +int _libssh2_eob(struct string_buf *buf); void _libssh2_xor_data(unsigned char *output, const unsigned char *input1, @@ -122,4 +143,4 @@ void _libssh2_xor_data(unsigned char *output, void _libssh2_aes_ctr_increment(unsigned char *ctr, size_t length); -#endif /* _LIBSSH2_MISC_H */ +#endif /* LIBSSH2_MISC_H */ diff --git a/uppsrc/Core/SSH/libssh2/openssl.c b/uppsrc/Core/SSH/libssh2/openssl.c index 7a6810f13..eba05031b 100644 --- a/uppsrc/Core/SSH/libssh2/openssl.c +++ b/uppsrc/Core/SSH/libssh2/openssl.c @@ -1,8 +1,7 @@ -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * Copyright (c) 2004-2006, Sara Golemon - * - * Author: Simon Josefsson +/* Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. + * Copyright (C) Sara Golemon + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -36,26 +35,189 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include "libssh2_priv.h" +#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */ -#ifdef LIBSSH2_OPENSSL /* compile only if we build with openssl */ +#include +#include -#include -#include "misc.h" +int _libssh2_hmac_ctx_init(libssh2_hmac_ctx *ctx) +{ +#ifdef USE_OPENSSL_3 + *ctx = NULL; + return 1; +#elif defined(HAVE_OPAQUE_STRUCTS) + *ctx = HMAC_CTX_new(); + return *ctx ? 1 : 0; +#else + HMAC_CTX_init(ctx); + return 1; +#endif +} -#ifndef EVP_MAX_BLOCK_LENGTH -#define EVP_MAX_BLOCK_LENGTH 32 +#ifdef USE_OPENSSL_3 +static int _libssh2_hmac_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen, + const char *digest_name) +{ + EVP_MAC* mac; + OSSL_PARAM params[3]; + + mac = EVP_MAC_fetch(NULL, OSSL_MAC_NAME_HMAC, NULL); + if(!mac) + return 0; + + *ctx = EVP_MAC_CTX_new(mac); + EVP_MAC_free(mac); + if(!*ctx) + return 0; + + params[0] = OSSL_PARAM_construct_octet_string( + OSSL_MAC_PARAM_KEY, (void *)key, keylen); + params[1] = OSSL_PARAM_construct_utf8_string( + OSSL_MAC_PARAM_DIGEST, (char *)digest_name, 0); + params[2] = OSSL_PARAM_construct_end(); + + return EVP_MAC_init(*ctx, NULL, 0, params); +} #endif -int -read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session, - const char *key_type, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); +#if LIBSSH2_MD5 +int _libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ +#ifdef USE_OPENSSL_3 + return _libssh2_hmac_init(ctx, key, keylen, OSSL_DIGEST_NAME_MD5); +#elif defined(HAVE_OPAQUE_STRUCTS) + return HMAC_Init_ex(*ctx, key, (int)keylen, EVP_md5(), NULL); +#else + return HMAC_Init_ex(ctx, key, (int)keylen, EVP_md5(), NULL); +#endif +} +#endif +#if LIBSSH2_HMAC_RIPEMD +int _libssh2_hmac_ripemd160_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ +#ifdef USE_OPENSSL_3 + return _libssh2_hmac_init(ctx, key, keylen, OSSL_DIGEST_NAME_RIPEMD160); +#elif defined(HAVE_OPAQUE_STRUCTS) + return HMAC_Init_ex(*ctx, key, (int)keylen, EVP_ripemd160(), NULL); +#else + return HMAC_Init_ex(ctx, key, (int)keylen, EVP_ripemd160(), NULL); +#endif +} +#endif + +int _libssh2_hmac_sha1_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ +#ifdef USE_OPENSSL_3 + return _libssh2_hmac_init(ctx, key, keylen, OSSL_DIGEST_NAME_SHA1); +#elif defined(HAVE_OPAQUE_STRUCTS) + return HMAC_Init_ex(*ctx, key, (int)keylen, EVP_sha1(), NULL); +#else + return HMAC_Init_ex(ctx, key, (int)keylen, EVP_sha1(), NULL); +#endif +} + +int _libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ +#ifdef USE_OPENSSL_3 + return _libssh2_hmac_init(ctx, key, keylen, OSSL_DIGEST_NAME_SHA2_256); +#elif defined(HAVE_OPAQUE_STRUCTS) + return HMAC_Init_ex(*ctx, key, (int)keylen, EVP_sha256(), NULL); +#else + return HMAC_Init_ex(ctx, key, (int)keylen, EVP_sha256(), NULL); +#endif +} + +int _libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ +#ifdef USE_OPENSSL_3 + return _libssh2_hmac_init(ctx, key, keylen, OSSL_DIGEST_NAME_SHA2_512); +#elif defined(HAVE_OPAQUE_STRUCTS) + return HMAC_Init_ex(*ctx, key, (int)keylen, EVP_sha512(), NULL); +#else + return HMAC_Init_ex(ctx, key, (int)keylen, EVP_sha512(), NULL); +#endif +} + +int _libssh2_hmac_update(libssh2_hmac_ctx *ctx, + const void *data, size_t datalen) +{ +#ifdef USE_OPENSSL_3 + return EVP_MAC_update(*ctx, data, datalen); +#elif defined(HAVE_OPAQUE_STRUCTS) +/* FIXME: upstream bug as of v5.7.0: datalen is int instead of size_t */ +#if defined(LIBSSH2_WOLFSSL) + return HMAC_Update(*ctx, data, (int)datalen); +#else /* !LIBSSH2_WOLFSSL */ + return HMAC_Update(*ctx, data, datalen); +#endif /* LIBSSH2_WOLFSSL */ +#else + return HMAC_Update(ctx, data, datalen); +#endif +} + +int _libssh2_hmac_final(libssh2_hmac_ctx *ctx, void *data) +{ +#ifdef USE_OPENSSL_3 + return EVP_MAC_final(*ctx, data, NULL, MAX_MACSIZE); +#elif defined(HAVE_OPAQUE_STRUCTS) + return HMAC_Final(*ctx, data, NULL); +#else + return HMAC_Final(ctx, data, NULL); +#endif +} + +void _libssh2_hmac_cleanup(libssh2_hmac_ctx *ctx) +{ +#ifdef USE_OPENSSL_3 + EVP_MAC_CTX_free(*ctx); +#elif defined(HAVE_OPAQUE_STRUCTS) + HMAC_CTX_free(*ctx); +#else + HMAC_cleanup(ctx); +#endif +} + +static int +_libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, + void **key_ctx, + const char *key_type, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privatekeydata, + size_t privatekeydata_len, + unsigned const char *passphrase); + +static int +_libssh2_sk_pub_openssh_keyfilememory(LIBSSH2_SESSION *session, + void **key_ctx, + const char *key_type, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + unsigned const char *passphrase); + +#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA static unsigned char * write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes) { @@ -73,7 +235,33 @@ write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes) return p + bn_bytes; } +#endif +static inline void +_libssh2_swap_bytes(unsigned char *buf, unsigned long len) +{ +#if !defined(WORDS_BIGENDIAN) || !WORDS_BIGENDIAN + unsigned long i, j; + unsigned char temp; + for(i = 0, j = len - 1; i < j; i++, j--) { + temp = buf[i]; + buf[i] = buf[j]; + buf[j] = temp; + } +#endif +} + +int +_libssh2_openssl_random(void *buf, size_t len) +{ + if(len > INT_MAX) { + return -1; + } + + return RAND_bytes(buf, (int)len) == 1 ? 0 : -1; +} + +#if LIBSSH2_RSA int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, const unsigned char *edata, @@ -92,6 +280,78 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, unsigned long e2len, const unsigned char *coeffdata, unsigned long coefflen) { +#ifdef USE_OPENSSL_3 + int ret = 0; + EVP_PKEY_CTX *ctx; + OSSL_PARAM params[4]; + int param_num = 0; + unsigned char *nbuf = NULL; + unsigned char *ebuf = NULL; + unsigned char *dbuf = NULL; + + (void)pdata; + (void)plen; + (void)qdata; + (void)qlen; + (void)e1data; + (void)e1len; + (void)e2data; + (void)e2len; + (void)coeffdata; + (void)coefflen; + + if(ndata && nlen > 0) { + nbuf = OPENSSL_malloc(nlen); + + if(nbuf) { + memcpy(nbuf, ndata, nlen); + _libssh2_swap_bytes(nbuf, nlen); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_N, nbuf, nlen); + } + } + + if(edata && elen > 0) { + ebuf = OPENSSL_malloc(elen); + if(ebuf) { + memcpy(ebuf, edata, elen); + _libssh2_swap_bytes(ebuf, elen); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, ebuf, elen); + } + } + + if(ddata && dlen > 0) { + dbuf = OPENSSL_malloc(dlen); + if(dbuf) { + memcpy(dbuf, ddata, dlen); + _libssh2_swap_bytes(dbuf, dlen); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_D, dbuf, dlen); + } + } + + params[param_num] = OSSL_PARAM_construct_end(); + + *rsa = NULL; + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + + if(EVP_PKEY_fromdata_init(ctx) > 0) { + ret = EVP_PKEY_fromdata(ctx, rsa, EVP_PKEY_KEYPAIR, params); + } + if(nbuf) + OPENSSL_clear_free(nbuf, nlen); + + if(ebuf) + OPENSSL_clear_free(ebuf, elen); + + if(dbuf) + OPENSSL_clear_free(dbuf, dlen); + + EVP_PKEY_CTX_free(ctx); + + return (ret == 1) ? 0 : -1; +#else BIGNUM * e; BIGNUM * n; BIGNUM * d = 0; @@ -102,29 +362,29 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, BIGNUM * iqmp = 0; e = BN_new(); - BN_bin2bn(edata, elen, e); + BN_bin2bn(edata, (int) elen, e); n = BN_new(); - BN_bin2bn(ndata, nlen, n); + BN_bin2bn(ndata, (int) nlen, n); if(ddata) { d = BN_new(); - BN_bin2bn(ddata, dlen, d); + BN_bin2bn(ddata, (int) dlen, d); p = BN_new(); - BN_bin2bn(pdata, plen, p); + BN_bin2bn(pdata, (int) plen, p); q = BN_new(); - BN_bin2bn(qdata, qlen, q); + BN_bin2bn(qdata, (int) qlen, q); dmp1 = BN_new(); - BN_bin2bn(e1data, e1len, dmp1); + BN_bin2bn(e1data, (int) e1len, dmp1); dmq1 = BN_new(); - BN_bin2bn(e2data, e2len, dmq1); + BN_bin2bn(e2data, (int) e2len, dmq1); iqmp = BN_new(); - BN_bin2bn(coeffdata, coefflen, iqmp); + BN_bin2bn(coeffdata, (int) coefflen, iqmp); } *rsa = RSA_new(); @@ -151,24 +411,104 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, (*rsa)->iqmp = iqmp; #endif return 0; + +#endif /* USE_OPENSSL_3 */ } int -_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, +_libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, + size_t hash_len, const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len) + size_t sig_len, + const unsigned char *m, size_t m_len) { - unsigned char hash[SHA_DIGEST_LENGTH]; - int ret; +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = NULL; + const EVP_MD *md = NULL; +#endif - if(_libssh2_sha1(m, m_len, hash)) + int ret; + int nid_type; + unsigned char *hash = malloc(hash_len); + if(!hash) + return -1; + + if(hash_len == SHA_DIGEST_LENGTH) { + nid_type = NID_sha1; + ret = _libssh2_sha1(m, m_len, hash); + } + else if(hash_len == SHA256_DIGEST_LENGTH) { + nid_type = NID_sha256; + ret = _libssh2_sha256(m, m_len, hash); + } + else if(hash_len == SHA512_DIGEST_LENGTH) { + nid_type = NID_sha512; + ret = _libssh2_sha512(m, m_len, hash); + } + else { +/* silence: + warning C4701: potentially uninitialized local variable 'nid_type' used */ +#if defined(_MSC_VER) + nid_type = 0; +#endif + ret = -1; /* unsupported digest */ + } + + if(ret) { + free(hash); return -1; /* failure */ - ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, - (unsigned char *) sig, sig_len, rsactx); + } + +#ifdef USE_OPENSSL_3 + ctx = EVP_PKEY_CTX_new(rsactx, NULL); + + if(nid_type == NID_sha1) { + md = EVP_sha1(); + } + else if(nid_type == NID_sha256) { + md = EVP_sha256(); + } + else if(nid_type == NID_sha512) { + md = EVP_sha512(); + } + + if(ctx && md) { + if(EVP_PKEY_verify_init(ctx) > 0 && + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0 && + EVP_PKEY_CTX_set_signature_md(ctx, md) > 0) { + ret = EVP_PKEY_verify(ctx, sig, sig_len, hash, hash_len); + } + } + + if(ctx) { + EVP_PKEY_CTX_free(ctx); + } + +#else + + ret = RSA_verify(nid_type, hash, (unsigned int) hash_len, + (unsigned char *) sig, + (unsigned int) sig_len, rsactx); +#endif + + free(hash); + return (ret == 1) ? 0 : -1; } +#if LIBSSH2_RSA_SHA1 +int +_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, size_t m_len) +{ + return _libssh2_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH, sig, sig_len, m, + m_len); +} +#endif +#endif + #if LIBSSH2_DSA int _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, @@ -182,6 +522,97 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, unsigned long y_len, const unsigned char *x, unsigned long x_len) { +#ifdef USE_OPENSSL_3 + int ret = 0; + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM params[6]; + int param_num = 0; + unsigned char *p_buf = NULL; + unsigned char *q_buf = NULL; + unsigned char *g_buf = NULL; + unsigned char *y_buf = NULL; + unsigned char *x_buf = NULL; + + if(p && p_len > 0) { + p_buf = OPENSSL_malloc(p_len); + + if(p_buf) { + memcpy(p_buf, p, p_len); + _libssh2_swap_bytes(p_buf, p_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_FFC_P, p_buf, p_len); + } + } + + if(q && q_len > 0) { + q_buf = OPENSSL_malloc(q_len); + + if(q_buf) { + memcpy(q_buf, q, q_len); + _libssh2_swap_bytes(q_buf, q_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_FFC_Q, q_buf, q_len); + } + } + + if(g && g_len > 0) { + g_buf = OPENSSL_malloc(g_len); + + if(g_buf) { + memcpy(g_buf, g, g_len); + _libssh2_swap_bytes(g_buf, g_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_FFC_G, g_buf, g_len); + } + } + + if(y && y_len > 0) { + y_buf = OPENSSL_malloc(y_len); + + if(y_buf) { + memcpy(y_buf, y, y_len); + _libssh2_swap_bytes(y_buf, y_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PUB_KEY, y_buf, y_len); + } + } + + if(x && x_len > 0) { + x_buf = OPENSSL_malloc(x_len); + + if(x_buf) { + memcpy(x_buf, x, x_len); + _libssh2_swap_bytes(x_buf, x_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PRIV_KEY, + x_buf, x_len); + } + } + + params[param_num] = OSSL_PARAM_construct_end(); + + *dsactx = NULL; + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); + + if(EVP_PKEY_fromdata_init(ctx) > 0) { + ret = EVP_PKEY_fromdata(ctx, dsactx, EVP_PKEY_KEYPAIR, params); + } + + if(p_buf) + OPENSSL_clear_free(p_buf, p_len); + if(q_buf) + OPENSSL_clear_free(q_buf, q_len); + if(g_buf) + OPENSSL_clear_free(g_buf, g_len); + if(x_buf) + OPENSSL_clear_free(x_buf, x_len); + if(y_buf) + OPENSSL_clear_free(y_buf, y_len); + + return (ret == 1) ? 0 : -1; + +#else + BIGNUM * p_bn; BIGNUM * q_bn; BIGNUM * g_bn; @@ -189,20 +620,20 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, BIGNUM * priv_key = NULL; p_bn = BN_new(); - BN_bin2bn(p, p_len, p_bn); + BN_bin2bn(p, (int) p_len, p_bn); q_bn = BN_new(); - BN_bin2bn(q, q_len, q_bn); + BN_bin2bn(q, (int) q_len, q_bn); g_bn = BN_new(); - BN_bin2bn(g, g_len, g_bn); + BN_bin2bn(g, (int) g_len, g_bn); pub_key = BN_new(); - BN_bin2bn(y, y_len, pub_key); + BN_bin2bn(y, (int) y_len, pub_key); if(x_len) { priv_key = BN_new(); - BN_bin2bn(x, x_len, priv_key); + BN_bin2bn(x, (int) x_len, priv_key); } *dsactx = DSA_new(); @@ -222,13 +653,21 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, (*dsactx)->priv_key = priv_key; #endif return 0; + +#endif /* USE_OPENSSL_3 */ } int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, const unsigned char *sig, - const unsigned char *m, unsigned long m_len) + const unsigned char *m, size_t m_len) { +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = NULL; + unsigned char *der = NULL; + int der_len = 0; +#endif + unsigned char hash[SHA_DIGEST_LENGTH]; DSA_SIG * dsasig; BIGNUM * r; @@ -247,9 +686,30 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, dsasig->r = r; dsasig->s = s; #endif + +#ifdef USE_OPENSSL_3 + ctx = EVP_PKEY_CTX_new(dsactx, NULL); + der_len = i2d_DSA_SIG(dsasig, &der); + + if(ctx && !_libssh2_sha1(m, m_len, hash)) { + /* _libssh2_sha1() succeeded */ + if(EVP_PKEY_verify_init(ctx) > 0) { + ret = EVP_PKEY_verify(ctx, der, der_len, hash, SHA_DIGEST_LENGTH); + } + } + + if(ctx) { + EVP_PKEY_CTX_free(ctx); + } + + if(der) { + OPENSSL_clear_free(der, der_len); + } +#else if(!_libssh2_sha1(m, m_len, hash)) /* _libssh2_sha1() succeeded */ ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, dsasig, dsactx); +#endif DSA_SIG_free(dsasig); @@ -268,8 +728,25 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, libssh2_curve_type _libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx) { +#ifdef USE_OPENSSL_3 + int bits = 0; + EVP_PKEY_get_int_param(ec_ctx, OSSL_PKEY_PARAM_BITS, &bits); + + if(bits == 256) { + return LIBSSH2_EC_CURVE_NISTP256; + } + else if(bits == 384) { + return LIBSSH2_EC_CURVE_NISTP384; + } + else if(bits == 521) { + return LIBSSH2_EC_CURVE_NISTP521; + } + + return LIBSSH2_EC_CURVE_NISTP256; +#else const EC_GROUP *group = EC_KEY_get0_group(ec_ctx); return EC_GROUP_get_curve_name(group); +#endif } /* _libssh2_ecdsa_curve_type_from_name @@ -282,10 +759,9 @@ int _libssh2_ecdsa_curve_type_from_name(const char *name, libssh2_curve_type *out_type) { - int ret = 0; libssh2_curve_type type; - if(name == NULL || strlen(name) != 19) + if(!name || strlen(name) != 19) return -1; if(strcmp(name, "ecdsa-sha2-nistp256") == 0) @@ -295,14 +771,14 @@ _libssh2_ecdsa_curve_type_from_name(const char *name, else if(strcmp(name, "ecdsa-sha2-nistp521") == 0) type = LIBSSH2_EC_CURVE_NISTP521; else { - ret = -1; + return -1; } - if(ret == 0 && out_type) { + if(out_type) { *out_type = type; } - return ret; + return 0; } /* _libssh2_ecdsa_curve_name_with_octal_new @@ -316,63 +792,161 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ec_ctx, const unsigned char *k, size_t k_len, libssh2_curve_type curve) { - int ret = 0; - const EC_GROUP *ec_group = NULL; + +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + const char *n = EC_curve_nid2nist(curve); + char *group_name = NULL; + unsigned char *data = NULL; + + if(!ctx) + return -1; + + if(n) { + group_name = OPENSSL_zalloc(strlen(n) + 1); + } + + if(k_len > 0) { + data = OPENSSL_malloc(k_len); + } + + if(group_name && data) { + OSSL_PARAM params[3] = { 0 }; + + memcpy(group_name, n, strlen(n)); + memcpy(data, k, k_len); + + params[0] = + OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 0); + + params[1] = + OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + data, k_len); + + params[2] = OSSL_PARAM_construct_end(); + + if(EVP_PKEY_fromdata_init(ctx) > 0) + ret = EVP_PKEY_fromdata(ctx, ec_ctx, EVP_PKEY_PUBLIC_KEY, + params); + else + ret = -1; + } + else + ret = -1; + + if(group_name) + OPENSSL_clear_free(group_name, strlen(n)); + + if(data) + OPENSSL_clear_free(data, k_len); + + EVP_PKEY_CTX_free(ctx); +#else EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve); - EC_POINT *point = NULL; if(ec_key) { + const EC_GROUP *ec_group = NULL; + EC_POINT *point = NULL; + ec_group = EC_KEY_get0_group(ec_key); point = EC_POINT_new(ec_group); - ret = EC_POINT_oct2point(ec_group, point, k, k_len, NULL); - ret = EC_KEY_set_public_key(ec_key, point); - if(point != NULL) + if(point) { + ret = EC_POINT_oct2point(ec_group, point, k, k_len, NULL); + if(ret == 1) + ret = EC_KEY_set_public_key(ec_key, point); + EC_POINT_free(point); + } + else + ret = -1; - if(ec_ctx != NULL) + if(ret == 1 && ec_ctx) *ec_ctx = ec_key; + else { + EC_KEY_free(ec_key); + ret = -1; + } } + else + ret = -1; +#endif return (ret == 1) ? 0 : -1; } -#define LIBSSH2_ECDSA_VERIFY(digest_type) \ -{ \ - unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ - libssh2_sha##digest_type(m, m_len, hash); \ - ret = ECDSA_do_verify(hash, SHA##digest_type##_DIGEST_LENGTH, \ - ecdsa_sig, ec_key); \ - \ -} +#ifdef USE_OPENSSL_3 +#define LIBSSH2_ECDSA_VERIFY(digest_type) \ + do { \ + unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ + if(libssh2_sha##digest_type(m, m_len, hash) == 0) { \ + ret = EVP_PKEY_verify_init(ctx); \ + if(ret > 0) { \ + ret = EVP_PKEY_verify(ctx, der, der_len, hash, \ + SHA##digest_type##_DIGEST_LENGTH); \ + } \ + } \ + } while(0) +#else +#define LIBSSH2_ECDSA_VERIFY(digest_type) \ + do { \ + unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ + if(libssh2_sha##digest_type(m, m_len, hash) == 0) { \ + ret = ECDSA_do_verify(hash, \ + SHA##digest_type##_DIGEST_LENGTH, \ + ecdsa_sig, ec_key); \ + } \ + } while(0) +#endif 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) +_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ecdsa_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 ret = 0; - EC_KEY *ec_key = (EC_KEY*)ctx; - libssh2_curve_type type = _libssh2_ecdsa_get_curve_type(ec_key); + libssh2_curve_type type = _libssh2_ecdsa_get_curve_type(ecdsa_ctx); + +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = NULL; + unsigned char *der = NULL; + int der_len = 0; +#else + EC_KEY *ec_key = (EC_KEY*)ecdsa_ctx; +#endif #ifdef HAVE_OPAQUE_STRUCTS ECDSA_SIG *ecdsa_sig = ECDSA_SIG_new(); BIGNUM *pr = BN_new(); BIGNUM *ps = BN_new(); - BN_bin2bn(r, r_len, pr); - BN_bin2bn(s, s_len, ps); + BN_bin2bn(r, (int) r_len, pr); + BN_bin2bn(s, (int) s_len, ps); ECDSA_SIG_set0(ecdsa_sig, pr, ps); - #else ECDSA_SIG ecdsa_sig_; ECDSA_SIG *ecdsa_sig = &ecdsa_sig_; ecdsa_sig_.r = BN_new(); - BN_bin2bn(r, r_len, ecdsa_sig_.r); + BN_bin2bn(r, (int) r_len, ecdsa_sig_.r); ecdsa_sig_.s = BN_new(); - BN_bin2bn(s, s_len, ecdsa_sig_.s); + BN_bin2bn(s, (int) s_len, ecdsa_sig_.s); +#endif + +#ifdef USE_OPENSSL_3 + ctx = EVP_PKEY_CTX_new(ecdsa_ctx, NULL); + if(!ctx) { + ret = -1; + goto cleanup; + } + + der_len = i2d_ECDSA_SIG(ecdsa_sig, &der); + if(der_len <= 0) { + ret = -1; + goto cleanup; + } #endif if(type == LIBSSH2_EC_CURVE_NISTP256) { @@ -385,12 +959,24 @@ _libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx, LIBSSH2_ECDSA_VERIFY(512); } +#ifdef USE_OPENSSL_3 +cleanup: + + if(ctx) + EVP_PKEY_CTX_free(ctx); + + if(der) + OPENSSL_free(der); +#endif + #ifdef HAVE_OPAQUE_STRUCTS if(ecdsa_sig) ECDSA_SIG_free(ecdsa_sig); #else - BN_clear_free(ecdsa_sig_.s); - BN_clear_free(ecdsa_sig_.r); + if(ecdsa_sig_.s) + BN_clear_free(ecdsa_sig_.s); + if(ecdsa_sig_.r) + BN_clear_free(ecdsa_sig_.r); #endif return (ret == 1) ? 0 : -1; @@ -404,262 +990,157 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, unsigned char *iv, unsigned char *secret, int encrypt) { #ifdef HAVE_OPAQUE_STRUCTS +#if LIBSSH2_AES_GCM + const int is_aesgcm = (algo == EVP_aes_128_gcm) || + (algo == EVP_aes_256_gcm); +#endif /* LIBSSH2_AES_GCM */ + int rc; + *h = EVP_CIPHER_CTX_new(); - return !EVP_CipherInit(*h, algo(), secret, iv, encrypt); + rc = !EVP_CipherInit(*h, algo(), secret, iv, encrypt); +#if LIBSSH2_AES_GCM + if(is_aesgcm) { + /* Sets both fixed and invocation_counter parts of IV */ + rc |= !EVP_CIPHER_CTX_ctrl(*h, EVP_CTRL_AEAD_SET_IV_FIXED, -1, iv); + } +#endif /* LIBSSH2_AES_GCM */ + + return rc; #else +# if LIBSSH2_AES_GCM +# error AES-GCM is only supported with opaque structs in use +# endif /* LIBSSH2_AES_GCM */ EVP_CIPHER_CTX_init(h); return !EVP_CipherInit(h, algo(), secret, iv, encrypt); #endif } +#ifndef EVP_MAX_BLOCK_LENGTH +#define EVP_MAX_BLOCK_LENGTH 32 +#endif + int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blocksize) + int encrypt, unsigned char *block, size_t blocksize, + int firstlast) { unsigned char buf[EVP_MAX_BLOCK_LENGTH]; - int ret; - (void) algo; - (void) encrypt; + int ret = 1; + int rc = 1; +#if LIBSSH2_AES_GCM + const int is_aesgcm = (algo == EVP_aes_128_gcm) || + (algo == EVP_aes_256_gcm); + char lastiv[1]; +#else + const int is_aesgcm = 0; +#endif /* LIBSSH2_AES_GCM */ + /* length of AES-GCM Authentication Tag */ + const int authlen = is_aesgcm ? 16 : 0; + /* length of AAD, only on the first block */ + const int aadlen = (is_aesgcm && IS_FIRST(firstlast)) ? 4 : 0; + /* size of AT, if present */ + const int authenticationtag = IS_LAST(firstlast) ? authlen : 0; + /* length to encrypt */ + const int cryptlen = (unsigned int)blocksize - aadlen - authenticationtag; + + (void)algo; + + assert(blocksize <= sizeof(buf)); + assert(cryptlen >= 0); + +#if LIBSSH2_AES_GCM + /* First block */ + if(IS_FIRST(firstlast)) { + /* Increments invocation_counter portion of IV */ + if(is_aesgcm) { + ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_IV_GEN, 1, lastiv); + } + + if(aadlen) { + /* Include the 4 byte packet length as AAD */ + ret = EVP_Cipher(*ctx, NULL, block, aadlen); + } + } + + /* Last portion of block to encrypt/decrypt */ + if(IS_LAST(firstlast)) { + if(is_aesgcm && !encrypt) { + /* set tag on decryption */ + ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_SET_TAG, authlen, + block + blocksize - authlen); + } + } +#else + (void)encrypt; + (void)firstlast; +#endif /* LIBSSH2_AES_GCM */ + + if(cryptlen > 0) { #ifdef HAVE_OPAQUE_STRUCTS - ret = EVP_Cipher(*ctx, buf, block, blocksize); + ret = EVP_Cipher(*ctx, buf + aadlen, block + aadlen, cryptlen); #else - ret = EVP_Cipher(ctx, buf, block, blocksize); + ret = EVP_Cipher(ctx, buf + aadlen, block + aadlen, cryptlen); #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; +#if defined(USE_OPENSSL_3) || defined(LIBSSH2_WOLFSSL) + if(ret != -1) #else - return ret == 1 ? 0 : 1; + if(ret >= 1) #endif + { + rc = 0; + if(IS_LAST(firstlast)) { + /* This is the last block. + encrypt: compute tag, if applicable + decrypt: verify tag, if applicable + in!=NULL is equivalent to EVP_CipherUpdate + in==NULL is equivalent to EVP_CipherFinal */ +#if defined(LIBSSH2_WOLFSSL) && LIBWOLFSSL_VERSION_HEX < 0x05007000 + /* Workaround for wolfSSL bug fixed in v5.7.0: + https://github.com/wolfSSL/wolfssl/pull/7143 */ + unsigned char buf2[EVP_MAX_BLOCK_LENGTH]; + int outb; + ret = EVP_CipherFinal(*ctx, buf2, &outb); +#elif defined(HAVE_OPAQUE_STRUCTS) + ret = EVP_Cipher(*ctx, NULL, NULL, 0); /* final */ +#else + ret = EVP_Cipher(ctx, NULL, NULL, 0); /* final */ +#endif + if(ret < 0) { + ret = 0; + } + else { + ret = 1; +#if LIBSSH2_AES_GCM + if(is_aesgcm && encrypt) { + /* write the Authentication Tag a.k.a. MAC at the end + of the block */ + assert(authenticationtag == authlen); + ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_GET_TAG, + authlen, block + blocksize - authenticationtag); + } +#endif /* LIBSSH2_AES_GCM */ + } + } + /* Copy en/decrypted data back to the caller. + The first aadlen should not be touched because they weren't + encrypted and are unmodified. */ + memcpy(block + aadlen, buf + aadlen, cryptlen); + rc = !ret; + } + + /* TODO: the return code should distinguish between decryption errors and + invalid MACs */ + return rc; } -#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) - -#include -#include - -typedef struct -{ - AES_KEY key; - EVP_CIPHER_CTX *aes_ctx; - 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 */ -{ - /* - * variable "c" is leaked from this scope, but is later freed - * in aes_ctr_cleanup - */ - aes_ctr_ctx *c; - const EVP_CIPHER *aes_cipher; - (void) enc; - - switch(EVP_CIPHER_CTX_key_length(ctx)) { - case 16: - aes_cipher = EVP_aes_128_ecb(); - break; - case 24: - aes_cipher = EVP_aes_192_ecb(); - break; - case 32: - aes_cipher = EVP_aes_256_ecb(); - break; - default: - return 0; - } - - c = malloc(sizeof(*c)); - if(c == NULL) - return 0; - -#ifdef HAVE_OPAQUE_STRUCTS - c->aes_ctx = EVP_CIPHER_CTX_new(); -#else - c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX)); -#endif - if(c->aes_ctx == NULL) { - free(c); - return 0; - } - - if(EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) { -#ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER_CTX_free(c->aes_ctx); -#else - free(c->aes_ctx); -#endif - free(c); - return 0; - } - - EVP_CIPHER_CTX_set_padding(c->aes_ctx, 0); - - memcpy(c->ctr, iv, AES_BLOCK_SIZE); - - EVP_CIPHER_CTX_set_app_data(ctx, c); - - return 1; -} - -static int -aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, - size_t inl) /* encrypt/decrypt data */ -{ - aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); - unsigned char b1[AES_BLOCK_SIZE]; - int outlen = 0; - - if(inl != 16) /* libssh2 only ever encrypt one block */ - return 0; - - if(c == NULL) { - return 0; - } - -/* - To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each - blocks of length L), the encryptor first encrypts with - to obtain a block B1. The block B1 is then XORed with P1 to generate - the ciphertext block C1. The counter X is then incremented -*/ - - if(EVP_EncryptUpdate(c->aes_ctx, b1, &outlen, - c->ctr, AES_BLOCK_SIZE) != 1) { - return 0; - } - - _libssh2_xor_data(out, in, b1, AES_BLOCK_SIZE); - _libssh2_aes_ctr_increment(c->ctr, AES_BLOCK_SIZE); - - return 1; -} - -static int -aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */ -{ - aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); - - if(c == NULL) { - return 1; - } - - if(c->aes_ctx != NULL) { -#ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER_CTX_free(c->aes_ctx); -#else - _libssh2_cipher_dtor(c->aes_ctx); - free(c->aes_ctx); -#endif - } - - free(c); - - return 1; -} - -static const EVP_CIPHER * -make_ctr_evp (size_t keylen, EVP_CIPHER **aes_ctr_cipher, int type) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *aes_ctr_cipher = EVP_CIPHER_meth_new(type, 16, keylen); - if(*aes_ctr_cipher) { - EVP_CIPHER_meth_set_iv_length(*aes_ctr_cipher, 16); - EVP_CIPHER_meth_set_init(*aes_ctr_cipher, aes_ctr_init); - EVP_CIPHER_meth_set_do_cipher(*aes_ctr_cipher, aes_ctr_do_cipher); - EVP_CIPHER_meth_set_cleanup(*aes_ctr_cipher, aes_ctr_cleanup); - } -#else - (*aes_ctr_cipher)->nid = type; - (*aes_ctr_cipher)->block_size = 16; - (*aes_ctr_cipher)->key_len = keylen; - (*aes_ctr_cipher)->iv_len = 16; - (*aes_ctr_cipher)->init = aes_ctr_init; - (*aes_ctr_cipher)->do_cipher = aes_ctr_do_cipher; - (*aes_ctr_cipher)->cleanup = aes_ctr_cleanup; -#endif - - return *aes_ctr_cipher; -} - -const EVP_CIPHER * -_libssh2_EVP_aes_128_ctr(void) -{ -#ifdef HAVE_OPAQUE_STRUCTS - 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; - 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 -} - -const EVP_CIPHER * -_libssh2_EVP_aes_192_ctr(void) -{ -#ifdef HAVE_OPAQUE_STRUCTS - 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; - 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 -} - -const EVP_CIPHER * -_libssh2_EVP_aes_256_ctr(void) -{ -#ifdef HAVE_OPAQUE_STRUCTS - 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; - 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 -} - -#endif /* LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) */ - void _libssh2_openssl_crypto_init(void) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) -#ifndef OPENSSL_NO_ENGINE - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); -#endif -#else +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) OpenSSL_add_all_algorithms(); OpenSSL_add_all_ciphers(); OpenSSL_add_all_digests(); @@ -668,44 +1149,25 @@ void _libssh2_openssl_crypto_init(void) ENGINE_register_all_complete(); #endif #endif -#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(); +#if defined(LIBSSH2_WOLFSSL) && defined(DEBUG_WOLFSSL) + wolfSSL_Debugging_ON(); #endif } void _libssh2_openssl_crypto_exit(void) { -#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); - } - - if(aes_192_ctr_cipher) { - EVP_CIPHER_meth_free(aes_192_ctr_cipher); - } - - if(aes_256_ctr_cipher) { - EVP_CIPHER_meth_free(aes_256_ctr_cipher); - } -#endif - - aes_128_ctr_cipher = NULL; - aes_192_ctr_cipher = NULL; - aes_256_ctr_cipher = NULL; -#endif } +#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA || LIBSSH2_ED25519 /* TODO: Optionally call a passphrase callback specified by the * calling program */ static int passphrase_cb(char *buf, int size, int rwflag, char *passphrase) { - int passphrase_len = strlen(passphrase); - (void) rwflag; + int passphrase_len = (int) strlen(passphrase); + + (void)rwflag; if(passphrase_len > (size - 1)) { passphrase_len = size - 1; @@ -730,19 +1192,24 @@ read_private_key_from_memory(void **key_ctx, *key_ctx = NULL; - bp = BIO_new_mem_buf((char *)filedata, filedata_len); +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL + bp = BIO_new_mem_buf(filedata, (int)filedata_len); +#else + bp = BIO_new_mem_buf((char *)filedata, (int)filedata_len); +#endif if(!bp) { return -1; } + *key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb, (void *) passphrase); BIO_free(bp); return (*key_ctx) ? 0 : -1; } +#endif - - +#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA static int read_private_key_from_file(void **key_ctx, pem_read_bio_func read_private_key, @@ -764,47 +1231,75 @@ read_private_key_from_file(void **key_ctx, BIO_free(bp); return (*key_ctx) ? 0 : -1; } +#endif +#if LIBSSH2_RSA int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, + const char *filedata, + size_t filedata_len, unsigned const char *passphrase) { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_rsa = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_rsa = (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; +#endif _libssh2_init_if_needed(); - rc = read_private_key_from_memory((void **) rsa, read_rsa, - filedata, filedata_len, passphrase); + rc = read_private_key_from_memory((void **)rsa, read_rsa, + filedata, filedata_len, + passphrase); if(rc) { - rc = read_openssh_private_key_from_memory((void **)rsa, session, - "ssh-rsa", filedata, filedata_len, passphrase); + rc = _libssh2_pub_priv_openssh_keyfilememory(session, (void **)rsa, + "ssh-rsa", + NULL, NULL, NULL, NULL, + filedata, filedata_len, + passphrase); } -return rc; + return rc; } static unsigned char * -gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa, +gen_publickey_from_rsa(LIBSSH2_SESSION *session, libssh2_rsa_ctx *rsa, size_t *key_len) { int e_bytes, n_bytes; unsigned long len; - unsigned char *key; + unsigned char *key = NULL; unsigned char *p; + +#ifdef USE_OPENSSL_3 + BIGNUM * e = NULL; + BIGNUM * n = NULL; + + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n); +#else const BIGNUM * e; const BIGNUM * n; -#ifdef HAVE_OPAQUE_STRUCTS +#if defined(HAVE_OPAQUE_STRUCTS) + e = NULL; + n = NULL; + RSA_get0_key(rsa, &n, &e, NULL); #else e = rsa->e; n = rsa->n; #endif +#endif + if(!e || !n) { + goto fail; + } + e_bytes = BN_num_bytes(e) + 1; n_bytes = BN_num_bytes(n) + 1; @@ -812,8 +1307,8 @@ gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa, len = 4 + 7 + 4 + e_bytes + 4 + n_bytes; key = LIBSSH2_ALLOC(session, len); - if(key == NULL) { - return NULL; + if(!key) { + goto fail; } /* Process key encoding. */ @@ -828,6 +1323,11 @@ gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa, p = write_bn(p, n, n_bytes); *key_len = (size_t)(p - key); +fail: +#ifdef USE_OPENSSL_3 + BN_clear_free(e); + BN_clear_free(n); +#endif return key; } @@ -839,44 +1339,56 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, size_t *pubkeydata_len, EVP_PKEY *pk) { - RSA* rsa = NULL; + libssh2_rsa_ctx* rsa = NULL; unsigned char *key; unsigned char *method_buf = NULL; size_t key_len; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing public key from RSA private key envelope"); + "Computing public key from RSA private key envelope")); +#ifdef USE_OPENSSL_3 + rsa = pk; +#else rsa = EVP_PKEY_get1_RSA(pk); - if(rsa == NULL) { +#endif + if(!rsa) { /* Assume memory allocation error... what else could it be ? */ goto __alloc_error; } method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */ - if(method_buf == NULL) { + if(!method_buf) { goto __alloc_error; } key = gen_publickey_from_rsa(session, rsa, &key_len); - if(key == NULL) { + if(!key) { goto __alloc_error; } +#ifndef USE_OPENSSL_3 RSA_free(rsa); +#endif memcpy(method_buf, "ssh-rsa", 7); - *method = method_buf; - *method_len = 7; - *pubkeydata = key; - *pubkeydata_len = key_len; + *method = method_buf; + if(method_len) { + *method_len = 7; + } + *pubkeydata = key; + if(pubkeydata_len) { + *pubkeydata_len = key_len; + } return 0; - __alloc_error: - if(rsa != NULL) { +__alloc_error: +#ifndef USE_OPENSSL_3 + if(rsa) { RSA_free(rsa); } - if(method_buf != NULL) { +#endif + if(method_buf) { LIBSSH2_FREE(session, method_buf); } @@ -885,7 +1397,8 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, "Unable to allocate memory for private key data"); } -static int _libssh2_rsa_new_additional_parameters(RSA *rsa) +#ifndef USE_OPENSSL_3 +static int _libssh2_rsa_new_additional_parameters(libssh2_rsa_ctx *rsa) { BN_CTX *ctx = NULL; BIGNUM *aux = NULL; @@ -906,23 +1419,23 @@ static int _libssh2_rsa_new_additional_parameters(RSA *rsa) #endif ctx = BN_CTX_new(); - if(ctx == NULL) + if(!ctx) return -1; aux = BN_new(); - if(aux == NULL) { + if(!aux) { rc = -1; goto out; } dmp1 = BN_new(); - if(dmp1 == NULL) { + if(!dmp1) { rc = -1; goto out; } dmq1 = BN_new(); - if(dmq1 == NULL) { + if(!dmq1) { rc = -1; goto out; } @@ -947,7 +1460,7 @@ out: BN_clear_free(aux); BN_CTX_free(ctx); - if(rc != 0) { + if(rc) { if(dmp1) BN_clear_free(dmp1); if(dmq1) @@ -956,6 +1469,7 @@ out: return rc; } +#endif /* ndef USE_OPENSSL_3 */ static int gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, @@ -969,11 +1483,11 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, int rc = 0; size_t nlen, elen, dlen, plen, qlen, coefflen, commentlen; unsigned char *n, *e, *d, *p, *q, *coeff, *comment; - RSA *rsa = NULL; + libssh2_rsa_ctx *rsa = NULL; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing RSA keys from private key data"); + "Computing RSA keys from private key data")); /* public key data */ if(_libssh2_get_bignum_bytes(decrypted, &n, &nlen)) { @@ -1019,41 +1533,55 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, return -1; } - if((rc = _libssh2_rsa_new(&rsa, e, elen, n, nlen, d, dlen, p, plen, - q, qlen, NULL, 0, NULL, 0, - coeff, coefflen)) != 0) { - _libssh2_debug(session, + rc = _libssh2_rsa_new(&rsa, + e, (unsigned long)elen, + n, (unsigned long)nlen, + d, (unsigned long)dlen, + p, (unsigned long)plen, + q, (unsigned long)qlen, + NULL, 0, NULL, 0, + coeff, (unsigned long)coefflen); + if(rc) { + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Could not create RSA private key"); + "Could not create RSA private key")); goto fail; } - if(rsa != NULL) +#ifndef USE_OPENSSL_3 + if(rsa) rc = _libssh2_rsa_new_additional_parameters(rsa); +#endif - if(rsa != NULL && pubkeydata != NULL && method != NULL) { + if(rsa && pubkeydata && method) { +#ifdef USE_OPENSSL_3 + EVP_PKEY *pk = rsa; +#else EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pk, rsa); +#endif rc = gen_publickey_from_rsa_evp(session, method, method_len, pubkeydata, pubkeydata_len, pk); +#ifndef USE_OPENSSL_3 if(pk) EVP_PKEY_free(pk); +#endif } - if(rsa_ctx != NULL) + if(rsa_ctx) *rsa_ctx = rsa; else - RSA_free(rsa); + _libssh2_rsa_free(rsa); return rc; fail: - if(rsa != NULL) - RSA_free(rsa); + if(rsa) + _libssh2_rsa_free(rsa); return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -1071,7 +1599,7 @@ _libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa, unsigned char *buf = NULL; struct string_buf *decrypted = NULL; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); return -1; @@ -1095,7 +1623,7 @@ _libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -1103,8 +1631,8 @@ _libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa, if(strcmp("ssh-rsa", (const char *)buf) == 0) { rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted, - NULL, 0, - NULL, 0, rsa); + NULL, NULL, + NULL, NULL, rsa); } else { rc = -1; @@ -1123,8 +1651,13 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_rsa = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_rsa = (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; +#endif _libssh2_init_if_needed(); @@ -1138,41 +1671,63 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, return rc; } +#endif #if LIBSSH2_DSA int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, + const char *filedata, + size_t filedata_len, unsigned const char *passphrase) { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_dsa = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_dsa = (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; +#endif _libssh2_init_if_needed(); rc = read_private_key_from_memory((void **)dsa, read_dsa, - filedata, filedata_len, passphrase); + filedata, filedata_len, + passphrase); if(rc) { - rc = read_openssh_private_key_from_memory((void **)dsa, session, - "ssh-dsa", filedata, filedata_len, passphrase); + rc = _libssh2_pub_priv_openssh_keyfilememory(session, (void **)dsa, + "ssh-dsa", + NULL, NULL, NULL, NULL, + filedata, filedata_len, + passphrase); } return rc; } static unsigned char * -gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa, +gen_publickey_from_dsa(LIBSSH2_SESSION* session, libssh2_dsa_ctx *dsa, size_t *key_len) { int p_bytes, q_bytes, g_bytes, k_bytes; unsigned long len; - unsigned char *key; + unsigned char *key = NULL; unsigned char *p; +#ifdef USE_OPENSSL_3 + BIGNUM * p_bn = NULL; + BIGNUM * q = NULL; + BIGNUM * g = NULL; + BIGNUM * pub_key = NULL; + + EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_P, &p_bn); + EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else const BIGNUM * p_bn; const BIGNUM * q; const BIGNUM * g; @@ -1189,6 +1744,7 @@ gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa, DSA_get0_key(dsa, &pub_key, NULL); #else pub_key = dsa->pub_key; +#endif #endif p_bytes = BN_num_bytes(p_bn) + 1; q_bytes = BN_num_bytes(q) + 1; @@ -1199,8 +1755,8 @@ gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa, len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes; key = LIBSSH2_ALLOC(session, len); - if(key == NULL) { - return NULL; + if(!key) { + goto fail; } /* Process key encoding. */ @@ -1217,6 +1773,13 @@ gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa, p = write_bn(p, pub_key, k_bytes); *key_len = (size_t)(p - key); +fail: +#ifdef USE_OPENSSL_3 + BN_clear_free(p_bn); + BN_clear_free(q); + BN_clear_free(g); + BN_clear_free(pub_key); +#endif return key; } @@ -1228,44 +1791,56 @@ gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session, size_t *pubkeydata_len, EVP_PKEY *pk) { - DSA* dsa = NULL; + libssh2_dsa_ctx *dsa = NULL; unsigned char *key; unsigned char *method_buf = NULL; size_t key_len; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing public key from DSA private key envelope"); + "Computing public key from DSA private key envelope")); +#ifdef USE_OPENSSL_3 + dsa = pk; +#else dsa = EVP_PKEY_get1_DSA(pk); - if(dsa == NULL) { +#endif + if(!dsa) { /* Assume memory allocation error... what else could it be ? */ goto __alloc_error; } method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */ - if(method_buf == NULL) { + if(!method_buf) { goto __alloc_error; } key = gen_publickey_from_dsa(session, dsa, &key_len); - if(key == NULL) { + if(!key) { goto __alloc_error; } +#ifndef USE_OPENSSL_3 DSA_free(dsa); +#endif memcpy(method_buf, "ssh-dss", 7); - *method = method_buf; - *method_len = 7; - *pubkeydata = key; - *pubkeydata_len = key_len; + *method = method_buf; + if(method_len) { + *method_len = 7; + } + *pubkeydata = key; + if(pubkeydata_len) { + *pubkeydata_len = key_len; + } return 0; - __alloc_error: - if(dsa != NULL) { +__alloc_error: +#ifndef USE_OPENSSL_3 + if(dsa) { DSA_free(dsa); } - if(method_buf != NULL) { +#endif + if(method_buf) { LIBSSH2_FREE(session, method_buf); } @@ -1286,11 +1861,11 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, int rc = 0; size_t plen, qlen, glen, pub_len, priv_len; unsigned char *p, *q, *g, *pub_key, *priv_key; - DSA *dsa = NULL; + libssh2_dsa_ctx *dsa = NULL; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing DSA keys from private key data"); + "Computing DSA keys from private key data")); if(_libssh2_get_bignum_bytes(decrypted, &p, &plen)) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, @@ -1322,38 +1897,48 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, return -1; } - rc = _libssh2_dsa_new(&dsa, p, plen, q, qlen, g, glen, pub_key, pub_len, - priv_key, priv_len); - if(rc != 0) { - _libssh2_debug(session, + rc = _libssh2_dsa_new(&dsa, + p, (unsigned long)plen, + q, (unsigned long)qlen, + g, (unsigned long)glen, + pub_key, (unsigned long)pub_len, + priv_key, (unsigned long)priv_len); + if(rc) { + _libssh2_debug((session, LIBSSH2_ERROR_PROTO, - "Could not create DSA private key"); + "Could not create DSA private key")); goto fail; } - if(dsa != NULL && pubkeydata != NULL && method != NULL) { + if(dsa && pubkeydata && method) { +#ifdef USE_OPENSSL_3 + EVP_PKEY *pk = dsa; +#else EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_DSA(pk, dsa); +#endif rc = gen_publickey_from_dsa_evp(session, method, method_len, pubkeydata, pubkeydata_len, pk); +#ifndef USE_OPENSSL_3 if(pk) EVP_PKEY_free(pk); +#endif } - if(dsa_ctx != NULL) + if(dsa_ctx) *dsa_ctx = dsa; else - DSA_free(dsa); + _libssh2_dsa_free(dsa); return rc; fail: - if(dsa != NULL) - DSA_free(dsa); + if(dsa) + _libssh2_dsa_free(dsa); return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -1371,7 +1956,7 @@ _libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa, unsigned char *buf = NULL; struct string_buf *decrypted = NULL; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); return -1; @@ -1395,7 +1980,7 @@ _libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -1403,8 +1988,8 @@ _libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa, if(strcmp("ssh-dss", (const char *)buf) == 0) { rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted, - NULL, 0, - NULL, 0, dsa); + NULL, NULL, + NULL, NULL, dsa); } else { rc = -1; @@ -1423,8 +2008,13 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_dsa = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_dsa = (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; +#endif _libssh2_init_if_needed(); @@ -1438,36 +2028,71 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, return rc; } - #endif /* LIBSSH_DSA */ #if LIBSSH2_ECDSA - int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, - LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, - unsigned const char *passphrase) + LIBSSH2_SESSION * session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase) { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_ec = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; +#endif _libssh2_init_if_needed(); - rc = read_private_key_from_memory((void **) ec_ctx, read_ec, - filedata, filedata_len, passphrase); + rc = read_private_key_from_memory((void **)ec_ctx, read_ec, + filedata, filedata_len, + passphrase); if(rc) { - rc = read_openssh_private_key_from_memory((void **)ec_ctx, session, - "ssh-ecdsa", filedata, - filedata_len, passphrase); + rc = _libssh2_pub_priv_openssh_keyfilememory(session, (void **)ec_ctx, + "ssh-ecdsa", + NULL, NULL, NULL, NULL, + filedata, filedata_len, + passphrase); } return rc; } +int _libssh2_ecdsa_new_private_frommemory_sk(libssh2_ecdsa_ctx ** ec_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase) +{ + int algorithm; + return _libssh2_sk_pub_openssh_keyfilememory(session, + (void **)ec_ctx, + "sk-ecdsa-sha2-nistp256@openssh.com", + NULL, + NULL, + NULL, + NULL, + &algorithm, + flags, + application, + key_handle, + handle_len, + filedata, + filedata_len, + passphrase); +} + #endif /* LIBSSH2_ECDSA */ @@ -1485,38 +2110,38 @@ _libssh2_curve25519_new(LIBSSH2_SESSION *session, int rc = -1; pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); - if(pctx == NULL) + if(!pctx) return -1; if(EVP_PKEY_keygen_init(pctx) != 1 || EVP_PKEY_keygen(pctx, &key) != 1) { - goto cleanExit; + goto clean_exit; } - if(out_private_key != NULL) { + if(out_private_key) { privLen = LIBSSH2_ED25519_KEY_LEN; priv = LIBSSH2_ALLOC(session, privLen); - if(priv == NULL) - goto cleanExit; + if(!priv) + goto clean_exit; if(EVP_PKEY_get_raw_private_key(key, priv, &privLen) != 1 || privLen != LIBSSH2_ED25519_KEY_LEN) { - goto cleanExit; + goto clean_exit; } *out_private_key = priv; priv = NULL; } - if(out_public_key != NULL) { + if(out_public_key) { pubLen = LIBSSH2_ED25519_KEY_LEN; pub = LIBSSH2_ALLOC(session, pubLen); - if(pub == NULL) - goto cleanExit; + if(!pub) + goto clean_exit; if(EVP_PKEY_get_raw_public_key(key, pub, &pubLen) != 1 || pubLen != LIBSSH2_ED25519_KEY_LEN) { - goto cleanExit; + goto clean_exit; } *out_public_key = pub; @@ -1526,7 +2151,7 @@ _libssh2_curve25519_new(LIBSSH2_SESSION *session, /* success */ rc = 0; -cleanExit: +clean_exit: if(pctx) EVP_PKEY_CTX_free(pctx); @@ -1556,8 +2181,8 @@ gen_publickey_from_ed_evp(LIBSSH2_SESSION *session, size_t bufLen = 0; unsigned char *bufPos = NULL; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Computing public key from ED private key envelope"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Computing public key from ED private key envelope")); methodBuf = LIBSSH2_ALLOC(session, sizeof(methodName) - 1); if(!methodBuf) { @@ -1583,7 +2208,7 @@ gen_publickey_from_ed_evp(LIBSSH2_SESSION *session, } _libssh2_store_str(&bufPos, methodName, sizeof(methodName) - 1); - _libssh2_store_u32(&bufPos, rawKeyLen); + _libssh2_store_u32(&bufPos, (uint32_t) rawKeyLen); if(EVP_PKEY_get_raw_public_key(pk, bufPos, &rawKeyLen) != 1) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, @@ -1591,10 +2216,14 @@ gen_publickey_from_ed_evp(LIBSSH2_SESSION *session, goto fail; } - *method = methodBuf; - *method_len = sizeof(methodName) - 1; - *pubkeydata = keyBuf; - *pubkeydata_len = bufLen; + *method = methodBuf; + if(method_len) { + *method_len = sizeof(methodName) - 1; + } + *pubkeydata = keyBuf; + if(pubkeydata_len) { + *pubkeydata_len = bufLen; + } return 0; fail: @@ -1623,9 +2252,9 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, size_t key_len = 0, tmp_len = 0; unsigned char *p; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing ED25519 keys from private key data"); + "Computing ED25519 keys from private key data")); if(_libssh2_get_string(decrypted, &pub_key, &tmp_len) || tmp_len != LIBSSH2_ED25519_KEY_LEN) { @@ -1658,12 +2287,12 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, if(tmp_len > 0) { unsigned char *comment = LIBSSH2_CALLOC(session, tmp_len + 1); - if(comment != NULL) { + if(comment) { memcpy(comment, buf, tmp_len); memcpy(comment + tmp_len, "\0", 1); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Key comment: %s", - comment); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Key comment: %s", + comment)); LIBSSH2_FREE(session, comment); } @@ -1683,13 +2312,13 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, } if(ret == 0) { - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Computing public key from ED25519 " - "private key envelope"); + "private key envelope")); method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */ - if(method_buf == NULL) { + if(!method_buf) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for ED25519 key"); goto clean_exit; @@ -1699,7 +2328,7 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, pub_key(32). */ key_len = LIBSSH2_ED25519_KEY_LEN + 19; key = LIBSSH2_CALLOC(session, key_len); - if(key == NULL) { + if(!key) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for ED25519 key"); goto clean_exit; @@ -1712,25 +2341,25 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, memcpy(method_buf, "ssh-ed25519", 11); - if(method != NULL) + if(method) *method = method_buf; else LIBSSH2_FREE(session, method_buf); - if(method_len != NULL) + if(method_len) *method_len = 11; - if(pubkeydata != NULL) + if(pubkeydata) *pubkeydata = key; else LIBSSH2_FREE(session, key); - if(pubkeydata_len != NULL) + if(pubkeydata_len) *pubkeydata_len = key_len; - if(out_ctx != NULL) + if(out_ctx) *out_ctx = ctx; - else if(ctx != NULL) + else if(ctx) _libssh2_ed25519_free(ctx); return 0; @@ -1750,6 +2379,159 @@ clean_exit: return -1; } +static int +gen_publickey_from_sk_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, + struct string_buf *decrypted, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + libssh2_ed25519_ctx **out_ctx) +{ + const char *key_type = "sk-ssh-ed25519@openssh.com"; + + libssh2_ed25519_ctx *ctx = NULL; + unsigned char *method_buf = NULL; + unsigned char *key = NULL; + int ret = 0; + unsigned char *pub_key, *app; + size_t key_len = 0, app_len = 0, tmp_len = 0; + unsigned char *p; + + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing sk-ED25519 keys from private key data")); + + if(_libssh2_get_string(decrypted, &pub_key, &tmp_len) || + tmp_len != LIBSSH2_ED25519_KEY_LEN) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Wrong public key length"); + return -1; + } + + if(_libssh2_get_string(decrypted, &app, &app_len)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK application."); + return -1; + } + + if(flags && _libssh2_get_byte(decrypted, flags)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK flags."); + return -1; + } + + if(key_handle && handle_len) { + unsigned char *handle = NULL; + if(_libssh2_get_string(decrypted, &handle, handle_len)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK key_handle."); + return -1; + } + + if(*handle_len > 0) { + *key_handle = LIBSSH2_ALLOC(session, *handle_len); + + if(key_handle) { + memcpy((void *)*key_handle, handle, *handle_len); + } + } + } + + ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, + (const unsigned char *)pub_key, + LIBSSH2_ED25519_KEY_LEN); + + if(ret == 0) { + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing public key from ED25519 " + "private key envelope")); + + /* sk-ssh-ed25519@openssh.com. */ + method_buf = LIBSSH2_ALLOC(session, strlen(key_type)); + if(!method_buf) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for ED25519 key"); + goto clean_exit; + } + + /* Key form is: type_len(4) + type(26) + pub_key_len(4) + + pub_key(32) + application_len(4) + application(X). */ + key_len = LIBSSH2_ED25519_KEY_LEN + 38 + app_len; + key = LIBSSH2_CALLOC(session, key_len); + if(!key) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for ED25519 key"); + goto clean_exit; + } + + p = key; + + _libssh2_store_str(&p, key_type, strlen(key_type)); + _libssh2_store_str(&p, (const char *)pub_key, LIBSSH2_ED25519_KEY_LEN); + _libssh2_store_str(&p, (const char *)app, app_len); + + if(application && app_len > 0) { + *application = (const char *)LIBSSH2_ALLOC(session, app_len + 1); + _libssh2_explicit_zero((void *)*application, app_len + 1); + memcpy((void *)*application, app, app_len); + } + + memcpy(method_buf, key_type, strlen(key_type)); + + if(method) + *method = method_buf; + else + LIBSSH2_FREE(session, method_buf); + + if(method_len) + *method_len = strlen(key_type); + + if(pubkeydata) + *pubkeydata = key; + else if(key) + LIBSSH2_FREE(session, key); + + if(pubkeydata_len) + *pubkeydata_len = key_len; + + if(out_ctx) + *out_ctx = ctx; + else if(ctx) + _libssh2_ed25519_free(ctx); + + return 0; + } + +clean_exit: + + if(ctx) + _libssh2_ed25519_free(ctx); + + if(method_buf) + LIBSSH2_FREE(session, method_buf); + + if(key) + LIBSSH2_FREE(session, key); + + if(application && *application) { + LIBSSH2_FREE(session, (void *)application); + *application = NULL; + } + + if(key_handle && *key_handle) { + LIBSSH2_FREE(session, (void *)key_handle); + *key_handle = NULL; + } + + return -1; +} + int _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, LIBSSH2_SESSION * session, @@ -1761,7 +2543,7 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, struct string_buf *decrypted = NULL; libssh2_ed25519_ctx *ctx = NULL; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); return -1; @@ -1785,19 +2567,16 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; } if(strcmp("ssh-ed25519", (const char *)buf) == 0) { - rc = gen_publickey_from_ed25519_openssh_priv_data(session, - decrypted, - NULL, - NULL, - NULL, - NULL, + rc = gen_publickey_from_ed25519_openssh_priv_data(session, decrypted, + NULL, NULL, + NULL, NULL, &ctx); } else { @@ -1808,9 +2587,83 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, _libssh2_string_buf_free(session, decrypted); if(rc == 0) { - if(ed_ctx != NULL) + if(ed_ctx) *ed_ctx = ctx; - else if(ctx != NULL) + else if(ctx) + _libssh2_ed25519_free(ctx); + } + + return rc; +} + +int +_libssh2_ed25519_new_private_sk(libssh2_ed25519_ctx **ed_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION *session, + const char *filename, + const uint8_t *passphrase) +{ + int rc; + FILE *fp; + unsigned char *buf; + struct string_buf *decrypted = NULL; + libssh2_ed25519_ctx *ctx = NULL; + + if(!session) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Session is required"); + return -1; + } + + _libssh2_init_if_needed(); + + fp = fopen(filename, "r"); + if(!fp) { + _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to open ED25519 SK private key file"); + return -1; + } + + rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted); + fclose(fp); + if(rc) { + return rc; + } + + /* We have a new key file, now try and parse it using supported types */ + rc = _libssh2_get_string(decrypted, &buf, NULL); + + if(rc || !buf) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted key data not found"); + return -1; + } + + if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) { + rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session, + decrypted, + NULL, NULL, + NULL, NULL, + flags, + application, + key_handle, + handle_len, + &ctx); + } + else { + rc = -1; + } + + if(decrypted) + _libssh2_string_buf_free(session, decrypted); + + if(rc == 0) { + if(ed_ctx) + *ed_ctx = ctx; + else if(ctx) _libssh2_ed25519_free(ctx); } @@ -1831,7 +2684,8 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx, if(read_private_key_from_memory((void **)&ctx, (pem_read_bio_func) &PEM_read_bio_PrivateKey, - filedata, filedata_len, passphrase) == 0) { + filedata, filedata_len, + passphrase) == 0) { if(EVP_PKEY_id(ctx) != EVP_PKEY_ED25519) { _libssh2_ed25519_free(ctx); return _libssh2_error(session, LIBSSH2_ERROR_PROTO, @@ -1842,21 +2696,51 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx, return 0; } - return read_openssh_private_key_from_memory((void **)ed_ctx, session, - "ssh-ed25519", - filedata, filedata_len, - passphrase); + return _libssh2_pub_priv_openssh_keyfilememory(session, (void **)ed_ctx, + "ssh-ed25519", + NULL, NULL, NULL, NULL, + filedata, filedata_len, + passphrase); +} + +int +_libssh2_ed25519_new_private_frommemory_sk(libssh2_ed25519_ctx **ed_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION *session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase) +{ + int algorithm; + return _libssh2_sk_pub_openssh_keyfilememory(session, + (void **)ed_ctx, + "sk-ssh-ed25519@openssh.com", + NULL, + NULL, + NULL, + NULL, + &algorithm, + flags, + application, + key_handle, + handle_len, + filedata, + filedata_len, + passphrase); } int _libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx, LIBSSH2_SESSION * session, const unsigned char *raw_pub_key, - const uint8_t key_len) + const size_t key_len) { libssh2_ed25519_ctx *ctx = NULL; - if(ed_ctx == NULL) + if(!ed_ctx) return -1; ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, @@ -1865,7 +2749,7 @@ _libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx, return _libssh2_error(session, LIBSSH2_ERROR_PROTO, "could not create ED25519 public key"); - if(ed_ctx != NULL) + if(ed_ctx) *ed_ctx = ctx; else if(ctx) _libssh2_ed25519_free(ctx); @@ -1875,25 +2759,81 @@ _libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx, #endif /* LIBSSH2_ED25519 */ +#if LIBSSH2_RSA int -_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, +_libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session, libssh2_rsa_ctx * rsactx, const unsigned char *hash, size_t hash_len, unsigned char **signature, size_t *signature_len) { - int ret; - unsigned char *sig; - unsigned int sig_len; + int ret = -1; + unsigned char *sig = NULL; + +#ifdef USE_OPENSSL_3 + size_t sig_len = 0; + BIGNUM *n = NULL; + const EVP_MD *md = NULL; + + if(EVP_PKEY_get_bn_param(rsactx, OSSL_PKEY_PARAM_RSA_N, &n) > 0) { + sig_len = BN_num_bytes(n); + BN_clear_free(n); + } + + if(sig_len > 0) + sig = LIBSSH2_ALLOC(session, sig_len); +#else + unsigned int sig_len = 0; sig_len = RSA_size(rsactx); sig = LIBSSH2_ALLOC(session, sig_len); +#endif if(!sig) { return -1; } - ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx); +#ifdef USE_OPENSSL_3 + if(hash_len == SHA_DIGEST_LENGTH) + md = EVP_sha1(); + else if(hash_len == SHA256_DIGEST_LENGTH) + md = EVP_sha256(); + else if(hash_len == SHA512_DIGEST_LENGTH) + md = EVP_sha512(); + else { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unsupported hash digest length"); + } + + if(md) { + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(rsactx, NULL); + if(ctx && + EVP_PKEY_sign_init(ctx) > 0 && + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0 && + EVP_PKEY_CTX_set_signature_md(ctx, md) > 0) { + ret = EVP_PKEY_sign(ctx, sig, &sig_len, hash, hash_len); + } + + if(ctx) { + EVP_PKEY_CTX_free(ctx); + } + } +#else + if(hash_len == SHA_DIGEST_LENGTH) + ret = RSA_sign(NID_sha1, + hash, (unsigned int) hash_len, sig, &sig_len, rsactx); + else if(hash_len == SHA256_DIGEST_LENGTH) + ret = RSA_sign(NID_sha256, + hash, (unsigned int) hash_len, sig, &sig_len, rsactx); + else if(hash_len == SHA512_DIGEST_LENGTH) + ret = RSA_sign(NID_sha512, + hash, (unsigned int) hash_len, sig, &sig_len, rsactx); + else { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unsupported hash digest length"); + ret = -1; + } +#endif if(!ret) { LIBSSH2_FREE(session, sig); @@ -1906,19 +2846,61 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, return 0; } +#if LIBSSH2_RSA_SHA1 +int +_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, + libssh2_rsa_ctx * rsactx, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, size_t *signature_len) +{ + return _libssh2_rsa_sha2_sign(session, rsactx, hash, hash_len, + signature, signature_len); +} +#endif +#endif + #if LIBSSH2_DSA int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, const unsigned char *hash, - unsigned long hash_len, unsigned char *signature) + size_t hash_len, unsigned char *signature) { - DSA_SIG *sig; + DSA_SIG *sig = NULL; const BIGNUM * r; const BIGNUM * s; int r_len, s_len; - (void) hash_len; + +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(dsactx, NULL); + unsigned char *buf = NULL; + size_t sig_len = 0; + int size = 0; + + if(EVP_PKEY_get_int_param(dsactx, OSSL_PKEY_PARAM_MAX_SIZE, &size) > 0) { + sig_len = size; + buf = OPENSSL_malloc(size); + } + + if(buf && ctx && EVP_PKEY_sign_init(ctx) > 0) { + EVP_PKEY_sign(ctx, buf, &sig_len, hash, hash_len); + } + + if(ctx) { + EVP_PKEY_CTX_free(ctx); + } + + if(buf) { + const unsigned char *in = buf; + d2i_DSA_SIG(&sig, &in, (long)sig_len); + OPENSSL_clear_free(buf, size); + } +#else + (void)hash_len; sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx); +#endif + if(!sig) { return -1; } @@ -1930,20 +2912,20 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, s = sig->s; #endif r_len = BN_num_bytes(r); - if(r_len < 1 || r_len > 20) { + if(r_len < 1 || r_len > SHA_DIGEST_LENGTH) { DSA_SIG_free(sig); return -1; } s_len = BN_num_bytes(s); - if(s_len < 1 || s_len > 20) { + if(s_len < 1 || s_len > SHA_DIGEST_LENGTH) { DSA_SIG_free(sig); return -1; } - memset(signature, 0, 40); + memset(signature, 0, SHA_DIGEST_LENGTH * 2); - BN_bn2bin(r, signature + (20 - r_len)); - BN_bn2bin(s, signature + 20 + (20 - s_len)); + BN_bn2bin(r, signature + (SHA_DIGEST_LENGTH - r_len)); + BN_bn2bin(s, signature + SHA_DIGEST_LENGTH + (SHA_DIGEST_LENGTH - s_len)); DSA_SIG_free(sig); @@ -1955,8 +2937,8 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, int _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, - const unsigned char *hash, unsigned long hash_len, - unsigned char **signature, size_t *signature_len) + const unsigned char *hash, size_t hash_len, + unsigned char **signature, size_t *signature_len) { int r_len, s_len; int rc = 0; @@ -1965,10 +2947,47 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, const BIGNUM *pr = NULL, *ps = NULL; unsigned char *temp_buffer = NULL; unsigned char *out_buffer = NULL; + ECDSA_SIG *sig = NULL; - ECDSA_SIG *sig = ECDSA_do_sign(hash, hash_len, ec_ctx); - if(sig == NULL) +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(ec_ctx, NULL); + const unsigned char *p = NULL; + rc = -1; + + if(!ctx) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "out of memory"); + } + + out_buffer_len = EVP_PKEY_get_size(ec_ctx); + temp_buffer = LIBSSH2_ALLOC(session, out_buffer_len); + if(!temp_buffer) { + goto clean_exit; + } + + rc = EVP_PKEY_sign_init(ctx); + if(rc <= 0) { + rc = -1; + goto clean_exit; + } + + rc = EVP_PKEY_sign(ctx, temp_buffer, &out_buffer_len, hash, hash_len); + if(rc <= 0) { + rc = -1; + goto clean_exit; + } + + rc = 0; + + p = temp_buffer; + sig = d2i_ECDSA_SIG(NULL, &p, (long)out_buffer_len); + OPENSSL_clear_free(temp_buffer, out_buffer_len); +#else + sig = ECDSA_do_sign(hash, (int)hash_len, ec_ctx); + if(!sig) return -1; +#endif + #ifdef HAVE_OPAQUE_STRUCTS ECDSA_SIG_get0(sig, &pr, &ps); #else @@ -1980,7 +2999,7 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, s_len = BN_num_bytes(ps) + 1; temp_buffer = malloc(r_len + s_len + 8); - if(temp_buffer == NULL) { + if(!temp_buffer) { rc = -1; goto clean_exit; } @@ -1992,7 +3011,7 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, out_buffer_len = (size_t)(sp - temp_buffer); out_buffer = LIBSSH2_CALLOC(session, out_buffer_len); - if(out_buffer == NULL) { + if(!out_buffer) { rc = -1; goto clean_exit; } @@ -2004,12 +3023,17 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, clean_exit: - if(temp_buffer != NULL) + if(temp_buffer) free(temp_buffer); if(sig) ECDSA_SIG_free(sig); +#ifdef USE_OPENSSL_3 + if(ctx) + EVP_PKEY_CTX_free(ctx); +#endif + return rc; } #endif /* LIBSSH2_ECDSA */ @@ -2020,7 +3044,7 @@ _libssh2_sha1_init(libssh2_sha1_ctx *ctx) #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha1"))) @@ -2037,13 +3061,37 @@ _libssh2_sha1_init(libssh2_sha1_ctx *ctx) } int -_libssh2_sha1(const unsigned char *message, unsigned long len, +_libssh2_sha1_update(libssh2_sha1_ctx *ctx, + const void *data, size_t len) +{ +#ifdef HAVE_OPAQUE_STRUCTS + return EVP_DigestUpdate(*ctx, data, len); +#else + return EVP_DigestUpdate(ctx, data, len); +#endif +} + +int +_libssh2_sha1_final(libssh2_sha1_ctx *ctx, + unsigned char *out) +{ +#ifdef HAVE_OPAQUE_STRUCTS + int ret = EVP_DigestFinal(*ctx, out, NULL); + EVP_MD_CTX_free(*ctx); + return ret; +#else + return EVP_DigestFinal(ctx, out, NULL); +#endif +} + +int +_libssh2_sha1(const unsigned char *message, size_t len, unsigned char *out) { #ifdef HAVE_OPAQUE_STRUCTS EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - if(ctx == NULL) + if(!ctx) return 1; /* error */ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha1"))) { @@ -2072,7 +3120,7 @@ _libssh2_sha256_init(libssh2_sha256_ctx *ctx) #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha256"))) @@ -2089,13 +3137,37 @@ _libssh2_sha256_init(libssh2_sha256_ctx *ctx) } int -_libssh2_sha256(const unsigned char *message, unsigned long len, +_libssh2_sha256_update(libssh2_sha256_ctx *ctx, + const void *data, size_t len) +{ +#ifdef HAVE_OPAQUE_STRUCTS + return EVP_DigestUpdate(*ctx, data, len); +#else + return EVP_DigestUpdate(ctx, data, len); +#endif +} + +int +_libssh2_sha256_final(libssh2_sha256_ctx *ctx, + unsigned char *out) +{ +#ifdef HAVE_OPAQUE_STRUCTS + int ret = EVP_DigestFinal(*ctx, out, NULL); + EVP_MD_CTX_free(*ctx); + return ret; +#else + return EVP_DigestFinal(ctx, out, NULL); +#endif +} + +int +_libssh2_sha256(const unsigned char *message, size_t len, unsigned char *out) { #ifdef HAVE_OPAQUE_STRUCTS EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - if(ctx == NULL) + if(!ctx) return 1; /* error */ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha256"))) { @@ -2124,7 +3196,7 @@ _libssh2_sha384_init(libssh2_sha384_ctx *ctx) #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha384"))) @@ -2141,13 +3213,37 @@ _libssh2_sha384_init(libssh2_sha384_ctx *ctx) } int -_libssh2_sha384(const unsigned char *message, unsigned long len, - unsigned char *out) +_libssh2_sha384_update(libssh2_sha384_ctx *ctx, + const void *data, size_t len) +{ +#ifdef HAVE_OPAQUE_STRUCTS + return EVP_DigestUpdate(*ctx, data, len); +#else + return EVP_DigestUpdate(ctx, data, len); +#endif +} + +int +_libssh2_sha384_final(libssh2_sha384_ctx *ctx, + unsigned char *out) +{ +#ifdef HAVE_OPAQUE_STRUCTS + int ret = EVP_DigestFinal(*ctx, out, NULL); + EVP_MD_CTX_free(*ctx); + return ret; +#else + return EVP_DigestFinal(ctx, out, NULL); +#endif +} + +int +_libssh2_sha384(const unsigned char *message, size_t len, + unsigned char *out) { #ifdef HAVE_OPAQUE_STRUCTS EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - if(ctx == NULL) + if(!ctx) return 1; /* error */ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha384"))) { @@ -2176,7 +3272,7 @@ _libssh2_sha512_init(libssh2_sha512_ctx *ctx) #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha512"))) @@ -2193,13 +3289,37 @@ _libssh2_sha512_init(libssh2_sha512_ctx *ctx) } int -_libssh2_sha512(const unsigned char *message, unsigned long len, - unsigned char *out) +_libssh2_sha512_update(libssh2_sha512_ctx *ctx, + const void *data, size_t len) +{ +#ifdef HAVE_OPAQUE_STRUCTS + return EVP_DigestUpdate(*ctx, data, len); +#else + return EVP_DigestUpdate(ctx, data, len); +#endif +} + +int +_libssh2_sha512_final(libssh2_sha512_ctx *ctx, + unsigned char *out) +{ +#ifdef HAVE_OPAQUE_STRUCTS + int ret = EVP_DigestFinal(*ctx, out, NULL); + EVP_MD_CTX_free(*ctx); + return ret; +#else + return EVP_DigestFinal(ctx, out, NULL); +#endif +} + +int +_libssh2_sha512(const unsigned char *message, size_t len, + unsigned char *out) { #ifdef HAVE_OPAQUE_STRUCTS EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - if(ctx == NULL) + if(!ctx) return 1; /* error */ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha512"))) { @@ -2222,6 +3342,7 @@ _libssh2_sha512(const unsigned char *message, unsigned long len, return 1; /* error */ } +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM int _libssh2_md5_init(libssh2_md5_ctx *ctx) { @@ -2231,17 +3352,17 @@ _libssh2_md5_init(libssh2_md5_ctx *ctx) * So, just return 0 in FIPS mode */ #if OPENSSL_VERSION_NUMBER >= 0x000907000L && \ - defined(OPENSSL_VERSION_MAJOR) && \ - OPENSSL_VERSION_MAJOR < 3 && \ + !defined(USE_OPENSSL_3) && \ !defined(LIBRESSL_VERSION_NUMBER) - if(FIPS_mode() != 0) - return 0; + + if(FIPS_mode()) + return 0; #endif #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("md5"))) @@ -2257,6 +3378,31 @@ _libssh2_md5_init(libssh2_md5_ctx *ctx) #endif } +int +_libssh2_md5_update(libssh2_md5_ctx *ctx, + const void *data, size_t len) +{ +#ifdef HAVE_OPAQUE_STRUCTS + return EVP_DigestUpdate(*ctx, data, len); +#else + return EVP_DigestUpdate(ctx, data, len); +#endif +} + +int +_libssh2_md5_final(libssh2_md5_ctx *ctx, + unsigned char *out) +{ +#ifdef HAVE_OPAQUE_STRUCTS + int ret = EVP_DigestFinal(*ctx, out, NULL); + EVP_MD_CTX_free(*ctx); + return ret; +#else + return EVP_DigestFinal(ctx, out, NULL); +#endif +} +#endif + #if LIBSSH2_ECDSA static int @@ -2265,31 +3411,41 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, size_t *method_len, unsigned char **pubkeydata, size_t *pubkeydata_len, + int is_sk, EVP_PKEY *pk) { int rc = 0; - EC_KEY *ec = NULL; unsigned char *p; unsigned char *method_buf = NULL; unsigned char *key; + size_t method_buf_len = 0; size_t key_len = 0; unsigned char *octal_value = NULL; size_t octal_len; - const EC_POINT *public_key; - const EC_GROUP *group; - BN_CTX *bn_ctx; libssh2_curve_type type; - _libssh2_debug(session, +#ifdef USE_OPENSSL_3 + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing public key from EC private key envelope"); + "Computing public key from EC private key envelope")); + + type = _libssh2_ecdsa_get_curve_type(pk); +#else + EC_KEY *ec = NULL; + const EC_POINT *public_key; + const EC_GROUP *group; + BN_CTX *bn_ctx = NULL; + + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing public key from EC private key envelope")); bn_ctx = BN_CTX_new(); - if(bn_ctx == NULL) + if(!bn_ctx) return -1; ec = EVP_PKEY_get1_EC_KEY(pk); - if(ec == NULL) { + if(!ec) { rc = -1; goto clean_exit; } @@ -2297,27 +3453,46 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, public_key = EC_KEY_get0_public_key(ec); group = EC_KEY_get0_group(ec); type = _libssh2_ecdsa_get_curve_type(ec); +#endif - method_buf = LIBSSH2_ALLOC(session, 19); - if(method_buf == NULL) { + if(is_sk) + method_buf_len = 34; + else + method_buf_len = 19; + + method_buf = LIBSSH2_ALLOC(session, method_buf_len); + if(!method_buf) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "out of memory"); + "out of memory"); } - if(type == LIBSSH2_EC_CURVE_NISTP256) - memcpy(method_buf, "ecdsa-sha2-nistp256", 19); - else if(type == LIBSSH2_EC_CURVE_NISTP384) - memcpy(method_buf, "ecdsa-sha2-nistp384", 19); - else if(type == LIBSSH2_EC_CURVE_NISTP521) - memcpy(method_buf, "ecdsa-sha2-nistp521", 19); + if(is_sk) { + memcpy(method_buf, "sk-ecdsa-sha2-nistp256@openssh.com", + method_buf_len); + } + else if(type == LIBSSH2_EC_CURVE_NISTP256) { + memcpy(method_buf, "ecdsa-sha2-nistp256", method_buf_len); + } + else if(type == LIBSSH2_EC_CURVE_NISTP384) { + memcpy(method_buf, "ecdsa-sha2-nistp384", method_buf_len); + } + else if(type == LIBSSH2_EC_CURVE_NISTP521) { + memcpy(method_buf, "ecdsa-sha2-nistp521", method_buf_len); + } else { - _libssh2_debug(session, - LIBSSH2_TRACE_ERROR, - "Unsupported EC private key type"); + _libssh2_debug((session, + LIBSSH2_TRACE_ERROR, + "Unsupported EC private key type")); rc = -1; goto clean_exit; } +#ifdef USE_OPENSSL_3 + octal_len = EC_MAX_POINT_LEN; + octal_value = LIBSSH2_ALLOC(session, octal_len); + EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_PUB_KEY, + octal_value, octal_len, &octal_len); +#else /* get length */ octal_len = EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, @@ -2328,7 +3503,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, } octal_value = malloc(octal_len); - if(octal_value == NULL) { + if(!octal_value) { rc = -1; goto clean_exit; } @@ -2336,52 +3511,64 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, /* convert to octal */ if(EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, octal_value, octal_len, bn_ctx) != octal_len) { - rc = -1; - goto clean_exit; - } - - /* Key form is: type_len(4) + type(19) + domain_len(4) + domain(8) + - pub_key_len(4) + pub_key(~65). */ - key_len = 4 + 19 + 4 + 8 + 4 + octal_len; - key = LIBSSH2_ALLOC(session, key_len); - if(key == NULL) { rc = -1; - goto clean_exit; + goto clean_exit; + } +#endif + + /* Key form is: type_len(4) + type(method_buf_len) + domain_len(4) + + domain(8) + pub_key_len(4) + pub_key(~65). */ + key_len = 4 + method_buf_len + 4 + 8 + 4 + octal_len; + key = LIBSSH2_ALLOC(session, key_len); + if(!key) { + rc = -1; + goto clean_exit; } /* Process key encoding. */ p = key; /* Key type */ - _libssh2_store_str(&p, (const char *)method_buf, 19); + _libssh2_store_str(&p, (const char *)method_buf, method_buf_len); /* Name domain */ - _libssh2_store_str(&p, (const char *)method_buf + 11, 8); + if(is_sk) { + _libssh2_store_str(&p, "nistp256", 8); + } + else { + _libssh2_store_str(&p, (const char *)method_buf + 11, 8); + } /* Public key */ _libssh2_store_str(&p, (const char *)octal_value, octal_len); - *method = method_buf; - *method_len = 19; - *pubkeydata = key; - *pubkeydata_len = key_len; + *method = method_buf; + if(method_len) { + *method_len = method_buf_len; + } + *pubkeydata = key; + if(pubkeydata_len) { + *pubkeydata_len = key_len; + } clean_exit: - if(ec != NULL) +#ifndef USE_OPENSSL_3 + if(ec) EC_KEY_free(ec); - if(bn_ctx != NULL) { + if(bn_ctx) { BN_CTX_free(bn_ctx); } +#endif - if(octal_value != NULL) + if(octal_value) free(octal_value); if(rc == 0) return 0; - if(method_buf != NULL) + if(method_buf) LIBSSH2_FREE(session, method_buf); return -1; @@ -2400,12 +3587,20 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, int rc = 0; size_t curvelen, exponentlen, pointlen; unsigned char *curve, *exponent, *point_buf; - EC_KEY *ec_key = NULL; - BIGNUM *bn_exponent; + libssh2_ecdsa_ctx *ec_key = NULL; - _libssh2_debug(session, +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *fromdata_ctx = NULL; + OSSL_PARAM params[4]; + const char *n = EC_curve_nid2nist(curve_type); + char *group_name = NULL; +#else + BIGNUM *bn_exponent; +#endif + + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing ECDSA keys from private key data"); + "Computing ECDSA keys from private key data")); if(_libssh2_get_string(decrypted, &curve, &curvelen) || curvelen == 0) { @@ -2426,8 +3621,47 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, return -1; } - if((rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf, - pointlen, curve_type)) != 0) { +#ifdef USE_OPENSSL_3 + if(!n) + return -1; + + fromdata_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + + if(!fromdata_ctx) + goto fail; + + group_name = OPENSSL_zalloc(strlen(n) + 1); + + if(!group_name) + goto fail; + + memcpy(group_name, n, strlen(n)); + _libssh2_swap_bytes(exponent, (unsigned long)exponentlen); + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 0); + + params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + point_buf, pointlen); + + params[2] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PRIV_KEY, exponent, + exponentlen); + + params[3] = OSSL_PARAM_construct_end(); + + if(EVP_PKEY_fromdata_init(fromdata_ctx) <= 0) + goto fail; + + rc = EVP_PKEY_fromdata(fromdata_ctx, &ec_key, EVP_PKEY_KEYPAIR, params); + rc = rc != 1; + + if(group_name) + OPENSSL_clear_free(group_name, strlen(n)); +#else + rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, + point_buf, pointlen, + curve_type); + if(rc) { rc = -1; _libssh2_error(session, LIBSSH2_ERROR_PROTO, "ECDSA could not create key"); @@ -2435,42 +3669,205 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, } bn_exponent = BN_new(); - if(bn_exponent == NULL) { + if(!bn_exponent) { rc = -1; _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for private key data"); goto fail; } - BN_bin2bn(exponent, exponentlen, bn_exponent); + BN_bin2bn(exponent, (int) exponentlen, bn_exponent); rc = (EC_KEY_set_private_key(ec_key, bn_exponent) != 1); +#endif - if(rc == 0 && ec_key != NULL && pubkeydata != NULL && method != NULL) { + if(rc == 0 && ec_key && pubkeydata && method) { +#ifdef USE_OPENSSL_3 + EVP_PKEY *pk = ec_key; +#else EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(pk, ec_key); +#endif rc = gen_publickey_from_ec_evp(session, method, method_len, pubkeydata, pubkeydata_len, - pk); + 0, pk); +#ifndef USE_OPENSSL_3 if(pk) EVP_PKEY_free(pk); +#endif } - if(ec_ctx != NULL) +#ifdef USE_OPENSSL_3 + if(fromdata_ctx) + EVP_PKEY_CTX_free(fromdata_ctx); +#endif + + if(ec_ctx) *ec_ctx = ec_key; else - EC_KEY_free(ec_key); + _libssh2_ecdsa_free(ec_key); return rc; fail: - if(ec_key != NULL) - EC_KEY_free(ec_key); +#ifdef USE_OPENSSL_3 + if(fromdata_ctx) + EVP_PKEY_CTX_free(fromdata_ctx); +#endif + + if(ec_key) + _libssh2_ecdsa_free(ec_key); return rc; } +static int +gen_publickey_from_sk_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, + struct string_buf *decrypted, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + uint8_t *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + libssh2_ecdsa_ctx **ec_ctx) +{ + int rc = 0; + size_t curvelen, pointlen, key_len, app_len; + unsigned char *curve, *point_buf, *p, *key, *app; + libssh2_ecdsa_ctx *ec_key = NULL; + + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Extracting ECDSA-SK public key")); + + if(_libssh2_get_string(decrypted, &curve, &curvelen) || + curvelen == 0) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "ECDSA no curve"); + return -1; + } + + if(_libssh2_get_string(decrypted, &point_buf, &pointlen)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "ECDSA no point"); + return -1; + } + + rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, + point_buf, pointlen, + LIBSSH2_EC_CURVE_NISTP256); + if(rc) { + rc = -1; + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "ECDSA could not create key"); + goto fail; + } + + if(_libssh2_get_string(decrypted, &app, &app_len)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK application."); + goto fail; + } + + if(flags && _libssh2_get_byte(decrypted, flags)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK flags."); + goto fail; + } + + if(key_handle && handle_len) { + unsigned char *handle = NULL; + if(_libssh2_get_string(decrypted, &handle, handle_len)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK key_handle."); + goto fail; + } + + if(*handle_len > 0) { + *key_handle = LIBSSH2_ALLOC(session, *handle_len); + + if(*key_handle) { + memcpy((void *)*key_handle, handle, *handle_len); + } + } + } + + if(rc == 0 && ec_key && pubkeydata && method) { +#ifdef USE_OPENSSL_3 + EVP_PKEY *pk = ec_key; +#else + EVP_PKEY *pk = EVP_PKEY_new(); + EVP_PKEY_set1_EC_KEY(pk, ec_key); +#endif + + rc = gen_publickey_from_ec_evp(session, method, method_len, + pubkeydata, pubkeydata_len, + 1, pk); + +#ifndef USE_OPENSSL_3 + if(pk) + EVP_PKEY_free(pk); +#endif + } + + if(rc == 0 && pubkeydata) { + key_len = *pubkeydata_len + app_len + 4; + key = LIBSSH2_ALLOC(session, key_len); + + if(!key) { + rc = -1; + goto fail; + } + + p = key + *pubkeydata_len; + + memcpy(key, *pubkeydata, *pubkeydata_len); + _libssh2_store_str(&p, (const char *)app, app_len); + + if(application && app_len > 0) { + *application = (const char *)LIBSSH2_ALLOC(session, app_len + 1); + _libssh2_explicit_zero((void *)*application, app_len + 1); + memcpy((void *)*application, app, app_len); + } + + LIBSSH2_FREE(session, *pubkeydata); + *pubkeydata_len = key_len; + + if(pubkeydata) + *pubkeydata = key; + else if(key) + LIBSSH2_FREE(session, key); + } + + if(ec_ctx) + *ec_ctx = ec_key; + else + _libssh2_ecdsa_free(ec_key); + + return rc; + +fail: + if(ec_key) + _libssh2_ecdsa_free(ec_key); + + if(application && *application) { + LIBSSH2_FREE(session, (void *)application); + *application = NULL; + } + + if(key_handle && *key_handle) { + LIBSSH2_FREE(session, (void *)key_handle); + *key_handle = NULL; + } + + return rc; +} + + static int _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, LIBSSH2_SESSION * session, @@ -2483,9 +3880,9 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, libssh2_curve_type type; struct string_buf *decrypted = NULL; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); + "Session is required"); return -1; } @@ -2507,7 +3904,7 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -2517,8 +3914,75 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, if(rc == 0) { rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type, - decrypted, NULL, 0, - NULL, 0, ec_ctx); + decrypted, + NULL, NULL, + NULL, NULL, ec_ctx); + } + else { + rc = -1; + } + + if(decrypted) + _libssh2_string_buf_free(session, decrypted); + + return rc; +} + +static int +_libssh2_ecdsa_new_openssh_private_sk(libssh2_ecdsa_ctx ** ec_ctx, + uint8_t *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase) +{ + FILE *fp; + int rc; + unsigned char *buf = NULL; + struct string_buf *decrypted = NULL; + + if(!session) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Session is required"); + return -1; + } + + _libssh2_init_if_needed(); + + fp = fopen(filename, "r"); + if(!fp) { + _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to open OpenSSH ECDSA private key file"); + return -1; + } + + rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted); + fclose(fp); + if(rc) { + return rc; + } + + /* We have a new key file, now try and parse it using supported types */ + rc = _libssh2_get_string(decrypted, &buf, NULL); + + if(rc || !buf) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted key data not found"); + return -1; + } + + if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) { + rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, + decrypted, + NULL, NULL, + NULL, NULL, + flags, + application, + key_handle, + handle_len, + ec_ctx); } else { rc = -1; @@ -2537,12 +4001,18 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, { int rc; - pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_ec = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else + pem_read_bio_func read_ec = + (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; +#endif _libssh2_init_if_needed(); rc = read_private_key_from_file((void **) ec_ctx, read_ec, - filename, passphrase); + filename, passphrase); if(rc) { return _libssh2_ecdsa_new_openssh_private(ec_ctx, session, @@ -2552,6 +4022,46 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, return rc; } +int +_libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase) +{ + int rc; + +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_ec = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else + pem_read_bio_func read_ec = + (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; +#endif + + _libssh2_init_if_needed(); + + rc = read_private_key_from_file((void **) ec_ctx, read_ec, + filename, passphrase); + + if(rc) { + return _libssh2_ecdsa_new_openssh_private_sk(ec_ctx, + flags, + application, + key_handle, + handle_len, + session, + filename, + passphrase); + } + + return rc; +} + + /* * _libssh2_ecdsa_create_key * @@ -2570,8 +4080,51 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, int ret = 1; size_t octal_len = 0; unsigned char octal_value[EC_MAX_POINT_LEN]; + _libssh2_ec_key *private_key = NULL; + +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + + if(ctx && + EVP_PKEY_keygen_init(ctx) > 0 && + EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_type) > 0) { + ret = EVP_PKEY_keygen(ctx, &private_key); + } + + if(ret <= 0) { + goto clean_exit; + } + + if(out_private_key) + *out_private_key = private_key; + + ret = EVP_PKEY_get_octet_string_param(private_key, OSSL_PKEY_PARAM_PUB_KEY, + NULL, 0, &octal_len); + + if(ret <= 0) { + goto clean_exit; + } + + *out_public_key_octal = LIBSSH2_ALLOC(session, octal_len); + + if(!(*out_public_key_octal)) { + ret = -1; + goto clean_exit; + } + + ret = EVP_PKEY_get_octet_string_param(private_key, OSSL_PKEY_PARAM_PUB_KEY, + octal_value, octal_len, &octal_len); + + if(ret <= 0) { + goto clean_exit; + } + + memcpy(*out_public_key_octal, octal_value, octal_len); + + if(out_public_key_octal_len) + *out_public_key_octal_len = octal_len; +#else const EC_POINT *public_key = NULL; - EC_KEY *private_key = NULL; const EC_GROUP *group = NULL; /* create key */ @@ -2597,16 +4150,16 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, /* convert to octal */ if(EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, octal_value, octal_len, bn_ctx) != octal_len) { - ret = -1; - goto clean_exit; + ret = -1; + goto clean_exit; } - if(out_private_key != NULL) + if(out_private_key) *out_private_key = private_key; if(out_public_key_octal) { *out_public_key_octal = LIBSSH2_ALLOC(session, octal_len); - if(*out_public_key_octal == NULL) { + if(!*out_public_key_octal) { ret = -1; goto clean_exit; } @@ -2614,13 +4167,18 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, memcpy(*out_public_key_octal, octal_value, octal_len); } - if(out_public_key_octal_len != NULL) + if(out_public_key_octal_len) *out_public_key_octal_len = octal_len; +#endif /* USE_OPENSSL_3 */ clean_exit: - +#ifdef USE_OPENSSL_3 + if(ctx) + EVP_PKEY_CTX_free(ctx); +#else if(bn_ctx) BN_CTX_free(bn_ctx); +#endif return (ret == 1) ? 0 : -1; } @@ -2633,27 +4191,131 @@ clean_exit: int _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, - const unsigned char *server_public_key, size_t server_public_key_len) + const unsigned char *server_public_key, + size_t server_public_key_len) { int ret = 0; - int rc; + BN_CTX *bn_ctx = NULL; + +#ifdef USE_OPENSSL_3 + char *group_name = NULL; + size_t group_name_len = 0; + unsigned char *out_shared_key = NULL; + EVP_PKEY *peer_key = NULL, *server_key = NULL; + EVP_PKEY_CTX *key_fromdata_ctx = NULL; + EVP_PKEY_CTX *server_key_ctx = NULL; + OSSL_PARAM params[3]; + + size_t out_len = 0; + + if(!k || !(*k) || server_public_key_len <= 0) + return -1; + + bn_ctx = BN_CTX_new(); + if(!bn_ctx) + goto clean_exit; + + key_fromdata_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if(!key_fromdata_ctx) + goto clean_exit; + + ret = EVP_PKEY_get_utf8_string_param(private_key, + OSSL_PKEY_PARAM_GROUP_NAME, + NULL, 0, &group_name_len); + + if(ret <= 0) + goto clean_exit; + + group_name_len += 1; + group_name = OPENSSL_zalloc(group_name_len); + + if(!group_name) + goto clean_exit; + + ret = EVP_PKEY_get_utf8_string_param(private_key, + OSSL_PKEY_PARAM_GROUP_NAME, + group_name, group_name_len, + &group_name_len); + + if(ret <= 0) + goto clean_exit; + + out_shared_key = OPENSSL_malloc(server_public_key_len); + + if(!out_shared_key) + goto clean_exit; + + memcpy(out_shared_key, server_public_key, server_public_key_len); + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 0); + + params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + out_shared_key, + server_public_key_len); + + params[2] = OSSL_PARAM_construct_end(); + + ret = EVP_PKEY_fromdata_init(key_fromdata_ctx); + if(ret <= 0) + goto clean_exit; + + ret = EVP_PKEY_fromdata(key_fromdata_ctx, &peer_key, + EVP_PKEY_PUBLIC_KEY, params); + + if(ret <= 0) + goto clean_exit; + + server_key = private_key; + + if(!peer_key || !server_key) { + goto clean_exit; + } + + server_key_ctx = EVP_PKEY_CTX_new(server_key, NULL); + if(!server_key_ctx) { + goto clean_exit; + } + + ret = EVP_PKEY_derive_init(server_key_ctx); + if(ret <= 0) + goto clean_exit; + + ret = EVP_PKEY_derive_set_peer(server_key_ctx, peer_key); + if(ret <= 0) + goto clean_exit; + + ret = EVP_PKEY_derive(server_key_ctx, NULL, &out_len); + if(ret <= 0) + goto clean_exit; + + ret = EVP_PKEY_derive(server_key_ctx, out_shared_key, &out_len); + + if(ret == 1) { + BN_bin2bn(out_shared_key, (int)out_len, *k); + } + else { + ret = -1; + } +#else + int rc = -1; size_t secret_len; unsigned char *secret = NULL; const EC_GROUP *private_key_group; EC_POINT *server_public_key_point; - BN_CTX *bn_ctx = BN_CTX_new(); + bn_ctx = BN_CTX_new(); if(!bn_ctx) return -1; - if(k == NULL) + if(!k) return -1; private_key_group = EC_KEY_get0_group(private_key); server_public_key_point = EC_POINT_new(private_key_group); - if(server_public_key_point == NULL) + if(!server_public_key_point) return -1; rc = EC_POINT_oct2point(private_key_group, server_public_key_point, @@ -2678,20 +4340,35 @@ _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, goto clean_exit; } - BN_bin2bn(secret, secret_len, *k); + BN_bin2bn(secret, (int) secret_len, *k); +#endif clean_exit: +#ifdef USE_OPENSSL_3 + if(group_name) + OPENSSL_clear_free(group_name, group_name_len); - if(server_public_key_point != NULL) + if(out_shared_key) + OPENSSL_clear_free(out_shared_key, server_public_key_len); + + if(server_key_ctx) + EVP_PKEY_CTX_free(server_key_ctx); +#else + if(server_public_key_point) EC_POINT_free(server_public_key_point); - if(bn_ctx != NULL) + if(bn_ctx) BN_CTX_free(bn_ctx); - if(secret != NULL) + if(secret) free(secret); +#endif +#ifdef USE_OPENSSL_3 + return ret == 1 ? 0 : -1; +#else return ret; +#endif } @@ -2709,7 +4386,7 @@ _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, size_t sig_len = 0; unsigned char *sig = NULL; - if(md_ctx != NULL) { + if(md_ctx) { if(EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, ctx) != 1) goto clean_exit; if(EVP_DigestSign(md_ctx, NULL, &sig_len, message, message_len) != 1) @@ -2719,7 +4396,7 @@ _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, goto clean_exit; sig = LIBSSH2_CALLOC(session, sig_len); - if(sig == NULL) + if(!sig) goto clean_exit; rc = EVP_DigestSign(md_ctx, sig, &sig_len, message, message_len); @@ -2740,7 +4417,7 @@ clean_exit: if(md_ctx) EVP_MD_CTX_free(md_ctx); - return (rc == 1 ? 0 : -1); + return (rc == 1) ? 0 : -1; } int @@ -2755,11 +4432,11 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k, BN_CTX *bn_ctx = NULL; size_t out_len = 0; - if(k == NULL || *k == NULL) + if(!k || !*k) return -1; bn_ctx = BN_CTX_new(); - if(bn_ctx == NULL) + if(!bn_ctx) return -1; peer_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, @@ -2770,27 +4447,33 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k, private_key, LIBSSH2_ED25519_KEY_LEN); - if(peer_key == NULL || server_key == NULL) { - goto cleanExit; + if(!peer_key || !server_key) { + goto clean_exit; } server_key_ctx = EVP_PKEY_CTX_new(server_key, NULL); - if(server_key_ctx == NULL) { - goto cleanExit; + if(!server_key_ctx) { + goto clean_exit; } rc = EVP_PKEY_derive_init(server_key_ctx); - if(rc <= 0) goto cleanExit; + if(rc <= 0) { + goto clean_exit; + } rc = EVP_PKEY_derive_set_peer(server_key_ctx, peer_key); - if(rc <= 0) goto cleanExit; + if(rc <= 0) { + goto clean_exit; + } rc = EVP_PKEY_derive(server_key_ctx, NULL, &out_len); - if(rc <= 0) goto cleanExit; + if(rc <= 0) { + goto clean_exit; + } if(out_len != LIBSSH2_ED25519_KEY_LEN) { rc = -1; - goto cleanExit; + goto clean_exit; } rc = EVP_PKEY_derive(server_key_ctx, out_shared_key, &out_len); @@ -2802,7 +4485,7 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k, rc = -1; } -cleanExit: +clean_exit: if(server_key_ctx) EVP_PKEY_CTX_free(server_key_ctx); @@ -2810,7 +4493,7 @@ cleanExit: EVP_PKEY_free(peer_key); if(server_key) EVP_PKEY_free(server_key); - if(bn_ctx != NULL) + if(bn_ctx) BN_CTX_free(bn_ctx); return (rc == 1) ? 0 : -1; @@ -2824,7 +4507,7 @@ _libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s, int ret = -1; EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); - if(NULL == md_ctx) + if(!md_ctx) return -1; ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx); @@ -2833,7 +4516,7 @@ _libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s, ret = EVP_DigestVerify(md_ctx, s, s_len, m, m_len); - clean_exit: +clean_exit: EVP_MD_CTX_free(md_ctx); @@ -2856,7 +4539,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, struct string_buf *decrypted = NULL; int rc = 0; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); return -1; @@ -2883,7 +4566,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -2891,6 +4574,12 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, rc = -1; + /* Avoid unused variable warnings when all branches below are disabled */ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + #if LIBSSH2_ED25519 if(strcmp("ssh-ed25519", (const char *)buf) == 0) { rc = gen_publickey_from_ed25519_openssh_priv_data(session, decrypted, @@ -2937,7 +4626,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, if(decrypted) _libssh2_string_buf_free(session, decrypted); - if(rc != 0) { + if(rc) { _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unsupported OpenSSH key type"); } @@ -2960,24 +4649,24 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, int pktype; int rc; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Computing public key from private key file: %s", - privatekey); + privatekey)); bp = BIO_new_file(privatekey, "r"); - if(bp == NULL) { + if(!bp) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to extract public key from private key " "file: Unable to open private key file"); } - BIO_reset(bp); + (void)BIO_reset(bp); pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase); BIO_free(bp); - if(pk == NULL) { + if(!pk) { /* Try OpenSSH format */ rc = _libssh2_pub_priv_openssh_keyfile(session, @@ -2985,7 +4674,7 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, method_len, pubkeydata, pubkeydata_len, privatekey, passphrase); - if(rc != 0) { + if(rc) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to extract public key " @@ -3005,31 +4694,30 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, switch(pktype) { #if LIBSSH2_ED25519 - case EVP_PKEY_ED25519 : + case EVP_PKEY_ED25519: st = gen_publickey_from_ed_evp( session, method, method_len, pubkeydata, pubkeydata_len, pk); break; #endif /* LIBSSH2_ED25519 */ - case EVP_PKEY_RSA : +#if LIBSSH2_RSA + case EVP_PKEY_RSA: st = gen_publickey_from_rsa_evp( session, method, method_len, pubkeydata, pubkeydata_len, pk); break; - +#endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA - case EVP_PKEY_DSA : + case EVP_PKEY_DSA: st = gen_publickey_from_dsa_evp( session, method, method_len, pubkeydata, pubkeydata_len, pk); break; -#endif /* LIBSSH_DSA */ - +#endif /* LIBSSH2_DSA */ #if LIBSSH2_ECDSA - case EVP_PKEY_EC : + case EVP_PKEY_EC: st = gen_publickey_from_ec_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); + session, method, method_len, pubkeydata, pubkeydata_len, 0, pk); break; -#endif - - default : +#endif /* LIBSSH2_ECDSA */ + default: st = _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to extract public key " @@ -3058,14 +4746,14 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, unsigned char *buf = NULL; struct string_buf *decrypted = NULL; - if(key_ctx != NULL) + if(key_ctx) *key_ctx = NULL; - if(session == NULL) + if(!session) return _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); - if(key_type != NULL && (strlen(key_type) > 11 || strlen(key_type) < 7)) + if(key_type && (strlen(key_type) > 11 || strlen(key_type) < 7)) return _libssh2_error(session, LIBSSH2_ERROR_PROTO, "type is invalid"); @@ -3078,19 +4766,25 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, if(rc) return rc; - /* We have a new key file, now try and parse it using supported types */ - rc = _libssh2_get_string(decrypted, &buf, NULL); + /* We have a new key file, now try and parse it using supported types */ + rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) - return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted " - "key data not found"); + if(rc || !buf) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted " + "key data not found"); - rc = LIBSSH2_ERROR_FILE; + rc = LIBSSH2_ERROR_FILE; + + /* Avoid unused variable warnings when all branches below are disabled */ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; #if LIBSSH2_ED25519 if(strcmp("ssh-ed25519", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-ed25519", key_type) == 0) { + if(!key_type || strcmp("ssh-ed25519", key_type) == 0) { rc = gen_publickey_from_ed25519_openssh_priv_data(session, decrypted, method, @@ -3099,42 +4793,67 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, pubkeydata_len, (libssh2_ed25519_ctx**)key_ctx); } - } + } + + if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) { + if(!key_type || + strcmp("sk-ssh-ed25519@openssh.com", key_type) == 0) { + rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session, + decrypted, + method, + method_len, + pubkeydata, + pubkeydata_len, + NULL, NULL, + NULL, NULL, + (libssh2_ed25519_ctx**)key_ctx); + } + } #endif #if LIBSSH2_RSA if(strcmp("ssh-rsa", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-rsa", key_type) == 0) { + if(!key_type || strcmp("ssh-rsa", key_type) == 0) { rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted, method, method_len, pubkeydata, pubkeydata_len, - (libssh2_rsa_ctx**)key_ctx); + (libssh2_rsa_ctx**)key_ctx); } - } + } #endif #if LIBSSH2_DSA if(strcmp("ssh-dss", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-dss", key_type) == 0) { + if(!key_type || strcmp("ssh-dss", key_type) == 0) { rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted, - method, method_len, + method, method_len, pubkeydata, pubkeydata_len, - (libssh2_dsa_ctx**)key_ctx); + (libssh2_dsa_ctx**)key_ctx); } - } + } #endif #if LIBSSH2_ECDSA { - libssh2_curve_type type; + libssh2_curve_type type; - if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type) == 0) { - if(key_type == NULL || strcmp("ssh-ecdsa", key_type) == 0) { - rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type, - decrypted, + if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) { + rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, decrypted, method, method_len, pubkeydata, pubkeydata_len, - (libssh2_ecdsa_ctx**)key_ctx); + NULL, NULL, + NULL, NULL, + (libssh2_ecdsa_ctx**)key_ctx); + } + else if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type) + == 0) { + if(!key_type || strcmp("ssh-ecdsa", key_type) == 0) { + rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type, + decrypted, + method, method_len, + pubkeydata, + pubkeydata_len, + (libssh2_ecdsa_ctx**)key_ctx); } } } @@ -3151,19 +4870,117 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, return rc; } -int -read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session, - const char *key_type, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) +static int +_libssh2_sk_pub_openssh_keyfilememory(LIBSSH2_SESSION *session, + void **key_ctx, + const char *key_type, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + unsigned const char *passphrase) { - return _libssh2_pub_priv_openssh_keyfilememory(session, key_ctx, key_type, - NULL, NULL, NULL, NULL, - filedata, filedata_len, - passphrase); + int rc; + unsigned char *buf = NULL; + struct string_buf *decrypted = NULL; + + if(key_ctx) + *key_ctx = NULL; + + if(!session) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Session is required"); + + if(key_type && strlen(key_type) < 7) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "type is invalid"); + + _libssh2_init_if_needed(); + + rc = _libssh2_openssh_pem_parse_memory(session, passphrase, + privatekeydata, + privatekeydata_len, &decrypted); + + if(rc) + return rc; + + /* We have a new key file, now try and parse it using supported types */ + rc = _libssh2_get_string(decrypted, &buf, NULL); + + if(rc || !buf) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted " + "key data not found"); + + rc = LIBSSH2_ERROR_FILE; + + /* Avoid unused variable warnings when all branches below are disabled */ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)algorithm; + (void)flags; + (void)application; + (void)key_handle; + (void)handle_len; + +#if LIBSSH2_ED25519 + if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) { + *algorithm = LIBSSH2_HOSTKEY_TYPE_ED25519; + if(!key_type || + strcmp("sk-ssh-ed25519@openssh.com", key_type) == 0) { + rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session, + decrypted, + method, + method_len, + pubkeydata, + pubkeydata_len, + flags, + application, + key_handle, + handle_len, + (libssh2_ed25519_ctx**)key_ctx); + } + } +#endif +#if LIBSSH2_ECDSA + if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) { + *algorithm = LIBSSH2_HOSTKEY_TYPE_ECDSA_256; + rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, decrypted, + method, method_len, + pubkeydata, + pubkeydata_len, + flags, + application, + key_handle, + handle_len, + (libssh2_ecdsa_ctx**)key_ctx); + } +#endif + + if(rc == LIBSSH2_ERROR_FILE) + rc = _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public key from private key file: " + "invalid/unrecognized private key file format"); + + if(decrypted) + _libssh2_string_buf_free(session, decrypted); + + return rc; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define HAVE_SSLERROR_BAD_DECRYPT +#endif + int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, unsigned char **method, @@ -3178,21 +4995,31 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, BIO* bp; EVP_PKEY* pk; int pktype; +#ifdef HAVE_SSLERROR_BAD_DECRYPT + unsigned long sslError; +#endif - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing public key from private key."); + "Computing public key from private key.")); - bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len); +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL + bp = BIO_new_mem_buf(privatekeydata, (int)privatekeydata_len); +#else + bp = BIO_new_mem_buf((char *)privatekeydata, (int)privatekeydata_len); +#endif if(!bp) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory when" "computing public key"); - BIO_reset(bp); + (void)BIO_reset(bp); pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase); +#ifdef HAVE_SSLERROR_BAD_DECRYPT + sslError = ERR_get_error(); +#endif BIO_free(bp); - if(pk == NULL) { + if(!pk) { /* Try OpenSSH format */ st = _libssh2_pub_priv_openssh_keyfilememory(session, NULL, NULL, method, @@ -3201,10 +5028,23 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, pubkeydata_len, privatekeydata, privatekeydata_len, - (unsigned const char *)passphrase); - if(st != 0) - return st; - return 0; + (unsigned const char *)passphrase); + if(st == 0) + return 0; + +#ifdef HAVE_SSLERROR_BAD_DECRYPT + if((ERR_GET_LIB(sslError) == ERR_LIB_PEM && + ERR_GET_REASON(sslError) == PEM_R_BAD_DECRYPT) || + (ERR_GET_LIB(sslError) == ERR_LIB_PROV && + ERR_GET_REASON(sslError) == EVP_R_BAD_DECRYPT)) + return _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED, + "Wrong passphrase for private key"); +#endif + return _libssh2_error(session, + LIBSSH2_ERROR_FILE, + "Unable to extract public key " + "from private key file: " + "Unsupported private key file format"); } #ifdef HAVE_OPAQUE_STRUCTS @@ -3215,28 +5055,30 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, switch(pktype) { #if LIBSSH2_ED25519 - case EVP_PKEY_ED25519 : - st = gen_publickey_from_ed_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); + case EVP_PKEY_ED25519: + st = gen_publickey_from_ed_evp(session, method, method_len, + pubkeydata, pubkeydata_len, pk); break; #endif /* LIBSSH2_ED25519 */ - case EVP_PKEY_RSA : +#if LIBSSH2_RSA + case EVP_PKEY_RSA: st = gen_publickey_from_rsa_evp(session, method, method_len, pubkeydata, pubkeydata_len, pk); break; +#endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA - case EVP_PKEY_DSA : + case EVP_PKEY_DSA: st = gen_publickey_from_dsa_evp(session, method, method_len, pubkeydata, pubkeydata_len, pk); break; -#endif /* LIBSSH_DSA */ +#endif /* LIBSSH2_DSA */ #if LIBSSH2_ECDSA - case EVP_PKEY_EC : + case EVP_PKEY_EC: st = gen_publickey_from_ec_evp(session, method, method_len, - pubkeydata, pubkeydata_len, pk); + pubkeydata, pubkeydata_len, 0, pk); break; #endif /* LIBSSH2_ECDSA */ - default : + default: st = _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to extract public key " @@ -3249,6 +5091,62 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, return st; } +int +_libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) +{ + int st = -1; + BIO* bp; + EVP_PKEY* pk; + + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing public key from private key.")); + +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL + bp = BIO_new_mem_buf(privatekeydata, (int)privatekeydata_len); +#else + bp = BIO_new_mem_buf((char *)privatekeydata, (int)privatekeydata_len); +#endif + if(!bp) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory when" + "computing public key"); + (void)BIO_reset(bp); + pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase); + BIO_free(bp); + + if(!pk) { + /* Try OpenSSH format */ + st = _libssh2_sk_pub_openssh_keyfilememory(session, NULL, NULL, + method, + method_len, + pubkeydata, + pubkeydata_len, + algorithm, + flags, + application, + key_handle, + handle_len, + privatekeydata, + privatekeydata_len, + (unsigned const char *)passphrase); + } + + return st; +} + void _libssh2_dh_init(_libssh2_dh_ctx *dhctx) { @@ -3283,4 +5181,45 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) *dhctx = NULL; } -#endif /* LIBSSH2_OPENSSL */ +int +_libssh2_bn_from_bin(_libssh2_bn *bn, size_t len, const unsigned char *val) +{ + if(!BN_bin2bn(val, (int)len, bn)) { + return -1; + } + + return 0; +} + +/* _libssh2_supported_key_sign_algorithms + * + * Return supported key hash algo upgrades, see crypto.h + * + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len) +{ + (void)session; + +#if LIBSSH2_RSA_SHA2 + if((key_method_len == 7 && + memcmp(key_method, "ssh-rsa", key_method_len) == 0) || + (key_method_len == 28 && + memcmp(key_method, "ssh-rsa-cert-v01@openssh.com", + key_method_len) == 0) + ) { + return "rsa-sha2-512,rsa-sha2-256" +#if LIBSSH2_RSA_SHA1 + ",ssh-rsa" +#endif + ; + } +#endif + + return NULL; +} + +#endif /* LIBSSH2_CRYPTO_C */ diff --git a/uppsrc/Core/SSH/libssh2/openssl.h b/uppsrc/Core/SSH/libssh2/openssl.h index 658b040d6..e41c1df47 100644 --- a/uppsrc/Core/SSH/libssh2/openssl.h +++ b/uppsrc/Core/SSH/libssh2/openssl.h @@ -1,9 +1,8 @@ -#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. - * - * Author: Simon Josefsson +#ifndef LIBSSH2_OPENSSL_H +#define LIBSSH2_OPENSSL_H +/* Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -37,8 +36,64 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ +#define LIBSSH2_CRYPTO_ENGINE libssh2_openssl + +/* disable deprecated warnings in OpenSSL 3 */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#ifdef LIBSSH2_WOLFSSL + +#include +#include + +#if defined(NO_DSA) || defined(HAVE_FIPS) +#define OPENSSL_NO_DSA +#endif + +#if defined(NO_MD5) || defined(HAVE_FIPS) +#define OPENSSL_NO_MD5 +#endif + +#if !defined(WOLFSSL_RIPEMD) || defined(HAVE_FIPS) +#define OPENSSL_NO_RIPEMD +#endif + +#if defined(NO_RC4) || defined(HAVE_FIPS) +#define OPENSSL_NO_RC4 +#endif + +#ifdef NO_DES3 +#define OPENSSL_NO_DES +#endif + +/* wolfSSL doesn't support Blowfish or CAST. */ +#define OPENSSL_NO_BF +#define OPENSSL_NO_CAST +/* wolfSSL has no engine framework. */ +#define OPENSSL_NO_ENGINE + +#include +#include +#include +#ifndef OPENSSL_NO_DSA +#include +#endif +#ifndef OPENSSL_NO_MD5 +#include +#endif +#include +#include +#include +#include +#include +#include + +#else /* !LIBSSH2_WOLFSSL */ + #include #include #include @@ -51,21 +106,37 @@ #ifndef OPENSSL_NO_MD5 #include #endif +#include #include #include #include #include #include -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define USE_OPENSSL_3 1 +#include +#endif + +#endif /* LIBSSH2_WOLFSSL */ + +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(LIBRESSL_VERSION_NUMBER)) || defined(LIBSSH2_WOLFSSL) || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER >= 0x3050000fL) +/* For wolfSSL, whether the structs are truly opaque or not, it's best to not + * rely on their internal data members being exposed publicly. */ # define HAVE_OPAQUE_STRUCTS 1 #endif #ifdef OPENSSL_NO_RSA # define LIBSSH2_RSA 0 +# define LIBSSH2_RSA_SHA1 0 +# define LIBSSH2_RSA_SHA2 0 #else # define LIBSSH2_RSA 1 +# define LIBSSH2_RSA_SHA1 1 +# define LIBSSH2_RSA_SHA2 1 #endif #ifdef OPENSSL_NO_DSA @@ -74,14 +145,16 @@ # define LIBSSH2_DSA 1 #endif -#ifdef OPENSSL_NO_ECDSA +#if defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_EC) # define LIBSSH2_ECDSA 0 #else # define LIBSSH2_ECDSA 1 #endif -#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ -!defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER)) || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER >= 0x3070000fL) # define LIBSSH2_ED25519 1 #else # define LIBSSH2_ED25519 0 @@ -94,7 +167,7 @@ # define LIBSSH2_MD5 1 #endif -#ifdef OPENSSL_NO_RIPEMD +#if defined(OPENSSL_NO_RIPEMD) || defined(OPENSSL_NO_RMD160) # define LIBSSH2_HMAC_RIPEMD 0 #else # define LIBSSH2_HMAC_RIPEMD 1 @@ -103,12 +176,24 @@ #define LIBSSH2_HMAC_SHA256 1 #define LIBSSH2_HMAC_SHA512 1 -#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) +#if (OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)) || \ + (defined(LIBSSH2_WOLFSSL) && defined(WOLFSSL_AES_COUNTER)) # define LIBSSH2_AES_CTR 1 -# define LIBSSH2_AES 1 +# define LIBSSH2_AES_CBC 1 #else # define LIBSSH2_AES_CTR 0 -# define LIBSSH2_AES 0 +# define LIBSSH2_AES_CBC 0 +#endif + +/* wolfSSL v5.4.0 is required due to possibly this bug: + https://github.com/wolfSSL/wolfssl/pull/5205 + Before this release, all libssh2 tests crash with AES-GCM enabled */ +#if (OPENSSL_VERSION_NUMBER >= 0x01010100fL && !defined(OPENSSL_NO_AES)) || \ + (defined(LIBSSH2_WOLFSSL) && LIBWOLFSSL_VERSION_HEX >= 0x05004000 && \ + defined(HAVE_AESGCM) && defined(WOLFSSL_AESGCM_STREAM)) +# define LIBSSH2_AES_GCM 1 +#else +# define LIBSSH2_AES_GCM 0 #endif #ifdef OPENSSL_NO_BF @@ -135,9 +220,12 @@ # define LIBSSH2_3DES 1 #endif +#include "crypto_config.h" + #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) -#define _libssh2_random(buf, len) (RAND_bytes((buf), (len)) == 1 ? 0 : -1) +#define _libssh2_random(buf, len) \ + _libssh2_openssl_random((buf), (len)) #define libssh2_prepare_iovec(vec, len) /* Empty. */ @@ -149,19 +237,15 @@ /* returns 0 in case of failure */ int _libssh2_sha1_init(libssh2_sha1_ctx *ctx); -#define libssh2_sha1_init(x) _libssh2_sha1_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_sha1_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha1_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif -int _libssh2_sha1(const unsigned char *message, unsigned long len, +int _libssh2_sha1_update(libssh2_sha1_ctx *ctx, + const void *data, size_t len); +int _libssh2_sha1_final(libssh2_sha1_ctx *ctx, unsigned char *out); +int _libssh2_sha1(const unsigned char *message, size_t len, unsigned char *out); +#define libssh2_sha1_init(x) _libssh2_sha1_init(x) +#define libssh2_sha1_update(ctx, data, len) \ + _libssh2_sha1_update(&(ctx), data, len) +#define libssh2_sha1_final(ctx, out) _libssh2_sha1_final(&(ctx), out) #define libssh2_sha1(x,y,z) _libssh2_sha1(x,y,z) #ifdef HAVE_OPAQUE_STRUCTS @@ -172,20 +256,15 @@ int _libssh2_sha1(const unsigned char *message, unsigned long len, /* returns 0 in case of failure */ int _libssh2_sha256_init(libssh2_sha256_ctx *ctx); +int _libssh2_sha256_update(libssh2_sha256_ctx *ctx, + const void *data, size_t len); +int _libssh2_sha256_final(libssh2_sha256_ctx *ctx, unsigned char *out); +int _libssh2_sha256(const unsigned char *message, size_t len, + unsigned char *out); #define libssh2_sha256_init(x) _libssh2_sha256_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha256_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_sha256_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else #define libssh2_sha256_update(ctx, data, len) \ - EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha256_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif -int _libssh2_sha256(const unsigned char *message, unsigned long len, - unsigned char *out); + _libssh2_sha256_update(&(ctx), data, len) +#define libssh2_sha256_final(ctx, out) _libssh2_sha256_final(&(ctx), out) #define libssh2_sha256(x,y,z) _libssh2_sha256(x,y,z) #ifdef HAVE_OPAQUE_STRUCTS @@ -196,20 +275,15 @@ int _libssh2_sha256(const unsigned char *message, unsigned long len, /* returns 0 in case of failure */ int _libssh2_sha384_init(libssh2_sha384_ctx *ctx); -#define libssh2_sha384_init(x) _libssh2_sha384_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha384_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_sha384_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_sha384_update(ctx, data, len) \ - EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha384_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif -int _libssh2_sha384(const unsigned char *message, unsigned long len, +int _libssh2_sha384_update(libssh2_sha384_ctx *ctx, + const void *data, size_t len); +int _libssh2_sha384_final(libssh2_sha384_ctx *ctx, unsigned char *out); +int _libssh2_sha384(const unsigned char *message, size_t len, unsigned char *out); +#define libssh2_sha384_init(x) _libssh2_sha384_init(x) +#define libssh2_sha384_update(ctx, data, len) \ + _libssh2_sha384_update(&(ctx), data, len) +#define libssh2_sha384_final(ctx, out) _libssh2_sha384_final(&(ctx), out) #define libssh2_sha384(x,y,z) _libssh2_sha384(x,y,z) #ifdef HAVE_OPAQUE_STRUCTS @@ -220,22 +294,18 @@ int _libssh2_sha384(const unsigned char *message, unsigned long len, /* returns 0 in case of failure */ int _libssh2_sha512_init(libssh2_sha512_ctx *ctx); -#define libssh2_sha512_init(x) _libssh2_sha512_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_sha512_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_sha512_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_sha512_update(ctx, data, len) \ - EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_sha512_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif -int _libssh2_sha512(const unsigned char *message, unsigned long len, +int _libssh2_sha512_update(libssh2_sha512_ctx *ctx, + const void *data, size_t len); +int _libssh2_sha512_final(libssh2_sha512_ctx *ctx, unsigned char *out); +int _libssh2_sha512(const unsigned char *message, size_t len, unsigned char *out); +#define libssh2_sha512_init(x) _libssh2_sha512_init(x) +#define libssh2_sha512_update(ctx, data, len) \ + _libssh2_sha512_update(&(ctx), data, len) +#define libssh2_sha512_final(ctx, out) _libssh2_sha512_final(&(ctx), out) #define libssh2_sha512(x,y,z) _libssh2_sha512(x,y,z) +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM #ifdef HAVE_OPAQUE_STRUCTS #define libssh2_md5_ctx EVP_MD_CTX * #else @@ -244,74 +314,63 @@ int _libssh2_sha512(const unsigned char *message, unsigned long len, /* returns 0 in case of failure */ int _libssh2_md5_init(libssh2_md5_ctx *ctx); +int _libssh2_md5_update(libssh2_md5_ctx *ctx, + const void *data, size_t len); +int _libssh2_md5_final(libssh2_md5_ctx *ctx, unsigned char *out); #define libssh2_md5_init(x) _libssh2_md5_init(x) -#ifdef HAVE_OPAQUE_STRUCTS -#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len) -#define libssh2_md5_final(ctx, out) do { \ - EVP_DigestFinal(ctx, out, NULL); \ - EVP_MD_CTX_free(ctx); \ - } while(0) -#else -#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) -#define libssh2_md5_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) -#endif +#define libssh2_md5_update(ctx, data, len) \ + _libssh2_md5_update(&(ctx), data, len) +#define libssh2_md5_final(ctx, out) _libssh2_md5_final(&(ctx), out) +#endif /* LIBSSH2_MD5 || LIBSSH2_MD5_PEM */ -#ifdef HAVE_OPAQUE_STRUCTS +#ifdef USE_OPENSSL_3 +#define libssh2_hmac_ctx EVP_MAC_CTX * +#elif defined(HAVE_OPAQUE_STRUCTS) #define libssh2_hmac_ctx HMAC_CTX * -#define libssh2_hmac_ctx_init(ctx) ctx = HMAC_CTX_new() -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha1(), NULL) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_md5(), NULL) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_ripemd160(), NULL) -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha256(), NULL) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha512(), NULL) - -#define libssh2_hmac_update(ctx, data, datalen) \ - HMAC_Update(ctx, data, datalen) -#define libssh2_hmac_final(ctx, data) HMAC_Final(ctx, data, NULL) -#define libssh2_hmac_cleanup(ctx) HMAC_CTX_free(*(ctx)) -#else +#else /* !HAVE_OPAQUE_STRUCTS */ #define libssh2_hmac_ctx HMAC_CTX -#define libssh2_hmac_ctx_init(ctx) \ - HMAC_CTX_init(&ctx) -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha1(), NULL) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_md5(), NULL) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_ripemd160(), NULL) -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha256(), NULL) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha512(), NULL) - -#define libssh2_hmac_update(ctx, data, datalen) \ - HMAC_Update(&(ctx), data, datalen) -#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL) -#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx) -#endif +#endif /* USE_OPENSSL_3 */ extern void _libssh2_openssl_crypto_init(void); extern void _libssh2_openssl_crypto_exit(void); #define libssh2_crypto_init() _libssh2_openssl_crypto_init() #define libssh2_crypto_exit() _libssh2_openssl_crypto_exit() +#if LIBSSH2_RSA + +#ifdef USE_OPENSSL_3 +#define libssh2_rsa_ctx EVP_PKEY +#define _libssh2_rsa_free(rsactx) EVP_PKEY_free(rsactx) +#else #define libssh2_rsa_ctx RSA - #define _libssh2_rsa_free(rsactx) RSA_free(rsactx) +#endif +#endif /* LIBSSH2_RSA */ + +#if LIBSSH2_DSA + +#ifdef USE_OPENSSL_3 +#define libssh2_dsa_ctx EVP_PKEY +#define _libssh2_dsa_free(rsactx) EVP_PKEY_free(rsactx) +#else #define libssh2_dsa_ctx DSA - #define _libssh2_dsa_free(dsactx) DSA_free(dsactx) +#endif + +#endif /* LIBSSH2_DSA */ #if LIBSSH2_ECDSA + +#ifdef USE_OPENSSL_3 +#define libssh2_ecdsa_ctx EVP_PKEY +#define _libssh2_ecdsa_free(ecdsactx) EVP_PKEY_free(ecdsactx) +#define _libssh2_ec_key EVP_PKEY +#else #define libssh2_ecdsa_ctx EC_KEY #define _libssh2_ecdsa_free(ecdsactx) EC_KEY_free(ecdsactx) #define _libssh2_ec_key EC_KEY +#endif typedef enum { LIBSSH2_EC_CURVE_NISTP256 = NID_X9_62_prime256v1, @@ -319,15 +378,14 @@ typedef enum { LIBSSH2_EC_CURVE_NISTP521 = NID_secp521r1 } libssh2_curve_type; -#else +#else /* !LIBSSH2_ECDSA */ #define _libssh2_ec_key void #endif /* LIBSSH2_ECDSA */ #if LIBSSH2_ED25519 #define libssh2_ed25519_ctx EVP_PKEY - #define _libssh2_ed25519_free(ctx) EVP_PKEY_free(ctx) -#endif /* ED25519 */ +#endif /* LIBSSH2_ED25519 */ #define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void) #ifdef HAVE_OPAQUE_STRUCTS @@ -336,22 +394,20 @@ libssh2_curve_type; #define _libssh2_cipher_ctx EVP_CIPHER_CTX #endif +#define _libssh2_cipher_aes256gcm EVP_aes_256_gcm +#define _libssh2_cipher_aes128gcm EVP_aes_128_gcm + #define _libssh2_cipher_aes256 EVP_aes_256_cbc #define _libssh2_cipher_aes192 EVP_aes_192_cbc #define _libssh2_cipher_aes128 EVP_aes_128_cbc -#ifdef HAVE_EVP_AES_128_CTR #define _libssh2_cipher_aes128ctr EVP_aes_128_ctr #define _libssh2_cipher_aes192ctr EVP_aes_192_ctr #define _libssh2_cipher_aes256ctr EVP_aes_256_ctr -#else -#define _libssh2_cipher_aes128ctr _libssh2_EVP_aes_128_ctr -#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr -#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr -#endif #define _libssh2_cipher_blowfish EVP_bf_cbc #define _libssh2_cipher_arcfour EVP_rc4 #define _libssh2_cipher_cast5 EVP_cast5_cbc #define _libssh2_cipher_3des EVP_des_ede3_cbc +#define _libssh2_cipher_chacha20 NULL #ifdef HAVE_OPAQUE_STRUCTS #define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_free(*(ctx)) @@ -365,19 +421,28 @@ libssh2_curve_type; #define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx) #define _libssh2_bn_init() BN_new() #define _libssh2_bn_init_from_bin() _libssh2_bn_init() -#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val) -#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn) -#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val) +#define _libssh2_bn_set_word(bn, val) !BN_set_word(bn, val) +extern int _libssh2_bn_from_bin(_libssh2_bn *bn, size_t len, + const unsigned char *v); +#define _libssh2_bn_to_bin(bn, val) (BN_bn2bin(bn, val) <= 0) #define _libssh2_bn_bytes(bn) BN_num_bytes(bn) #define _libssh2_bn_bits(bn) BN_num_bits(bn) #define _libssh2_bn_free(bn) BN_clear_free(bn) +/* Default generate and safe prime sizes for + diffie-hellman-group-exchange-sha1 */ +#define LIBSSH2_DH_GEX_MINGROUP 2048 +#define LIBSSH2_DH_GEX_OPTGROUP 4096 +#define LIBSSH2_DH_GEX_MAXGROUP 8192 + +#define LIBSSH2_DH_MAX_MODULUS_BITS 16384 + #define _libssh2_dh_ctx BIGNUM * #define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) #define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) + _libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) #define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p, bnctx) + _libssh2_dh_secret(dhctx, secret, f, p, bnctx) #define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx); extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, @@ -389,8 +454,10 @@ extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, _libssh2_bn_ctx *bnctx); extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); +extern int _libssh2_openssl_random(void *buf, size_t len); + const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void); const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void); const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void); -#endif /* __LIBSSH2_OPENSSL_H */ +#endif /* LIBSSH2_OPENSSL_H */ diff --git a/uppsrc/Core/SSH/libssh2/os400qc3.c b/uppsrc/Core/SSH/libssh2/os400qc3.c new file mode 100644 index 000000000..9ec9b0360 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/os400qc3.c @@ -0,0 +1,2535 @@ +/* + * Copyright (C) Patrick Monnerat + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */ + +#include + +#include +#include +#include + +#include + + +#ifdef OS400_DEBUG +/* In debug mode, all system library errors cause an exception. */ +#define set_EC_length(ec, length) ((ec).Bytes_Provided = \ + (ec).Bytes_Available = 0) +#else +#define set_EC_length(ec, length) ((ec).Bytes_Provided = (length)) +#endif + + +/* Ensure va_list operations are not on an array. */ +typedef struct { + va_list list; +} valiststr; + + +typedef int (*loadkeyproc)(LIBSSH2_SESSION *session, + const unsigned char *data, unsigned int datalen, + const unsigned char *passphrase, void *loadkeydata); + +/* Public key extraction data. */ +typedef struct { + const char * method; + const unsigned char * data; + unsigned int length; +} loadpubkeydata; + + +/* Support for ASN.1 elements. */ + +typedef struct { + char * header; /* Pointer to header byte. */ + char * beg; /* Pointer to element data. */ + char * end; /* Pointer to 1st byte after element. */ + unsigned char class; /* ASN.1 element class. */ + unsigned char tag; /* ASN.1 element tag. */ + unsigned char constructed; /* Element is constructed. */ +} asn1Element; + +#define ASN1_INTEGER 2 +#define ASN1_BIT_STRING 3 +#define ASN1_OCTET_STRING 4 +#define ASN1_NULL 5 +#define ASN1_OBJ_ID 6 +#define ASN1_SEQ 16 + +#define ASN1_CONSTRUCTED 0x20 + +/* rsaEncryption OID: 1.2.840.113549.1.1.1 */ +static unsigned char OID_rsaEncryption[] = + {9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 1, 1, 1}; +static int sshrsapubkey(LIBSSH2_SESSION *session, char **sshpubkey, + asn1Element *params, asn1Element *key, + const char *method); + +#if LIBSSH2_DSA != 0 +/* dsaEncryption OID: 1.2.840.10040.4.1 */ +static unsigned char OID_dsaEncryption[] = + {7, 40 + 2, 0x86, 0x48, 0xCE, 0x38, 4, 1}; +static int sshdsapubkey(LIBSSH2_SESSION *session, char **sshpubkey, + asn1Element *params, asn1Element *key, + const char *method); +#endif + +static unsigned char OID_dhKeyAgreement[] = + {9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 1, 3, 1}; + + +/* PKCS#5 support. */ + +typedef struct pkcs5params pkcs5params; +struct pkcs5params { + int cipher; /* Encryption cipher. */ + int blocksize; /* Cipher block size. */ + char mode; /* Block encryption mode. */ + char padopt; /* Pad option. */ + char padchar; /* Pad character. */ + int (*kdf)(LIBSSH2_SESSION *session, char **dk, + const unsigned char *passphrase, pkcs5params *pkcs5); + int hash; /* KDF hash algorithm. */ + size_t hashlen; /* KDF hash digest length. */ + char * salt; /* Salt. */ + size_t saltlen; /* Salt length. */ + char * iv; /* Initialization vector. */ + size_t ivlen; /* Initialization vector length. */ + int itercount; /* KDF iteration count. */ + int dklen; /* Derived key length (#bytes). */ + int effkeysize; /* RC2 effective key size (#bits) or 0. */ +}; + +typedef struct pkcs5algo pkcs5algo; +struct pkcs5algo { + const unsigned char * oid; + int (*parse)(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param); + int cipher; /* Encryption cipher. */ + size_t blocksize; /* Cipher block size. */ + char mode; /* Block encryption mode. */ + char padopt; /* Pad option. */ + char padchar; /* Pad character. */ + size_t keylen; /* Key length (#bytes). */ + int hash; /* Hash algorithm. */ + size_t hashlen; /* Hash digest length. */ + size_t saltlen; /* Salt length. */ + size_t ivlen; /* Initialisation vector length. */ + int effkeysize; /* RC2 effective key size (#bits) or 0. */ +}; + +/* id-PBES2 OID: 1.2.840.113549.1.5.13 */ +static const unsigned char OID_id_PBES2[] = { + 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0D +}; +static int parse_pbes2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param); +static const pkcs5algo PBES2 = { + OID_id_PBES2, parse_pbes2, 0, 0, '\0', '\0', '\0', 0, + 0, 0, 0, 0, 0 +}; + +/* id-PBKDF2 OID: 1.2.840.113549.1.5.12 */ +static const unsigned char OID_id_PBKDF2[] = { + 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C +}; +static int parse_pbkdf2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param); +static const pkcs5algo PBKDF2 = { + OID_id_PBKDF2, parse_pbkdf2, 0, 0, '\0', '\0', '\0', + SHA_DIGEST_LENGTH, Qc3_SHA1, SHA_DIGEST_LENGTH, 8, 8, 0 +}; + +/* id-hmacWithSHA1 OID: 1.2.840.113549.2.7 */ +static const unsigned char OID_id_hmacWithSHA1[] = { + 8, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07 +}; +static int parse_hmacWithSHA1(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param); +static const pkcs5algo hmacWithSHA1 = { + OID_id_hmacWithSHA1, parse_hmacWithSHA1, 0, 0, '\0', '\0', '\0', + SHA_DIGEST_LENGTH, Qc3_SHA1, SHA_DIGEST_LENGTH, 8, 8, 0 +}; + +/* desCBC OID: 1.3.14.3.2.7 */ +static const unsigned char OID_desCBC[] = {5, 40 + 3, 0x0E, 0x03, 0x02, 0x07}; +static int parse_iv(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param); +static const pkcs5algo desCBC = { + OID_desCBC, parse_iv, Qc3_DES, 8, Qc3_CBC, Qc3_Pad_Counter, + '\0', 8, 0, 0, 8, 8, 0 +}; + +/* des-EDE3-CBC OID: 1.2.840.113549.3.7 */ +static const unsigned char OID_des_EDE3_CBC[] = { + 8, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07 +}; +static const pkcs5algo des_EDE3_CBC = { + OID_des_EDE3_CBC, parse_iv, Qc3_TDES, 8, Qc3_CBC, Qc3_Pad_Counter, + '\0', 24, 0, 0, 8, 8, 0 +}; + +/* rc2CBC OID: 1.2.840.113549.3.2 */ +static const unsigned char OID_rc2CBC[] = { + 8, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x02 +}; +static int parse_rc2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param); +static const pkcs5algo rc2CBC = { + OID_rc2CBC, parse_rc2, Qc3_RC2, 8, Qc3_CBC, Qc3_Pad_Counter, + '\0', 0, 0, 0, 8, 0, 32 +}; + +static int parse_pbes1(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param); + +#if LIBSSH2_MD5 +/* pbeWithMD5AndDES-CBC OID: 1.2.840.113549.1.5.3 */ +static const unsigned char OID_pbeWithMD5AndDES_CBC[] = { + 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x03 +}; +static const pkcs5algo pbeWithMD5AndDES_CBC = { + OID_pbeWithMD5AndDES_CBC, parse_pbes1, Qc3_DES, 8, Qc3_CBC, + Qc3_Pad_Counter, '\0', 8, Qc3_MD5, MD5_DIGEST_LENGTH, 8, 0, 0 +}; + +/* pbeWithMD5AndRC2-CBC OID: 1.2.840.113549.1.5.6 */ +static const unsigned char OID_pbeWithMD5AndRC2_CBC[] = { + 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x06 +}; +static const pkcs5algo pbeWithMD5AndRC2_CBC = { + OID_pbeWithMD5AndRC2_CBC, parse_pbes1, Qc3_RC2, 8, Qc3_CBC, + Qc3_Pad_Counter, '\0', 0, Qc3_MD5, MD5_DIGEST_LENGTH, 8, 0, 64 +}; +#endif + +/* pbeWithSHA1AndDES-CBC OID: 1.2.840.113549.1.5.10 */ +static const unsigned char OID_pbeWithSHA1AndDES_CBC[] = { + 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0A +}; +static const pkcs5algo pbeWithSHA1AndDES_CBC = { + OID_pbeWithSHA1AndDES_CBC, parse_pbes1, Qc3_DES, 8, Qc3_CBC, + Qc3_Pad_Counter, '\0', 8, Qc3_SHA1, SHA_DIGEST_LENGTH, 8, 0, 0 +}; + +/* pbeWithSHA1AndRC2-CBC OID: 1.2.840.113549.1.5.11 */ +static const unsigned char OID_pbeWithSHA1AndRC2_CBC[] = { + 9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0B +}; +static const pkcs5algo pbeWithSHA1AndRC2_CBC = { + OID_pbeWithSHA1AndRC2_CBC, parse_pbes1, Qc3_RC2, 8, Qc3_CBC, + Qc3_Pad_Counter, '\0', 0, Qc3_SHA1, SHA_DIGEST_LENGTH, 8, 0, 64 +}; + +/* rc5-CBC-PAD OID: 1.2.840.113549.3.9: RC5 not implemented in Qc3. */ +/* pbeWithMD2AndDES-CBC OID: 1.2.840.113549.1.5.1: MD2 not implemented. */ +/* pbeWithMD2AndRC2-CBC OID: 1.2.840.113549.1.5.4: MD2 not implemented. */ + +static const pkcs5algo * pbestable[] = { +#if LIBSSH2_MD5 + &pbeWithMD5AndDES_CBC, + &pbeWithMD5AndRC2_CBC, +#endif + &pbeWithSHA1AndDES_CBC, + &pbeWithSHA1AndRC2_CBC, + &PBES2, + NULL +}; + +static const pkcs5algo * pbkdf2table[] = { + &PBKDF2, + NULL +}; + +static const pkcs5algo * pbes2enctable[] = { + &desCBC, + &des_EDE3_CBC, + &rc2CBC, + NULL +}; + +static const pkcs5algo * kdf2prftable[] = { + &hmacWithSHA1, + NULL +}; + + +/* Public key extraction support. */ +static struct { + unsigned char *oid; + int (*sshpubkey)(LIBSSH2_SESSION *session, char **pubkey, + asn1Element *params, asn1Element *key, + const char *method); + const char * method; +} pka[] = { +#if LIBSSH2_RSA != 0 + { OID_rsaEncryption, sshrsapubkey, "ssh-rsa" }, +#endif +#if LIBSSH2_DSA != 0 + { OID_dsaEncryption, sshdsapubkey, "ssh-dss" }, +#endif + { NULL, NULL, NULL } +}; + +/* Define ASCII strings. */ +static const char beginencprivkeyhdr[] = + "-----BEGIN ENCRYPTED PRIVATE KEY-----"; +static const char endencprivkeyhdr[] = "-----END ENCRYPTED PRIVATE KEY-----"; +static const char beginprivkeyhdr[] = "-----BEGIN PRIVATE KEY-----"; +static const char endprivkeyhdr[] = "-----END PRIVATE KEY-----"; +static const char beginrsaprivkeyhdr[] = "-----BEGIN RSA PRIVATE KEY-----"; +static const char endrsaprivkeyhdr[] = "-----END RSA PRIVATE KEY-----"; +static const char fopenrmode[] = "r"; +static const char fopenrbmode[] = "rb"; + + +/* The rest of character literals in this module are in EBCDIC. */ +#pragma convert(37) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static Qc3_Format_KEYD0100_T nulltoken = {""}; + +static int zero = 0; +static int rsaprivate[] = { Qc3_RSA_Private }; +static char anycsp[] = { Qc3_Any_CSP }; +static char binstring[] = { Qc3_Bin_String }; +static char berstring[] = { Qc3_BER_String }; +static char qc3clear[] = { Qc3_Clear }; + +static const Qus_EC_t ecnull = {0}; /* Error causes an exception. */ + +static asn1Element lastbytebitcount = { + (char *) &zero, NULL, (char *) &zero + 1 +}; + + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: big numbers support. + * + *******************************************************************/ + +int +_libssh2_random(unsigned char *buf, size_t len) +{ + Qus_EC_t errcode; + + set_EC_length(errcode, sizeof(errcode)); + Qc3GenPRNs(buf, len, + Qc3PRN_TYPE_NORMAL, Qc3PRN_NO_PARITY, (char *) &errcode); + return errcode.Bytes_Available ? -1 : 0; +} + +_libssh2_bn * +_libssh2_bn_init(void) +{ + _libssh2_bn *bignum; + + bignum = (_libssh2_bn *) malloc(sizeof(*bignum)); + if(bignum) { + bignum->bignum = NULL; + bignum->length = 0; + } + + return bignum; +} + +void +_libssh2_bn_free(_libssh2_bn *bn) +{ + if(bn) { + if(bn->bignum) { + if(bn->length) + _libssh2_explicit_zero(bn->bignum, bn->length); + + free(bn->bignum); + } + + free((char *) bn); + } +} + +static int +_libssh2_bn_resize(_libssh2_bn *bn, size_t newlen) +{ + unsigned char *bignum; + + if(!bn) + return -1; + if(newlen == bn->length) + return 0; + + if(!bn->bignum) + bignum = (unsigned char *) malloc(newlen); + else { + if(newlen < bn->length) + _libssh2_explicit_zero(bn->bignum + newlen, bn->length - newlen); + + if(!newlen) { + free((char *) bn->bignum); + bn->bignum = NULL; + bn->length = 0; + return 0; + } + bignum = (unsigned char *) realloc((char *) bn->bignum, newlen); + } + + if(!bignum) + return -1; + + if(newlen > bn->length) + memset((char *) bignum + bn->length, 0, newlen - bn->length); + + bn->bignum = bignum; + bn->length = newlen; + return 0; +} + +unsigned long +_libssh2_bn_bits(_libssh2_bn *bn) +{ + unsigned int i; + unsigned char b; + + if(bn && bn->bignum) { + for(i = bn->length; i--;) { + b = bn->bignum[i]; + if(b) { + i *= 8; + do { + i++; + } while(b >>= 1); + return i; + } + } + } + + return 0; +} + +int +_libssh2_bn_from_bin(_libssh2_bn *bn, size_t len, const unsigned char *val) +{ + size_t i; + + if(!bn || (len && !val)) + return -1; + + for(; len && !*val; len--) + val++; + + if(_libssh2_bn_resize(bn, len)) + return -1; + + for(i = len; i--;) + bn->bignum[i] = *val++; + + return 0; +} + +int +_libssh2_bn_set_word(_libssh2_bn *bn, unsigned long val) +{ + val = htonl(val); + return _libssh2_bn_from_bin(bn, sizeof(val), (unsigned char *) &val); +} + +int +_libssh2_bn_to_bin(_libssh2_bn *bn, unsigned char *val) +{ + int i; + + if(!bn || !val) + return -1; + + for(i = bn->length; i--;) + *val++ = bn->bignum[i]; + + return 0; +} + +static int +_libssh2_bn_from_bn(_libssh2_bn *to, _libssh2_bn *from) +{ + int i; + + if(!to || !from) + return -1; + + if(_libssh2_bn_resize(to, from->length)) + return -1; + + for(i = to->length; i--;) + to->bignum[i] = from->bignum[i]; + + return 0; +} + + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: ASN.1 support. + * + *******************************************************************/ + +static char * +getASN1Element(asn1Element *elem, char *beg, char *end) +{ + unsigned char b; + unsigned long len; + asn1Element lelem; + + /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg' + * ending at `end'. + * Returns a pointer in source string after the parsed element, or NULL + * if an error occurs. + */ + + if(beg >= end || !*beg) + return NULL; + + /* Process header byte. */ + elem->header = beg; + b = (unsigned char) *beg++; + elem->constructed = (b & 0x20) != 0; + elem->class = (b >> 6) & 3; + b &= 0x1F; + if(b == 0x1F) + return NULL; /* Long tag values not supported here. */ + elem->tag = b; + + /* Process length. */ + if(beg >= end) + return NULL; + b = (unsigned char) *beg++; + if(!(b & 0x80)) + len = b; + else if(!(b &= 0x7F)) { + /* Unspecified length. Since we have all the data, we can determine the + * effective length by skipping element until an end element is + * found. + */ + if(!elem->constructed) + return NULL; + elem->beg = beg; + while(beg < end && *beg) { + beg = getASN1Element(&lelem, beg, end); + if(!beg) + return NULL; + } + if(beg >= end) + return NULL; + elem->end = beg; + return beg + 1; + } + else if(beg + b > end) + return NULL; /* Does not fit in source. */ + else { + /* Get long length. */ + len = 0; + do { + if(len & 0xFF000000L) + return NULL; /* Lengths > 32 bits are not supported. */ + len = (len << 8) | (unsigned char) *beg++; + } while(--b); + } + if((unsigned long) (end - beg) < len) + return NULL; /* Element data does not fit in source. */ + elem->beg = beg; + elem->end = beg + len; + return elem->end; +} + +static asn1Element * +asn1_new(unsigned int type, unsigned int length) +{ + asn1Element *e; + unsigned int hdrl = 2; + unsigned int i; + unsigned char *buf; + + e = (asn1Element *) malloc(sizeof(*e)); + + if(e) { + if(length >= 0x80) + for(i = length; i; i >>= 8) + hdrl++; + + buf = (unsigned char *) malloc(hdrl + length); + + if(buf) { + e->header = buf; + e->beg = buf + hdrl; + e->end = e->beg + length; + e->class = (type >> 6) & 0x03; + e->tag = type & 0x1F; + e->constructed = (type >> 5) & 0x01; + e->header[0] = type; + + if(length < 0x80) + e->header[1] = length; + else { + e->header[1] = (hdrl - 2) | 0x80; + do { + e->header[--hdrl] = length; + length >>= 8; + } while(length); + } + } + else { + free((char *) e); + e = NULL; + } + } + + return e; +} + +static asn1Element * +asn1_new_from_bytes(const unsigned char *data, unsigned int length) +{ + asn1Element *e; + asn1Element et; + + getASN1Element(&et, + (unsigned char *) data, (unsigned char *) data + length); + e = asn1_new(et.tag, et.end - et.beg); + + if(e) + memcpy(e->header, data, e->end - e->header); + + return e; +} + +static void +asn1delete(asn1Element *e) +{ + if(e) { + if(e->header) + free((char *) e->header); + free((char *) e); + } +} + +static asn1Element * +asn1uint(_libssh2_bn *bn) +{ + asn1Element *e; + int bits; + int length; + unsigned char *p; + + if(!bn) + return NULL; + + bits = _libssh2_bn_bits(bn); + length = (bits + 8) >> 3; + e = asn1_new(ASN1_INTEGER, length); + + if(e) { + p = e->beg; + if(!(bits & 0x07)) + *p++ = 0; + _libssh2_bn_to_bin(bn, p); + } + + return e; +} + +static asn1Element * +asn1containerv(unsigned int type, valiststr args) +{ + valiststr va; + asn1Element *e; + asn1Element *p; + unsigned char *bp; + unsigned int length = 0; + + memcpy((char *) &va, (char *) &args, sizeof(args)); + while((p = va_arg(va.list, asn1Element *))) + length += p->end - p->header; + va_end(va.list); + e = asn1_new(type, length); + if(e) { + bp = e->beg; + while((p = va_arg(args.list, asn1Element *))) { + memcpy(bp, p->header, p->end - p->header); + bp += p->end - p->header; + } + } + return e; +} + +/* VARARGS1 */ +static asn1Element * +asn1container(unsigned int type, ...) +{ + valiststr va; + asn1Element *e; + + va_start(va.list, type); + e = asn1containerv(type, va); + va_end(va.list); + return e; +} + +static asn1Element * +asn1bytes(unsigned int type, const unsigned char *bytes, unsigned int length) +{ + asn1Element *e; + + e = asn1_new(type, length); + if(e && length) + memcpy(e->beg, bytes, length); + return e; +} + +static asn1Element * +rsapublickey(_libssh2_bn *e, _libssh2_bn *m) +{ + asn1Element *publicexponent; + asn1Element *modulus; + asn1Element *rsapubkey; + + /* Build a PKCS#1 RSAPublicKey. */ + + modulus = asn1uint(m); + publicexponent = asn1uint(e); + rsapubkey = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, + modulus, publicexponent, NULL); + asn1delete(modulus); + asn1delete(publicexponent); + + if(!modulus || !publicexponent) { + asn1delete(rsapubkey); + rsapubkey = NULL; + } + + return rsapubkey; +} + +static asn1Element * +rsaprivatekey(_libssh2_bn *e, _libssh2_bn *m, _libssh2_bn *d, + _libssh2_bn *p, _libssh2_bn *q, + _libssh2_bn *exp1, _libssh2_bn *exp2, _libssh2_bn *coeff) +{ + asn1Element *version; + asn1Element *modulus; + asn1Element *publicexponent; + asn1Element *privateexponent; + asn1Element *prime1; + asn1Element *prime2; + asn1Element *exponent1; + asn1Element *exponent2; + asn1Element *coefficient; + asn1Element *rsaprivkey; + + /* Build a PKCS#1 RSAPrivateKey. */ + version = asn1bytes(ASN1_INTEGER, "\0", 1); + modulus = asn1uint(m); + publicexponent = asn1uint(e); + privateexponent = asn1uint(d); + prime1 = asn1uint(p); + prime2 = asn1uint(q); + exponent1 = asn1uint(exp1); + exponent2 = asn1uint(exp2); + coefficient = asn1uint(coeff); + rsaprivkey = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, version, modulus, + publicexponent, privateexponent, prime1, prime2, + exponent1, exponent2, coefficient, NULL); + asn1delete(version); + asn1delete(modulus); + asn1delete(publicexponent); + asn1delete(privateexponent); + asn1delete(prime1); + asn1delete(prime2); + asn1delete(exponent1); + asn1delete(exponent2); + asn1delete(coefficient); + + if(!version || !modulus || !publicexponent || !privateexponent || + !prime1 || !prime2 || !exponent1 || !exponent2 || !coefficient) { + asn1delete(rsaprivkey); + rsaprivkey = NULL; + } + + return rsaprivkey; +} + +static asn1Element * +subjectpublickeyinfo(asn1Element *pubkey, const unsigned char *algo, + asn1Element *parameters) +{ + asn1Element *subjpubkey; + asn1Element *algorithm; + asn1Element *algorithmid; + asn1Element *subjpubkeyinfo; + unsigned int algosize = *algo++; + + algorithm = asn1bytes(ASN1_OBJ_ID, algo, algosize); + algorithmid = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, + algorithm, parameters, NULL); + subjpubkey = asn1container(ASN1_BIT_STRING, &lastbytebitcount, + pubkey, NULL); + subjpubkeyinfo = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, + algorithmid, subjpubkey, NULL); + asn1delete(algorithm); + asn1delete(algorithmid); + asn1delete(subjpubkey); + if(!algorithm || !algorithmid || !subjpubkey) { + asn1delete(subjpubkeyinfo); + subjpubkeyinfo = NULL; + } + return subjpubkeyinfo; +} + +static asn1Element * +rsasubjectpublickeyinfo(asn1Element *pubkey) +{ + asn1Element *parameters; + asn1Element *subjpubkeyinfo; + + parameters = asn1bytes(ASN1_NULL, NULL, 0); + subjpubkeyinfo = subjectpublickeyinfo(pubkey, + OID_rsaEncryption, parameters); + asn1delete(parameters); + if(!parameters) { + asn1delete(subjpubkeyinfo); + subjpubkeyinfo = NULL; + } + return subjpubkeyinfo; +} + +static asn1Element * +privatekeyinfo(asn1Element *privkey, const unsigned char *algo, + asn1Element *parameters) +{ + asn1Element *version; + asn1Element *privatekey; + asn1Element *algorithm; + asn1Element *privatekeyalgorithm; + asn1Element *privkeyinfo; + unsigned int algosize = *algo++; + + /* Build a PKCS#8 PrivateKeyInfo. */ + version = asn1bytes(ASN1_INTEGER, "\0", 1); + algorithm = asn1bytes(ASN1_OBJ_ID, algo, algosize); + privatekeyalgorithm = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, + algorithm, parameters, NULL); + privatekey = asn1container(ASN1_OCTET_STRING, privkey, NULL); + privkeyinfo = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, version, + privatekeyalgorithm, privatekey, NULL); + asn1delete(version); + asn1delete(algorithm); + asn1delete(privatekeyalgorithm); + if(!version || !algorithm || !privatekeyalgorithm) { + asn1delete(privkeyinfo); + privkeyinfo = NULL; + } + return privkeyinfo; +} + +static asn1Element * +rsaprivatekeyinfo(asn1Element *privkey) +{ + asn1Element *parameters; + asn1Element *privkeyinfo; + + parameters = asn1bytes(ASN1_NULL, NULL, 0); + privkeyinfo = privatekeyinfo(privkey, OID_rsaEncryption, parameters); + asn1delete(parameters); + if(!parameters) { + asn1delete(privkeyinfo); + privkeyinfo = NULL; + } + return privkeyinfo; +} + + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: crypto context support. + * + *******************************************************************/ + +static _libssh2_os400qc3_crypto_ctx * +libssh2_init_crypto_ctx(_libssh2_os400qc3_crypto_ctx *ctx) +{ + if(!ctx) + ctx = (_libssh2_os400qc3_crypto_ctx *) malloc(sizeof(*ctx)); + + if(ctx) { + memset((char *) ctx, 0, sizeof(*ctx)); + ctx->hash.Final_Op_Flag = Qc3_Continue; + } + + return ctx; +} + +static int +null_token(const char *token) +{ + return !memcmp(token, nulltoken.Key_Context_Token, + sizeof(nulltoken.Key_Context_Token)); +} + +void +_libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x) +{ + if(!x) + return; + if(!null_token(x->hash.Alg_Context_Token)) { + Qc3DestroyAlgorithmContext(x->hash.Alg_Context_Token, + (char *) &ecnull); + memset(x->hash.Alg_Context_Token, 0, + sizeof(x->hash.Alg_Context_Token)); + } + if(!null_token(x->key.Key_Context_Token)) { + Qc3DestroyKeyContext(x->key.Key_Context_Token, (char *) &ecnull); + memset(x->key.Key_Context_Token, 0, + sizeof(x->key.Key_Context_Token)); + } + if(x->kek) { + _libssh2_os400qc3_crypto_dtor(x->kek); + free((char *) x->kek); + x->kek = NULL; + } +} + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: hash algorithms support. + * + *******************************************************************/ + +int +_libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x, unsigned int algorithm) +{ + Qc3_Format_ALGD0500_T algd; + Qus_EC_t errcode; + + if(!x) + return 0; + + memset((char *) x, 0, sizeof(*x)); + x->Final_Op_Flag = Qc3_Continue; + algd.Hash_Alg = algorithm; + set_EC_length(errcode, sizeof(errcode)); + Qc3CreateAlgorithmContext((char *) &algd, Qc3_Alg_Hash, + x->Alg_Context_Token, &errcode); + return errcode.Bytes_Available ? 0 : 1; +} + +int +_libssh2_os400qc3_hash_update(Qc3_Format_ALGD0100_T *ctx, + const unsigned char *data, int len) +{ + char dummy[64]; + Qus_EC_t errcode; + + ctx->Final_Op_Flag = Qc3_Continue; + set_EC_length(errcode, sizeof(errcode)); + Qc3CalculateHash((char *) data, &len, Qc3_Data, (char *) ctx, + Qc3_Alg_Token, anycsp, NULL, dummy, &errcode); + return errcode.Bytes_Available ? 0 : 1; +} + +int +_libssh2_os400qc3_hash_final(Qc3_Format_ALGD0100_T *ctx, unsigned char *out) +{ + char data; + Qus_EC_t errcode; + + ctx->Final_Op_Flag = Qc3_Final; + set_EC_length(errcode, sizeof(errcode)); + Qc3CalculateHash(&data, &zero, Qc3_Data, (char *) ctx, Qc3_Alg_Token, + anycsp, NULL, (char *) out, &errcode); + Qc3DestroyAlgorithmContext(ctx->Alg_Context_Token, (char *) &ecnull); + memset(ctx->Alg_Context_Token, 0, sizeof(ctx->Alg_Context_Token)); + return errcode.Bytes_Available ? 0 : 1; +} + +int +_libssh2_os400qc3_hash(const unsigned char *message, unsigned long len, + unsigned char *out, unsigned int algo) +{ + Qc3_Format_ALGD0100_T ctx; + + if(!_libssh2_os400qc3_hash_init(&ctx, algo) || + !_libssh2_os400qc3_hash_update(&ctx, message, len) || + !_libssh2_os400qc3_hash_final(&ctx, out)) + return 1; + + return 0; +} + +static int +libssh2_os400qc3_hmac_init(_libssh2_os400qc3_crypto_ctx *ctx, + int algo, size_t minkeylen, void *key, int keylen) +{ + Qus_EC_t errcode; + + if(keylen < minkeylen) { + char *lkey = alloca(minkeylen); + + /* Pad key with zeroes if too short. */ + if(!lkey) + return 0; + memcpy(lkey, (char *) key, keylen); + memset(lkey + keylen, 0, minkeylen - keylen); + key = (void *) lkey; + keylen = minkeylen; + } + if(!_libssh2_os400qc3_hash_init(&ctx->hash, algo)) + return 0; + set_EC_length(errcode, sizeof(errcode)); + Qc3CreateKeyContext((char *) key, &keylen, binstring, &algo, qc3clear, + NULL, NULL, ctx->key.Key_Context_Token, + (char *) &errcode); + return errcode.Bytes_Available ? 0 : 1; +} + +int _libssh2_hmac_ctx_init(libssh2_hmac_ctx *ctx) +{ + memset((char *) ctx, 0, sizeof(libssh2_hmac_ctx)); + return 1; +} + +#if LIBSSH2_MD5 +int _libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return libssh2_os400qc3_hmac_init(ctx, Qc3_MD5, \ + MD5_DIGEST_LENGTH, \ + key, keylen); +} +#endif + +int _libssh2_hmac_sha1_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return libssh2_os400qc3_hmac_init(ctx, Qc3_SHA1, \ + SHA_DIGEST_LENGTH, \ + key, keylen); +} + +int _libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return libssh2_os400qc3_hmac_init(ctx, Qc3_SHA256, \ + SHA256_DIGEST_LENGTH, \ + key, keylen); +} + +int _libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + return libssh2_os400qc3_hmac_init(ctx, Qc3_SHA512, \ + SHA512_DIGEST_LENGTH, \ + key, keylen); +} + +int _libssh2_hmac_update(libssh2_hmac_ctx *ctx, + const void *data, size_t datalen) +{ + char dummy[64]; + int len = (int) datalen; + Qus_EC_t errcode; + + ctx->hash.Final_Op_Flag = Qc3_Continue; + set_EC_length(errcode, sizeof(errcode)); + Qc3CalculateHMAC((char *) data, &len, Qc3_Data, (char *) &ctx->hash, + Qc3_Alg_Token, ctx->key.Key_Context_Token, Qc3_Key_Token, + anycsp, NULL, dummy, (char *) &errcode); + return errcode.Bytes_Available ? 0 : 1; +} + +int _libssh2_hmac_final(libssh2_hmac_ctx *ctx, void *out) +{ + char data; + Qus_EC_t errcode; + + ctx->hash.Final_Op_Flag = Qc3_Final; + set_EC_length(errcode, sizeof(errcode)); + Qc3CalculateHMAC((char *) data, &zero, Qc3_Data, (char *) &ctx->hash, + Qc3_Alg_Token, ctx->key.Key_Context_Token, Qc3_Key_Token, + anycsp, NULL, (char *) out, (char *) &errcode); + return errcode.Bytes_Available ? 0 : 1; +} + +void _libssh2_hmac_cleanup(libssh2_hmac_ctx *ctx) +{ + _libssh2_os400qc3_crypto_dtor(ctx); +} + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: cipher algorithms support. + * + *******************************************************************/ + +int +_libssh2_cipher_init(_libssh2_cipher_ctx *h, _libssh2_cipher_type(algo), + unsigned char *iv, unsigned char *secret, int encrypt) +{ + Qc3_Format_ALGD0200_T algd; + Qus_EC_t errcode; + + (void) encrypt; + + if(!h) + return -1; + + libssh2_init_crypto_ctx(h); + algd.Block_Cipher_Alg = algo.algo; + algd.Block_Length = algo.size; + algd.Mode = algo.mode; + algd.Pad_Option = Qc3_No_Pad; + algd.Pad_Character = 0; + algd.Reserved = 0; + algd.MAC_Length = 0; + algd.Effective_Key_Size = 0; + memset(algd.Init_Vector, 0, sizeof(algd.Init_Vector)); + if(algo.mode != Qc3_ECB && algo.size) + memcpy(algd.Init_Vector, iv, algo.size); + set_EC_length(errcode, sizeof(errcode)); + Qc3CreateAlgorithmContext((char *) &algd, algo.fmt, + h->hash.Alg_Context_Token, &errcode); + if(errcode.Bytes_Available) + return -1; + Qc3CreateKeyContext((char *) secret, &algo.keylen, binstring, + &algo.algo, qc3clear, NULL, NULL, + h->key.Key_Context_Token, (char *) &errcode); + if(errcode.Bytes_Available) { + _libssh2_os400qc3_crypto_dtor(h); + return -1; + } + + return 0; +} + +int +_libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx, + _libssh2_cipher_type(algo), + int encrypt, unsigned char *block, size_t blocksize, + int firstlast) +{ + Qus_EC_t errcode; + int outlen; + int blksize = blocksize; + + (void) algo; + + set_EC_length(errcode, sizeof(errcode)); + if(encrypt) + Qc3EncryptData((char *) block, &blksize, Qc3_Data, + ctx->hash.Alg_Context_Token, Qc3_Alg_Token, + ctx->key.Key_Context_Token, Qc3_Key_Token, anycsp, NULL, + (char *) block, &blksize, &outlen, (char *) &errcode); + else + Qc3DecryptData((char *) block, &blksize, + ctx->hash.Alg_Context_Token, Qc3_Alg_Token, + ctx->key.Key_Context_Token, Qc3_Key_Token, anycsp, NULL, + (char *) block, &blksize, &outlen, (char *) &errcode); + + return errcode.Bytes_Available ? -1 : 0; +} + + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: RSA support. + * + *******************************************************************/ + +int +_libssh2_rsa_new(libssh2_rsa_ctx **rsa, + const unsigned char *edata, unsigned long elen, + const unsigned char *ndata, unsigned long nlen, + const unsigned char *ddata, unsigned long dlen, + const unsigned char *pdata, unsigned long plen, + const unsigned char *qdata, unsigned long qlen, + const unsigned char *e1data, unsigned long e1len, + const unsigned char *e2data, unsigned long e2len, + const unsigned char *coeffdata, unsigned long coefflen) +{ + libssh2_rsa_ctx *ctx; + _libssh2_bn *e = _libssh2_bn_init_from_bin(); + _libssh2_bn *n = _libssh2_bn_init_from_bin(); + _libssh2_bn *d = NULL; + _libssh2_bn *p = NULL; + _libssh2_bn *q = NULL; + _libssh2_bn *e1 = NULL; + _libssh2_bn *e2 = NULL; + _libssh2_bn *coeff = NULL; + asn1Element *key = NULL; + asn1Element *structkey = NULL; + int keytype; + int ret = 0; + int i; + + ctx = libssh2_init_crypto_ctx(NULL); + if(!ctx) + ret = -1; + if(!ret) { + _libssh2_bn_from_bin(e, elen, edata); + _libssh2_bn_from_bin(n, nlen, ndata); + if(!e || !n) + ret = -1; + } + if(!ret && ddata) { + /* Private key. */ + d = _libssh2_bn_init_from_bin(); + _libssh2_bn_from_bin(d, dlen, ddata); + p = _libssh2_bn_init_from_bin(); + _libssh2_bn_from_bin(p, plen, pdata); + q = _libssh2_bn_init_from_bin(); + _libssh2_bn_from_bin(q, qlen, qdata); + e1 = _libssh2_bn_init_from_bin(); + _libssh2_bn_from_bin(e1, e1len, e1data); + e2 = _libssh2_bn_init_from_bin(); + _libssh2_bn_from_bin(e2, e2len, e2data); + coeff = _libssh2_bn_init_from_bin(); + _libssh2_bn_from_bin(coeff, coefflen, coeffdata); + if(!d || !p || !q ||!e1 || !e2 || !coeff) + ret = -1; + + if(!ret) { + /* Build a PKCS#8 private key. */ + key = rsaprivatekey(e, n, d, p, q, e1, e2, coeff); + structkey = rsaprivatekeyinfo(key); + } + keytype = Qc3_RSA_Private; + } + else if(!ret) { + key = rsapublickey(e, n); + structkey = rsasubjectpublickeyinfo(key); + keytype = Qc3_RSA_Public; + } + if(!key || !structkey) + ret = -1; + + /* Create the key context. */ + if(!ret) { + Qus_EC_t errcode; + + set_EC_length(errcode, sizeof(errcode)); + i = structkey->end - structkey->header; + Qc3CreateKeyContext(structkey->header, &i, berstring, &keytype, + qc3clear, NULL, NULL, ctx->key.Key_Context_Token, + (char *) &errcode); + if(errcode.Bytes_Available) + ret = -1; + } + + _libssh2_bn_free(e); + _libssh2_bn_free(n); + _libssh2_bn_free(d); + _libssh2_bn_free(p); + _libssh2_bn_free(q); + _libssh2_bn_free(e1); + _libssh2_bn_free(e2); + _libssh2_bn_free(coeff); + asn1delete(key); + asn1delete(structkey); + if(ret && ctx) { + _libssh2_rsa_free(ctx); + ctx = NULL; + } + *rsa = ctx; + return ret; +} + + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: Diffie-Hellman support. + * + *******************************************************************/ + +void +_libssh2_os400qc3_dh_init(_libssh2_dh_ctx *dhctx) +{ + memset((char *) dhctx, 0, sizeof(*dhctx)); +} + +int +_libssh2_os400qc3_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, + _libssh2_bn *g, _libssh2_bn *p, int group_order) +{ + asn1Element *prime; + asn1Element *base; + asn1Element *dhparameter; + asn1Element *dhkeyagreement; + asn1Element *pkcs3; + int pkcs3len; + char *pubkey; + int pubkeysize; + int pubkeylen; + Qus_EC_t errcode; + + (void) group_order; + + /* Build the PKCS#3 structure. */ + + base = asn1uint(g); + prime = asn1uint(p); + dhparameter = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, + prime, base, NULL); + asn1delete(base); + asn1delete(prime); + dhkeyagreement = asn1bytes(ASN1_OBJ_ID, + OID_dhKeyAgreement + 1, OID_dhKeyAgreement[0]); + pkcs3 = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED, + dhkeyagreement, dhparameter, NULL); + asn1delete(dhkeyagreement); + asn1delete(dhparameter); + if(!base || !prime || !dhparameter || + !dhkeyagreement || !dhparameter || !pkcs3) { + asn1delete(pkcs3); + return -1; + } + pkcs3len = pkcs3->end - pkcs3->header; + pubkeysize = (_libssh2_bn_bits(p) + 7) >> 3; + pubkey = alloca(pubkeysize); + set_EC_length(errcode, sizeof(errcode)); + Qc3GenDHKeyPair((char *) pkcs3->header, &pkcs3len, anycsp, NULL, + dhctx->token, pubkey, &pubkeysize, &pubkeylen, &errcode); + asn1delete(pkcs3); + if(errcode.Bytes_Available) + return -1; + return _libssh2_bn_from_bin(public, pubkeylen, (unsigned char *) pubkey); +} + +int +_libssh2_os400qc3_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, + _libssh2_bn *f, _libssh2_bn *p) +{ + char *pubkey; + int pubkeysize; + char *secretbuf; + int secretbufsize; + int secretbuflen; + Qus_EC_t errcode; + + pubkeysize = (_libssh2_bn_bits(f) + 7) >> 3; + pubkey = alloca(pubkeysize); + _libssh2_bn_to_bin(f, pubkey); + secretbufsize = (_libssh2_bn_bits(p) + 7) >> 3; + secretbuf = alloca(pubkeysize); + set_EC_length(errcode, sizeof(errcode)); + Qc3CalculateDHSecretKey(dhctx->token, pubkey, &pubkeysize, + secretbuf, &secretbufsize, &secretbuflen, + &errcode); + if(errcode.Bytes_Available) + return -1; + return _libssh2_bn_from_bin(secret, + secretbuflen, (unsigned char *) secretbuf); +} + +void +_libssh2_os400qc3_dh_dtor(_libssh2_dh_ctx *dhctx) +{ + if(!null_token(dhctx->token)) { + Qc3DestroyAlgorithmContext(dhctx->token, (char *) &ecnull); + memset((char *) dhctx, 0, sizeof(*dhctx)); + } +} + + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: PKCS#5 supplement. + * + *******************************************************************/ + +static int +oidcmp(const asn1Element *e, const unsigned char *oid) +{ + int i = e->end - e->beg - *oid++; + + if(*e->header != ASN1_OBJ_ID) + return -2; + if(!i) + i = memcmp(e->beg, oid, oid[-1]); + return i; +} + +static int +asn1getword(asn1Element *e, unsigned long *v) +{ + unsigned long a; + const unsigned char *cp; + + if(*e->header != ASN1_INTEGER) + return -1; + for(cp = e->beg; cp < e->end && !*cp; cp++) + ; + if(e->end - cp > sizeof(a)) + return -1; + for(a = 0; cp < e->end; cp++) + a = (a << 8) | *cp; + *v = a; + return 0; +} + +static int +pbkdf1(LIBSSH2_SESSION *session, char **dk, const unsigned char *passphrase, + pkcs5params *pkcs5) +{ + int i; + Qc3_Format_ALGD0100_T hctx; + int len = pkcs5->saltlen; + char *data = (char *) pkcs5->salt; + Qus_EC_t errcode; + + *dk = NULL; + if(pkcs5->dklen > pkcs5->hashlen) + return -1; + + /* Allocate the derived key buffer. */ + *dk = LIBSSH2_ALLOC(session, pkcs5->hashlen); + if(!*dk) + return -1; + + set_EC_length(errcode, sizeof(errcode)); + errcode.Bytes_Available = 1; /* Defaults to error flagging. */ + + /* Initial hash. */ + if(_libssh2_os400qc3_hash_init(&hctx, pkcs5->hash)) { + if(_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 *) &errcode); + + /* Iterate. */ + len = pkcs5->hashlen; + for(i = 1; !errcode.Bytes_Available && i < pkcs5->itercount; i++) + Qc3CalculateHash((char *) *dk, &len, Qc3_Data, (char *) &hctx, + Qc3_Alg_Token, anycsp, NULL, *dk, + (char *) &errcode); + } + + Qc3DestroyAlgorithmContext(hctx.Alg_Context_Token, (char *) &ecnull); + } + + if(errcode.Bytes_Available) { + LIBSSH2_FREE(session, *dk); + *dk = NULL; + return -1; + } + + /* Special stuff for PBES1: split derived key into 8-byte key and 8-byte + initialization vector. */ + pkcs5->dklen = 8; + pkcs5->ivlen = 8; + pkcs5->iv = *dk + 8; + + return 0; +} + +static int +pbkdf2(LIBSSH2_SESSION *session, char **dk, const unsigned char *passphrase, + pkcs5params *pkcs5) +{ + size_t i; + size_t k; + int j; + int l; + uint32_t ni; + unsigned long long t; + char *mac; + char *buf; + _libssh2_os400qc3_crypto_ctx hctx; + + *dk = NULL; + t = ((unsigned long long) pkcs5->dklen + pkcs5->hashlen - 1) / + pkcs5->hashlen; + if(t > 0xFFFFFFFF) + return -1; + mac = alloca(pkcs5->hashlen); + if(!mac) + return -1; + + /* Create an HMAC context for our computations. */ + if(!libssh2_os400qc3_hmac_init(&hctx, pkcs5->hash, pkcs5->hashlen, + (void *) passphrase, strlen(passphrase))) + return -1; + + /* Allocate the derived key buffer. */ + l = t; + buf = LIBSSH2_ALLOC(session, l * pkcs5->hashlen); + if(!buf) + return -1; + *dk = buf; + + /* Process each hLen-size blocks. */ + for(i = 1; i <= l; i++) { + ni = htonl(i); + if(!_libssh2_hmac_update(&hctx, pkcs5->salt, pkcs5->saltlen) || + !_libssh2_hmac_update(&hctx, &ni, sizeof(ni)) || + !_libssh2_hmac_final(&hctx, mac)) { + LIBSSH2_FREE(session, buf); + *dk = NULL; + _libssh2_os400qc3_crypto_dtor(&hctx); + return -1; + } + memcpy(buf, mac, pkcs5->hashlen); + for(j = 1; j < pkcs5->itercount; j++) { + if(!_libssh2_hmac_update(&hctx, mac, pkcs5->hashlen) || + !_libssh2_hmac_final(&hctx, mac)) { + LIBSSH2_FREE(session, buf); + *dk = NULL; + _libssh2_os400qc3_crypto_dtor(&hctx); + return -1; + } + for(k = 0; k < pkcs5->hashlen; k++) + buf[k] ^= mac[k]; + } + buf += pkcs5->hashlen; + } + + /* Computation done. Release HMAC context. */ + _libssh2_os400qc3_crypto_dtor(&hctx); + return 0; +} + +static int +parse_pkcs5_algorithm(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + asn1Element *algid, pkcs5algo **algotable) +{ + asn1Element oid; + asn1Element param; + char *cp; + + cp = getASN1Element(&oid, algid->beg, algid->end); + if(!cp || *oid.header != ASN1_OBJ_ID) + return -1; + param.header = NULL; + if(cp < algid->end) + cp = getASN1Element(¶m, cp, algid->end); + if(cp != algid->end) + return -1; + for(; *algotable; algotable++) + if(!oidcmp(&oid, (*algotable)->oid)) + return (*(*algotable)->parse)(session, pkcs5, *algotable, + param.header ? ¶m : NULL); + return -1; +} + +static int +parse_pbes2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param) +{ + asn1Element keyDerivationFunc; + asn1Element encryptionScheme; + char *cp; + + if(!param || *param->header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + cp = getASN1Element(&keyDerivationFunc, param->beg, param->end); + if(!cp || *keyDerivationFunc.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + if(getASN1Element(&encryptionScheme, cp, param->end) != param->end || + *encryptionScheme.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + if(parse_pkcs5_algorithm(session, pkcs5, &encryptionScheme, pbes2enctable)) + return -1; + if(parse_pkcs5_algorithm(session, pkcs5, &keyDerivationFunc, pbkdf2table)) + return -1; + return 0; +} + +static int +parse_pbkdf2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param) +{ + asn1Element salt; + asn1Element iterationCount; + asn1Element keyLength; + asn1Element prf; + unsigned long itercount; + char *cp; + + if(!param || *param->header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + cp = getASN1Element(&salt, param->beg, param->end); + /* otherSource not supported. */ + if(!cp || *salt.header != ASN1_OCTET_STRING) + return -1; + cp = getASN1Element(&iterationCount, cp, param->end); + if(!cp || *iterationCount.header != ASN1_INTEGER) + return -1; + keyLength.header = prf.header = NULL; + if(cp < param->end) { + cp = getASN1Element(&prf, cp, param->end); + if(!cp) + return -1; + if(*prf.header == ASN1_INTEGER) { + keyLength = prf; + prf.header = NULL; + if(cp < param->end) + cp = getASN1Element(&prf, cp, param->end); + } + if(cp != param->end) + return -1; + } + pkcs5->hash = algo->hash; + pkcs5->hashlen = algo->hashlen; + if(prf.header) { + if(*prf.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + if(parse_pkcs5_algorithm(session, pkcs5, &prf, kdf2prftable)) + return -1; + } + pkcs5->saltlen = salt.end - salt.beg; + pkcs5->salt = salt.beg; + if(asn1getword(&iterationCount, &itercount) || + !itercount || itercount > 100000) + return -1; + pkcs5->itercount = itercount; + pkcs5->kdf = pbkdf2; + return 0; +} + +static int +parse_hmacWithSHA1(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param) +{ + if(!param || *param->header != ASN1_NULL) + return -1; + pkcs5->hash = algo->hash; + pkcs5->hashlen = algo->hashlen; + return 0; +} + +static int +parse_iv(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param) +{ + if(!param || *param->header != ASN1_OCTET_STRING || + param->end - param->beg != algo->ivlen) + return -1; + pkcs5->cipher = algo->cipher; + pkcs5->blocksize = algo->blocksize; + pkcs5->mode = algo->mode; + pkcs5->padopt = algo->padopt; + pkcs5->padchar = algo->padchar; + pkcs5->dklen = algo->keylen; + pkcs5->ivlen = algo->ivlen; + pkcs5->iv = param->beg; + return 0; +} + +static int +parse_rc2(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param) +{ + asn1Element iv; + unsigned long effkeysize; + char *cp; + + if(!param || *param->header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + cp = getASN1Element(&iv, param->beg, param->end); + if(!cp) + return -1; + effkeysize = algo->effkeysize; + if(*iv.header == ASN1_INTEGER) { + if(asn1getword(&iv, &effkeysize) || effkeysize > 1024) + return -1; + + cp = getASN1Element(&iv, cp, param->end); + if(effkeysize < 256) + switch(effkeysize) { + case 160: + effkeysize = 40; + case 120: + effkeysize = 64; + case 58: + effkeysize = 128; + break; + default: + return -1; + } + } + if(effkeysize > 1024 || cp != param->end || + *iv.header != ASN1_OCTET_STRING || iv.end - iv.beg != algo->ivlen) + return -1; + pkcs5->cipher = algo->cipher; + pkcs5->blocksize = algo->blocksize; + pkcs5->mode = algo->mode; + pkcs5->padopt = algo->padopt; + pkcs5->padchar = algo->padchar; + pkcs5->ivlen = algo->ivlen; + pkcs5->iv = iv.beg; + pkcs5->effkeysize = effkeysize; + pkcs5->dklen = (effkeysize + 8 - 1) / 8; + return 0; +} + +static int +parse_pbes1(LIBSSH2_SESSION *session, pkcs5params *pkcs5, + pkcs5algo *algo, asn1Element *param) +{ + asn1Element salt; + asn1Element iterationCount; + unsigned long itercount; + char *cp; + + if(!param || *param->header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + + cp = getASN1Element(&salt, param->beg, param->end); + if(!cp || *salt.header != ASN1_OCTET_STRING || + salt.end - salt.beg != algo->saltlen) + return -1; + if(getASN1Element(&iterationCount, cp, param->end) != param->end || + *iterationCount.header != ASN1_INTEGER) + return -1; + if(asn1getword(&iterationCount, &itercount) || + !itercount || itercount > 100000) + return -1; + pkcs5->cipher = algo->cipher; + pkcs5->blocksize = algo->blocksize; + pkcs5->mode = algo->mode; + pkcs5->padopt = algo->padopt; + pkcs5->padchar = algo->padchar; + pkcs5->hash = algo->hash; + pkcs5->hashlen = algo->hashlen; + pkcs5->dklen = 16; + pkcs5->saltlen = algo->saltlen; + pkcs5->effkeysize = algo->effkeysize; + pkcs5->salt = salt.beg; + pkcs5->kdf = pbkdf1; + pkcs5->itercount = itercount; + return 0; +} + +static int +pkcs8kek(LIBSSH2_SESSION *session, _libssh2_os400qc3_crypto_ctx **ctx, + const unsigned char *data, unsigned int datalen, + const unsigned char *passphrase, asn1Element *privkeyinfo) +{ + asn1Element encprivkeyinfo; + asn1Element pkcs5alg; + pkcs5params pkcs5; + size_t pplen; + char *cp; + unsigned long t; + int i; + char *dk = NULL; + Qc3_Format_ALGD0200_T algd; + Qus_EC_t errcode; + + /* Determine if the PKCS#8 data is encrypted and, if so, set-up a + key encryption key and algorithm in context. + Return 1 if encrypted, 0, if not, -1 if error. */ + + *ctx = NULL; + privkeyinfo->beg = (char *) data; + privkeyinfo->end = privkeyinfo->beg + datalen; + + /* If no passphrase is given, it cannot be an encrypted key. */ + if(!passphrase || !*passphrase) + return 0; + + /* Parse PKCS#8 data, checking if ASN.1 format is PrivateKeyInfo or + EncryptedPrivateKeyInfo. */ + if(getASN1Element(&encprivkeyinfo, privkeyinfo->beg, privkeyinfo->end) != + (char *) data + datalen || + *encprivkeyinfo.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + cp = getASN1Element(&pkcs5alg, encprivkeyinfo.beg, encprivkeyinfo.end); + if(!cp) + return -1; + + switch(*pkcs5alg.header) { + case ASN1_INTEGER: /* Version. */ + return 0; /* This is a PrivateKeyInfo --> not encrypted. */ + case ASN1_SEQ | ASN1_CONSTRUCTED: /* AlgorithIdentifier. */ + break; /* This is an EncryptedPrivateKeyInfo --> encrypted. */ + default: + return -1; /* Unrecognized: error. */ + } + + /* Get the encrypted key data. */ + if(getASN1Element(privkeyinfo, cp, encprivkeyinfo.end) != + encprivkeyinfo.end || *privkeyinfo->header != ASN1_OCTET_STRING) + return -1; + + /* PKCS#5: parse the PBES AlgorithmIdentifier and recursively get all + encryption parameters. */ + memset((char *) &pkcs5, 0, sizeof(pkcs5)); + if(parse_pkcs5_algorithm(session, &pkcs5, &pkcs5alg, pbestable)) + return -1; + + /* Compute the derived key. */ + if((*pkcs5.kdf)(session, &dk, passphrase, &pkcs5)) + return -1; + + /* Prepare the algorithm descriptor. */ + memset((char *) &algd, 0, sizeof(algd)); + algd.Block_Cipher_Alg = pkcs5.cipher; + algd.Block_Length = pkcs5.blocksize; + algd.Mode = pkcs5.mode; + algd.Pad_Option = pkcs5.padopt; + algd.Pad_Character = pkcs5.padchar; + algd.Effective_Key_Size = pkcs5.effkeysize; + memcpy(algd.Init_Vector, pkcs5.iv, pkcs5.ivlen); + + /* Create the key and algorithm context tokens. */ + *ctx = libssh2_init_crypto_ctx(NULL); + if(!*ctx) { + LIBSSH2_FREE(session, dk); + return -1; + } + libssh2_init_crypto_ctx(*ctx); + set_EC_length(errcode, sizeof(errcode)); + Qc3CreateKeyContext(dk, &pkcs5.dklen, binstring, &algd.Block_Cipher_Alg, + qc3clear, NULL, NULL, (*ctx)->key.Key_Context_Token, + (char *) &errcode); + LIBSSH2_FREE(session, dk); + if(errcode.Bytes_Available) { + free((char *) *ctx); + *ctx = NULL; + return -1; + } + + Qc3CreateAlgorithmContext((char *) &algd, Qc3_Alg_Block_Cipher, + (*ctx)->hash.Alg_Context_Token, &errcode); + if(errcode.Bytes_Available) { + Qc3DestroyKeyContext((*ctx)->key.Key_Context_Token, (char *) &ecnull); + free((char *) *ctx); + *ctx = NULL; + return -1; + } + return 1; /* Tell it's encrypted. */ +} + +static int +rsapkcs8privkey(LIBSSH2_SESSION *session, + const unsigned char *data, unsigned int datalen, + const unsigned char *passphrase, void *loadkeydata) +{ + libssh2_rsa_ctx *ctx = (libssh2_rsa_ctx *) loadkeydata; + char keyform = Qc3_Clear; + char *kek = NULL; + char *kea = NULL; + _libssh2_os400qc3_crypto_ctx *kekctx; + asn1Element pki; + int pkilen; + Qus_EC_t errcode; + + switch(pkcs8kek(session, &kekctx, data, datalen, passphrase, &pki)) { + case 1: + keyform = Qc3_Encrypted; + kek = kekctx->key.Key_Context_Token; + kea = kekctx->hash.Alg_Context_Token; + case 0: + break; + default: + return -1; + } + + set_EC_length(errcode, sizeof(errcode)); + pkilen = pki.end - pki.beg; + Qc3CreateKeyContext((unsigned char *) pki.beg, &pkilen, berstring, + rsaprivate, &keyform, kek, kea, + ctx->key.Key_Context_Token, (char *) &errcode); + if(errcode.Bytes_Available) { + if(kekctx) + _libssh2_os400qc3_crypto_dtor(kekctx); + return -1; + } + ctx->kek = kekctx; + return 0; +} + +static char * +storewithlength(char *p, const char *data, int length) +{ + _libssh2_htonu32(p, length); + if(length) + memcpy(p + 4, data, length); + return p + 4 + length; +} + +static int +sshrsapubkey(LIBSSH2_SESSION *session, char **sshpubkey, + asn1Element *params, asn1Element *key, const char *method) +{ + int methlen = strlen(method); + asn1Element keyseq; + asn1Element m; + asn1Element e; + int len; + char *cp; + + if(getASN1Element(&keyseq, key->beg + 1, key->end) != key->end || + *keyseq.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + if(!getASN1Element(&m, keyseq.beg, keyseq.end) || + *m.header != ASN1_INTEGER) + return -1; + if(getASN1Element(&e, m.end, keyseq.end) != keyseq.end || + *e.header != ASN1_INTEGER) + return -1; + len = 4 + methlen + 4 + (e.end - e.beg) + 4 + (m.end - m.beg); + cp = LIBSSH2_ALLOC(session, len); + if(!cp) + return -1; + *sshpubkey = cp; + cp = storewithlength(cp, method, methlen); + cp = storewithlength(cp, e.beg, e.end - e.beg); + cp = storewithlength(cp, m.beg, m.end - m.beg); + return len; +} + +static int +rsapkcs8pubkey(LIBSSH2_SESSION *session, + const unsigned char *data, unsigned int datalen, + const unsigned char *passphrase, void *loadkeydata) +{ + loadpubkeydata *p = (loadpubkeydata *) loadkeydata; + char *buf; + int len; + char *cp; + int i; + char keyform = Qc3_Clear; + char *kek = NULL; + char *kea = NULL; + _libssh2_os400qc3_crypto_ctx *kekctx; + asn1Element subjpubkeyinfo; + asn1Element algorithmid; + asn1Element algorithm; + asn1Element subjpubkey; + asn1Element parameters; + asn1Element pki; + int pkilen; + Qus_EC_t errcode; + + buf = alloca(datalen); + if(!buf) + return -1; + + switch(pkcs8kek(session, &kekctx, data, datalen, passphrase, &pki)) { + case 1: + keyform = Qc3_Encrypted; + kek = kekctx->key.Key_Context_Token; + kea = kekctx->hash.Alg_Context_Token; + case 0: + break; + default: + return -1; + } + + set_EC_length(errcode, sizeof(errcode)); + pkilen = pki.end - pki.beg; + Qc3ExtractPublicKey(pki.beg, &pkilen, berstring, &keyform, + kek, kea, buf, (int *) &datalen, &len, &errcode); + _libssh2_os400qc3_crypto_dtor(kekctx); + if(errcode.Bytes_Available) + return -1; + /* Get the algorithm OID and key data from SubjectPublicKeyInfo. */ + if(getASN1Element(&subjpubkeyinfo, buf, buf + len) != buf + len || + *subjpubkeyinfo.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + cp = getASN1Element(&algorithmid, subjpubkeyinfo.beg, subjpubkeyinfo.end); + if(!cp || *algorithmid.header != (ASN1_SEQ | ASN1_CONSTRUCTED)) + return -1; + if(!getASN1Element(&algorithm, algorithmid.beg, algorithmid.end) || + *algorithm.header != ASN1_OBJ_ID) + return -1; + if(getASN1Element(&subjpubkey, cp, subjpubkeyinfo.end) != + subjpubkeyinfo.end || *subjpubkey.header != ASN1_BIT_STRING) + return -1; + /* Check for supported algorithm. */ + for(i = 0; pka[i].oid; i++) + if(!oidcmp(&algorithm, pka[i].oid)) { + len = (*pka[i].sshpubkey)(session, &p->data, &algorithmid, + &subjpubkey, pka[i].method); + if(len < 0) + return -1; + p->length = len; + p->method = pka[i].method; + return 0; + } + return -1; /* Algorithm not supported. */ +} + +static int +pkcs1topkcs8(LIBSSH2_SESSION *session, + const unsigned char **data8, unsigned int *datalen8, + const unsigned char *data1, unsigned int datalen1) +{ + asn1Element *prvk; + asn1Element *pkcs8; + unsigned char *data; + + *data8 = NULL; + *datalen8 = 0; + if(datalen1 < 2) + return -1; + prvk = asn1_new_from_bytes(data1, datalen1); + if(!prvk) + return -1; + pkcs8 = rsaprivatekeyinfo(prvk); + asn1delete(prvk); + if(!prvk) { + asn1delete(pkcs8); + pkcs8 = NULL; + } + if(!pkcs8) + return -1; + data = (unsigned char *) LIBSSH2_ALLOC(session, + pkcs8->end - pkcs8->header); + if(!data) { + asn1delete(pkcs8); + return -1; + } + *data8 = data; + *datalen8 = pkcs8->end - pkcs8->header; + memcpy((char *) data, (char *) pkcs8->header, *datalen8); + asn1delete(pkcs8); + return 0; +} + +static int +rsapkcs1privkey(LIBSSH2_SESSION *session, + const unsigned char *data, unsigned int datalen, + const unsigned char *passphrase, void *loadkeydata) +{ + const unsigned char *data8; + unsigned int datalen8; + int ret; + + if(pkcs1topkcs8(session, &data8, &datalen8, data, datalen)) + return -1; + ret = rsapkcs8privkey(session, data8, datalen8, passphrase, loadkeydata); + LIBSSH2_FREE(session, (char *) data8); + return ret; +} + +static int +rsapkcs1pubkey(LIBSSH2_SESSION *session, + const unsigned char *data, unsigned int datalen, + const unsigned char *passphrase, void *loadkeydata) +{ + const unsigned char *data8; + unsigned int datalen8; + int ret; + + if(pkcs1topkcs8(session, &data8, &datalen8, data, datalen)) + return -1; + ret = rsapkcs8pubkey(session, data8, datalen8, passphrase, loadkeydata); + LIBSSH2_FREE(session, (char *) data8); + return ret; +} + +static int +try_pem_load(LIBSSH2_SESSION *session, FILE *fp, + const unsigned char *passphrase, + const char *header, const char *trailer, + loadkeyproc proc, void *loadkeydata) +{ + unsigned char *data = NULL; + size_t datalen = 0; + int c; + int ret; + + fseek(fp, 0L, SEEK_SET); + for(;;) { + ret = _libssh2_pem_parse(session, header, trailer, + passphrase, + fp, &data, &datalen); + + if(!ret) { + ret = (*proc)(session, data, datalen, passphrase, loadkeydata); + if(!ret) + return 0; + } + + if(data) { + LIBSSH2_FREE(session, data); + data = NULL; + } + c = getc(fp); + + if(c == EOF) + break; + + ungetc(c, fp); + } + + return -1; +} + +static int +load_rsa_private_file(LIBSSH2_SESSION *session, const char *filename, + unsigned const char *passphrase, + loadkeyproc proc1, loadkeyproc proc8, void *loadkeydata) +{ + FILE *fp = fopen(filename, fopenrmode); + unsigned char *data = NULL; + size_t datalen = 0; + int ret; + long filesize; + + if(!fp) + return -1; + + /* Try with "ENCRYPTED PRIVATE KEY" PEM armor. + --> PKCS#8 EncryptedPrivateKeyInfo */ + ret = try_pem_load(session, fp, passphrase, beginencprivkeyhdr, + endencprivkeyhdr, proc8, loadkeydata); + + /* Try with "PRIVATE KEY" PEM armor. + --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ + if(ret) + ret = try_pem_load(session, fp, passphrase, beginprivkeyhdr, + endprivkeyhdr, proc8, loadkeydata); + + /* Try with "RSA PRIVATE KEY" PEM armor. + --> PKCS#1 RSAPrivateKey */ + if(ret) + ret = try_pem_load(session, fp, passphrase, beginrsaprivkeyhdr, + endrsaprivkeyhdr, proc1, loadkeydata); + fclose(fp); + + if(ret) { + /* Try DER encoding. */ + fp = fopen(filename, fopenrbmode); + fseek(fp, 0L, SEEK_END); + filesize = ftell(fp); + + if(filesize <= 32768) { /* Limit to a reasonable size. */ + datalen = filesize; + data = (unsigned char *) alloca(datalen); + if(data) { + fseek(fp, 0L, SEEK_SET); + fread(data, datalen, 1, fp); + + /* Try as PKCS#8 DER data. + --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ + ret = (*proc8)(session, data, datalen, passphrase, + loadkeydata); + + /* Try as PKCS#1 DER data. + --> PKCS#1 RSAPrivateKey */ + if(ret) + ret = (*proc1)(session, data, datalen, passphrase, + loadkeydata); + } + } + fclose(fp); + } + + return ret; +} + +int +_libssh2_rsa_new_private(libssh2_rsa_ctx **rsa, LIBSSH2_SESSION *session, + const char *filename, unsigned const char *passphrase) +{ + libssh2_rsa_ctx *ctx = libssh2_init_crypto_ctx(NULL); + int ret; + + if(!ctx) + return -1; + ret = load_rsa_private_file(session, filename, passphrase, + rsapkcs1privkey, rsapkcs8privkey, + (void *) ctx); + if(ret) { + _libssh2_os400qc3_crypto_dtor(ctx); + ctx = NULL; + } + *rsa = ctx; + return ret; +} + +int +_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, + unsigned char **method, size_t *method_len, + unsigned char **pubkeydata, size_t *pubkeydata_len, + const char *privatekey, const char *passphrase) +{ + loadpubkeydata p; + int ret; + + *method = NULL; + *method_len = 0; + *pubkeydata = NULL; + *pubkeydata_len = 0; + + ret = load_rsa_private_file(session, privatekey, passphrase, + rsapkcs1pubkey, rsapkcs8pubkey, (void *) &p); + if(!ret) { + *method_len = strlen(p.method); + *method = LIBSSH2_ALLOC(session, *method_len); + if(*method) + memcpy((char *) *method, p.method, *method_len); + else + ret = -1; + } + + if(ret) { + if(*method) + LIBSSH2_FREE(session, *method); + if(p.data) + LIBSSH2_FREE(session, (void *) p.data); + *method = NULL; + *method_len = 0; + } + else { + *pubkeydata = (unsigned char *) p.data; + *pubkeydata_len = p.length; + } + + return ret; +} + +int +_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase) +{ + libssh2_rsa_ctx *ctx = libssh2_init_crypto_ctx(NULL); + unsigned char *data = NULL; + size_t datalen = 0; + int ret; + + if(!ctx) + return -1; + + /* Try with "ENCRYPTED PRIVATE KEY" PEM armor. + --> PKCS#8 EncryptedPrivateKeyInfo */ + ret = _libssh2_pem_parse_memory(session, + beginencprivkeyhdr, endencprivkeyhdr, + filedata, filedata_len, &data, &datalen); + + /* Try with "PRIVATE KEY" PEM armor. + --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ + if(ret) + ret = _libssh2_pem_parse_memory(session, + beginprivkeyhdr, endprivkeyhdr, + filedata, filedata_len, + &data, &datalen); + + if(!ret) { + /* Process PKCS#8. */ + ret = rsapkcs8privkey(session, + data, datalen, passphrase, (void *) &ctx); + } + else { + /* Try with "RSA PRIVATE KEY" PEM armor. + --> PKCS#1 RSAPrivateKey */ + ret = _libssh2_pem_parse_memory(session, + beginrsaprivkeyhdr, endrsaprivkeyhdr, + filedata, filedata_len, + &data, &datalen); + if(!ret) + ret = rsapkcs1privkey(session, + data, datalen, passphrase, (void *) &ctx); + } + + if(ret) { + /* Try as PKCS#8 DER data. + --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ + ret = rsapkcs8privkey(session, filedata, filedata_len, + passphrase, (void *) &ctx); + + /* Try as PKCS#1 DER data. + --> PKCS#1 RSAPrivateKey */ + if(ret) + ret = rsapkcs1privkey(session, filedata, filedata_len, + passphrase, (void *) &ctx); + } + + if(data) + LIBSSH2_FREE(session, data); + + if(ret) { + _libssh2_os400qc3_crypto_dtor(ctx); + ctx = NULL; + } + + *rsa = ctx; + return ret; +} + +int +_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) +{ + loadpubkeydata p; + unsigned char *data = NULL; + size_t datalen = 0; + const char *meth; + int ret; + + *method = NULL; + *method_len = 0; + *pubkeydata = NULL; + *pubkeydata_len = 0; + + /* Try with "ENCRYPTED PRIVATE KEY" PEM armor. + --> PKCS#8 EncryptedPrivateKeyInfo */ + ret = _libssh2_pem_parse_memory(session, + beginencprivkeyhdr, endencprivkeyhdr, + privatekeydata, privatekeydata_len, + &data, &datalen); + + /* Try with "PRIVATE KEY" PEM armor. + --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ + if(ret) + ret = _libssh2_pem_parse_memory(session, + beginprivkeyhdr, endprivkeyhdr, + privatekeydata, privatekeydata_len, + &data, &datalen); + + if(!ret) { + /* Process PKCS#8. */ + ret = rsapkcs8pubkey(session, + data, datalen, passphrase, (void *) &p); + } + else { + /* Try with "RSA PRIVATE KEY" PEM armor. + --> PKCS#1 RSAPrivateKey */ + ret = _libssh2_pem_parse_memory(session, + beginrsaprivkeyhdr, endrsaprivkeyhdr, + privatekeydata, privatekeydata_len, + &data, &datalen); + if(!ret) + ret = rsapkcs1pubkey(session, + data, datalen, passphrase, (void *) &p); + } + + if(ret) { + /* Try as PKCS#8 DER data. + --> PKCS#8 PrivateKeyInfo or EncryptedPrivateKeyInfo */ + ret = rsapkcs8pubkey(session, privatekeydata, privatekeydata_len, + passphrase, (void *) &p); + + /* Try as PKCS#1 DER data. + --> PKCS#1 RSAPrivateKey */ + if(ret) + ret = rsapkcs1pubkey(session, privatekeydata, privatekeydata_len, + passphrase, (void *) &p); + } + + if(data) + LIBSSH2_FREE(session, data); + + if(!ret) { + *method_len = strlen(p.method); + *method = LIBSSH2_ALLOC(session, *method_len); + if(*method) + memcpy((char *) *method, p.method, *method_len); + else + ret = -1; + } + if(ret) { + if(*method) + LIBSSH2_FREE(session, *method); + if(p.data) + LIBSSH2_FREE(session, (void *) p.data); + *method = NULL; + *method_len = 0; + } + else { + *pubkeydata = (unsigned char *) p.data; + *pubkeydata_len = p.length; + } + + return ret; +} + +int +_libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) +{ + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public SK key from private key file: " + "Method unimplemented in OS/400 QC3 backend"); +} + +int +_libssh2_rsa_sha2_verify(libssh2_rsa_ctx *rsa, size_t hash_len, + const unsigned char *sig, size_t sig_len, + const unsigned char *m, size_t m_len) +{ + Qus_EC_t errcode; + Qc3_Format_ALGD0400_T algd; + int slen = (int)sig_len; + int mlen = (int)m_len; + + memset(&algd, 0, sizeof(algd)); + algd.Public_Key_Alg = Qc3_RSA; + algd.PKA_Block_Format = Qc3_PKCS1_01; + switch(hash_len) { + case SHA_DIGEST_LENGTH: + algd.Signing_Hash_Alg = Qc3_SHA1; + break; + case SHA256_DIGEST_LENGTH: + algd.Signing_Hash_Alg = Qc3_SHA256; + break; + case SHA512_DIGEST_LENGTH: + algd.Signing_Hash_Alg = Qc3_SHA512; + break; + default: + return -1; + } + + set_EC_length(errcode, sizeof(errcode)); + Qc3VerifySignature((char *) sig, &slen, (char *) m, &mlen, Qc3_Data, + (char *) &algd, Qc3_Alg_Public_Key, + (char *) &rsa->key, Qc3_Key_Token, anycsp, + NULL, (char *) &errcode); + return errcode.Bytes_Available ? -1 : 0; +} + +int +_libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa, + const unsigned char *sig, size_t sig_len, + const unsigned char *m, size_t m_len) +{ + return _libssh2_rsa_sha2_verify(rsa, SHA_DIGEST_LENGTH, + sig, sig_len, m, m_len); +} + +int +_libssh2_os400qc3_rsa_signv(LIBSSH2_SESSION *session, + int algo, + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec vector[], + libssh2_rsa_ctx *ctx) +{ + Qus_EC_t errcode; + Qc3_Format_ALGD0400_T algd; + int siglen; + unsigned char *sig; + char sigbuf[8192]; + int sigbufsize = sizeof(sigbuf); + + algd.Public_Key_Alg = Qc3_RSA; + algd.PKA_Block_Format = Qc3_PKCS1_01; + memset(algd.Reserved, 0, sizeof(algd.Reserved)); + algd.Signing_Hash_Alg = algo; + set_EC_length(errcode, sizeof(errcode)); + Qc3CalculateSignature((char *) vector, &veccount, Qc3_Array, + (char *) &algd, Qc3_Alg_Public_Key, + (char *) &ctx->key, Qc3_Key_Token, + anycsp, NULL, sigbuf, &sigbufsize, &siglen, + (char *) &errcode); + if(errcode.Bytes_Available) + return -1; + sig = LIBSSH2_ALLOC(session, siglen); + if(!sig) + return -1; + memcpy((char *) sig, sigbuf, siglen); + *signature = sig; + *signature_len = siglen; + return 0; +} + +/* _libssh2_supported_key_sign_algorithms + * + * Return supported key hash algo upgrades, see crypto.h + * + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len) +{ + (void)session; + + if(key_method_len == 7 && + memcmp(key_method, "ssh-rsa", key_method_len) == 0) { + return "rsa-sha2-512,rsa-sha2-256" +#if LIBSSH2_RSA_SHA1 + ",ssh-rsa" +#endif + ; + } + + return NULL; +} + +#endif /* LIBSSH2_CRYPTO_C */ + +/* vim: set expandtab ts=4 sw=4: */ diff --git a/uppsrc/Core/SSH/libssh2/os400qc3.h b/uppsrc/Core/SSH/libssh2/os400qc3.h new file mode 100644 index 000000000..8c4096b51 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/os400qc3.h @@ -0,0 +1,397 @@ +#ifndef LIBSSH2_OS400QC3_H +#define LIBSSH2_OS400QC3_H +/* + * Copyright (C) Patrick Monnerat + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define LIBSSH2_CRYPTO_ENGINE libssh2_os400qc3 + +#include +#include + +#include + + +/* Redefine character/string literals as always EBCDIC. */ +#undef Qc3_Alg_Token +#define Qc3_Alg_Token "\xC1\xD3\xC7\xC4\xF0\xF1\xF0\xF0" /* ALGD0100 */ +#undef Qc3_Alg_Block_Cipher +#define Qc3_Alg_Block_Cipher "\xC1\xD3\xC7\xC4\xF0\xF2\xF0\xF0" /* ALGD0200 */ +#undef Qc3_Alg_Block_CipherAuth +#define Qc3_Alg_Block_CipherAuth \ + "\xC1\xD3\xC7\xC4\xF0\xF2\xF1\xF0" /* ALGD0210 */ +#undef Qc3_Alg_Stream_Cipher +#define Qc3_Alg_Stream_Cipher \ + "\xC1\xD3\xC7\xC4\xF0\xF3\xF0\xF0" /* ALGD0300 */ +#undef Qc3_Alg_Public_Key +#define Qc3_Alg_Public_Key "\xC1\xD3\xC7\xC4\xF0\xF4\xF0\xF0" /* ALGD0400 */ +#undef Qc3_Alg_Hash +#define Qc3_Alg_Hash "\xC1\xD3\xC7\xC4\xF0\xF5\xF0\xF0" /* ALGD0500 */ +#undef Qc3_Data +#define Qc3_Data "\xC4\xC1\xE3\xC1\xF0\xF1\xF0\xF0" /* DATA0100 */ +#undef Qc3_Array +#define Qc3_Array "\xC4\xC1\xE3\xC1\xF0\xF2\xF0\xF0" /* DATA0200 */ +#undef Qc3_Key_Token +#define Qc3_Key_Token "\xD2\xC5\xE8\xC4\xF0\xF1\xF0\xF0" /* KEYD0100 */ +#undef Qc3_Key_Parms +#define Qc3_Key_Parms "\xD2\xC5\xE8\xC4\xF0\xF2\xF0\xF0" /* KEYD0200 */ +#undef Qc3_Key_KSLabel +#define Qc3_Key_KSLabel "\xD2\xC5\xE8\xC4\xF0\xF4\xF0\xF0" /* KEYD0400 */ +#undef Qc3_Key_PKCS5 +#define Qc3_Key_PKCS5 "\xD2\xC5\xE8\xC4\xF0\xF5\xF0\xF0" /* KEYD0500 */ +#undef Qc3_Key_PEMCert +#define Qc3_Key_PEMCert "\xD2\xC5\xE8\xC4\xF0\xF6\xF0\xF0" /* KEYD0600 */ +#undef Qc3_Key_CSLabel +#define Qc3_Key_CSLabel "\xD2\xC5\xE8\xC4\xF0\xF7\xF0\xF0" /* KEYD0700 */ +#undef Qc3_Key_CSDN +#define Qc3_Key_CSDN "\xD2\xC5\xE8\xC4\xF0\xF8\xF0\xF0" /* KEYD0800 */ +#undef Qc3_Key_AppID +#define Qc3_Key_AppID "\xD2\xC5\xE8\xC4\xF0\xF9\xF0\xF0" /* KEYD0900 */ + +#undef Qc3_ECB +#define Qc3_ECB '\xF0' /* '0' */ +#undef Qc3_CBC +#define Qc3_CBC '\xF1' /* '1' */ +#undef Qc3_OFB +#define Qc3_OFB '\xF2' /* '2' */ +#undef Qc3_CFB1Bit +#define Qc3_CFB1Bit '\xF3' /* '3' */ +#undef Qc3_CFB8Bit +#define Qc3_CFB8Bit '\xF4' /* '4' */ +#undef Qc3_CFB64Bit +#define Qc3_CFB64Bit '\xF5' /* '5' */ +#undef Qc3_CUSP +#define Qc3_CUSP '\xF6' /* '6' */ +#undef Qc3_CTR +#define Qc3_CTR '\xF7' /* '7' */ +#undef Qc3_CCM +#define Qc3_CCM '\xF8' /* '8' */ +#undef Qc3_No_Pad +#define Qc3_No_Pad '\xF0' /* '0' */ +#undef Qc3_Pad_Char +#define Qc3_Pad_Char '\xF1' /* '1' */ +#undef Qc3_Pad_Counter +#define Qc3_Pad_Counter '\xF2' /* '2' */ +#undef Qc3_PKCS1_00 +#define Qc3_PKCS1_00 '\xF0' /* '0' */ +#undef Qc3_PKCS1_01 +#define Qc3_PKCS1_01 '\xF1' /* '1' */ +#undef Qc3_PKCS1_02 +#define Qc3_PKCS1_02 '\xF2' /* '2' */ +#undef Qc3_ISO9796 +#define Qc3_ISO9796 '\xF3' /* '3' */ +#undef Qc3_Zero_Pad +#define Qc3_Zero_Pad '\xF4' /* '4' */ +#undef Qc3_ANSI_X931 +#define Qc3_ANSI_X931 '\xF5' /* '5' */ +#undef Qc3_OAEP +#define Qc3_OAEP '\xF6' /* '6' */ +#undef Qc3_Bin_String +#define Qc3_Bin_String '\xF0' /* '0' */ +#undef Qc3_BER_String +#define Qc3_BER_String '\xF1' /* '1' */ +#undef Qc3_MK_Struct +#define Qc3_MK_Struct '\xF3' /* '3' */ +#undef Qc3_KSLabel_Struct +#define Qc3_KSLabel_Struct '\xF4' /* '4' */ +#undef Qc3_PKCS5_Struct +#define Qc3_PKCS5_Struct '\xF5' /* '5' */ +#undef Qc3_PEMCert_String +#define Qc3_PEMCert_String '\xF6' /* '6' */ +#undef Qc3_CSLabel_String +#define Qc3_CSLabel_String '\xF7' /* '7' */ +#undef Qc3_CSDN_String +#define Qc3_CSDN_String '\xF8' /* '8' */ +#undef Qc3_Clear +#define Qc3_Clear '\xF0' /* '0' */ +#undef Qc3_Encrypted +#define Qc3_Encrypted '\xF1' /* '1' */ +#undef Qc3_MK_Encrypted +#define Qc3_MK_Encrypted '\xF2' /* '2' */ +#undef Qc3_Any_CSP +#define Qc3_Any_CSP '\xF0' /* '0' */ +#undef Qc3_Sfw_CSP +#define Qc3_Sfw_CSP '\xF1' /* '1' */ +#undef Qc3_Hdw_CSP +#define Qc3_Hdw_CSP '\xF2' /* '2' */ +#undef Qc3_Continue +#define Qc3_Continue '\xF0' /* '0' */ +#undef Qc3_Final +#define Qc3_Final '\xF1' /* '1' */ +#undef Qc3_MK_New +#define Qc3_MK_New '\xF0' /* '0' */ +#undef Qc3_MK_Current +#define Qc3_MK_Current '\xF1' /* '1' */ +#undef Qc3_MK_Old +#define Qc3_MK_Old '\xF2' /* '2' */ +#undef Qc3_MK_Pending +#define Qc3_MK_Pending '\xF3' /* '3' */ + +/* Define which features are supported. */ +#ifdef OPENSSL_NO_MD5 +# define LIBSSH2_MD5 0 +#else +# define LIBSSH2_MD5 1 +#endif + +#define LIBSSH2_HMAC_RIPEMD 0 +#define LIBSSH2_HMAC_SHA256 1 +#define LIBSSH2_HMAC_SHA512 1 + +#define LIBSSH2_AES_CBC 1 +#define LIBSSH2_AES_CTR 1 +#define LIBSSH2_AES_GCM 0 +#define LIBSSH2_BLOWFISH 0 +#define LIBSSH2_RC4 1 +#define LIBSSH2_CAST 0 +#define LIBSSH2_3DES 1 + +#define LIBSSH2_RSA 1 +#define LIBSSH2_RSA_SHA1 1 +#define LIBSSH2_RSA_SHA2 1 +#define LIBSSH2_DSA 0 +#define LIBSSH2_ECDSA 0 +#define LIBSSH2_ED25519 0 + +#include "crypto_config.h" + +#define SHA_DIGEST_LENGTH 20 +#define SHA256_DIGEST_LENGTH 32 +#define SHA384_DIGEST_LENGTH 48 +#define SHA512_DIGEST_LENGTH 64 + +#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) + +#if LIBSSH2_ECDSA +#else +#define _libssh2_ec_key void +#endif + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: global handles structures. + * + *******************************************************************/ + +/* HMAC & private key algorithms support structure. */ +typedef struct _libssh2_os400qc3_crypto_ctx _libssh2_os400qc3_crypto_ctx; +struct _libssh2_os400qc3_crypto_ctx { + Qc3_Format_ALGD0100_T hash; /* Hash algorithm. */ + Qc3_Format_KEYD0100_T key; /* Key. */ + _libssh2_os400qc3_crypto_ctx * kek; /* Key encryption. */ +}; + +typedef struct { /* Big number. */ + unsigned char * bignum; /* Number bits, little-endian. */ + unsigned int length; /* Length of bignum (# bytes). */ +} _libssh2_bn; + +typedef struct { /* Algorithm description. */ + char * fmt; /* Format of Qc3 structure. */ + int algo; /* Algorithm identifier. */ + unsigned char size; /* Block length. */ + unsigned char mode; /* Block mode. */ + int keylen; /* Key length. */ +} _libssh2_os400qc3_cipher_t; + +typedef struct { /* Diffie-Hellman context. */ + char token[8]; /* Context token. */ +} _libssh2_os400qc3_dh_ctx; + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: Define global types/codes. + * + *******************************************************************/ + +#define libssh2_crypto_init() +#define libssh2_crypto_exit() + +#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_hmac_ctx _libssh2_os400qc3_crypto_ctx +#define _libssh2_cipher_ctx _libssh2_os400qc3_crypto_ctx + +#define libssh2_sha1_init(x) _libssh2_os400qc3_hash_init(x, Qc3_SHA1) +#define libssh2_sha1_update(ctx, data, len) \ + _libssh2_os400qc3_hash_update(&(ctx), data, len) +#define libssh2_sha1_final(ctx, out) \ + _libssh2_os400qc3_hash_final(&(ctx), out) +#define libssh2_sha256_init(x) _libssh2_os400qc3_hash_init(x, Qc3_SHA256) +#define libssh2_sha256_update(ctx, data, len) \ + _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) \ + _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) +#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) + +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM +#define MD5_DIGEST_LENGTH 16 +#define libssh2_md5_ctx Qc3_Format_ALGD0100_T +#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) +#define libssh2_md5_final(ctx, out) \ + _libssh2_os400qc3_hash_final(&(ctx), out) +#endif + +#define _libssh2_bn_ctx int /* Not used. */ + +#define _libssh2_bn_ctx_new() 0 +#define _libssh2_bn_ctx_free(bnctx) ((void) 0) + +#define _libssh2_bn_init_from_bin() _libssh2_bn_init() +#define _libssh2_bn_bytes(bn) ((bn)->length) + +#define _libssh2_cipher_type(name) _libssh2_os400qc3_cipher_t name +#define _libssh2_cipher_aes128 {Qc3_Alg_Block_Cipher, Qc3_AES, 16, \ + Qc3_CBC, 16} +#define _libssh2_cipher_aes192 {Qc3_Alg_Block_Cipher, Qc3_AES, 16, \ + Qc3_CBC, 24} +#define _libssh2_cipher_aes256 {Qc3_Alg_Block_Cipher, Qc3_AES, 16, \ + Qc3_CBC, 32} +#define _libssh2_cipher_aes128ctr {Qc3_Alg_Block_Cipher, Qc3_AES, 16, \ + Qc3_CTR, 16} +#define _libssh2_cipher_aes192ctr {Qc3_Alg_Block_Cipher, Qc3_AES, 16, \ + Qc3_CTR, 24} +#define _libssh2_cipher_aes256ctr {Qc3_Alg_Block_Cipher, Qc3_AES, 16, \ + Qc3_CTR, 32} +#define _libssh2_cipher_3des {Qc3_Alg_Block_Cipher, Qc3_TDES, 8, \ + Qc3_CBC, 24} +/* Nonsense values for chacha20-poly1305 */ +#define _libssh2_cipher_chacha20 {Qc3_Alg_Stream_Cipher, Qc3_RC4, 8, 0, 16} +#define _libssh2_cipher_arcfour {Qc3_Alg_Stream_Cipher, Qc3_RC4, 8, 0, 16} + +#define _libssh2_cipher_dtor(ctx) _libssh2_os400qc3_crypto_dtor(ctx) + +#define libssh2_rsa_ctx _libssh2_os400qc3_crypto_ctx +#define _libssh2_rsa_free(ctx) (_libssh2_os400qc3_crypto_dtor(ctx), \ + free((char *) ctx)) +#define libssh2_prepare_iovec(vec, len) memset((char *) (vec), 0, \ + (len) * sizeof(struct iovec)) +#define _libssh2_rsa_sha1_signv(session, sig, siglen, count, vector, ctx) \ + _libssh2_os400qc3_rsa_signv(session, Qc3_SHA1, sig, siglen, \ + count, vector, ctx) +#define _libssh2_rsa_sha2_256_signv(session, sig, siglen, cnt, vector, ctx) \ + _libssh2_os400qc3_rsa_signv(session, Qc3_SHA256, sig, siglen, \ + cnt, vector, ctx) +#define _libssh2_rsa_sha2_512_signv(session, sig, siglen, cnt, vector, ctx) \ + _libssh2_os400qc3_rsa_signv(session, Qc3_SHA512, sig, siglen, \ + cnt, vector, ctx) + +/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 + Qc3 is limited to a maximum 2048-bit modulus/key size. */ +#define LIBSSH2_DH_GEX_MINGROUP 1024 +#define LIBSSH2_DH_GEX_OPTGROUP 1536 +#define LIBSSH2_DH_GEX_MAXGROUP 2048 + +#define LIBSSH2_DH_MAX_MODULUS_BITS 2048 + +#define _libssh2_dh_ctx _libssh2_os400qc3_dh_ctx +#define libssh2_dh_init(dhctx) _libssh2_os400qc3_dh_init(dhctx) +#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ + _libssh2_os400qc3_dh_key_pair(dhctx, public, g, p, group_order) +#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ + _libssh2_os400qc3_dh_secret(dhctx, secret, f, p) +#define libssh2_dh_dtor(dhctx) _libssh2_os400qc3_dh_dtor(dhctx) + + +/******************************************************************* + * + * OS/400 QC3 crypto-library backend: Support procedure prototypes. + * + *******************************************************************/ + +extern _libssh2_bn * _libssh2_bn_init(void); +extern void _libssh2_bn_free(_libssh2_bn *bn); +extern unsigned long _libssh2_bn_bits(_libssh2_bn *bn); +extern int _libssh2_bn_from_bin(_libssh2_bn *bn, size_t 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 int _libssh2_random(unsigned char *buf, size_t 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); +extern int _libssh2_os400qc3_hash_update(Qc3_Format_ALGD0100_T *ctx, + const unsigned char *data, + int len); +extern int _libssh2_os400qc3_hash_final(Qc3_Format_ALGD0100_T *ctx, + unsigned char *out); +extern int _libssh2_os400qc3_hash(const unsigned char *message, + unsigned long len, unsigned char *out, + unsigned int algo); +extern int _libssh2_os400qc3_rsa_signv(LIBSSH2_SESSION *session, int algo, + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec vector[], + libssh2_rsa_ctx *ctx); +extern void _libssh2_os400qc3_dh_init(_libssh2_dh_ctx *dhctx); +extern int _libssh2_os400qc3_dh_key_pair(_libssh2_dh_ctx *dhctx, + _libssh2_bn *public, + _libssh2_bn *g, + _libssh2_bn *p, int group_order); +extern int _libssh2_os400qc3_dh_secret(_libssh2_dh_ctx *dhctx, + _libssh2_bn *secret, + _libssh2_bn *f, _libssh2_bn *p); +extern void _libssh2_os400qc3_dh_dtor(_libssh2_dh_ctx *dhctx); + +#endif /* LIBSSH2_OS400QC3_H */ + +/* vim: set expandtab ts=4 sw=4: */ diff --git a/uppsrc/Core/SSH/libssh2/packet.c b/uppsrc/Core/SSH/libssh2/packet.c index 04937d62a..6da14e9fa 100644 --- a/uppsrc/Core/SSH/libssh2/packet.c +++ b/uppsrc/Core/SSH/libssh2/packet.c @@ -1,7 +1,7 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2005,2006 Mikhail Gusarov - * Copyright (c) 2009-2014 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson +/* Copyright (C) Sara Golemon + * Copyright (C) Mikhail Gusarov + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,31 +36,23 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include -#include #ifdef HAVE_UNISTD_H #include #endif - -#ifdef HAVE_SYS_TIME_H -#include -#endif - #ifdef HAVE_INTTYPES_H #include #endif - /* Needed for struct iovec on some platforms */ #ifdef HAVE_SYS_UIO_H #include #endif -#include - #include "transport.h" #include "channel.h" #include "packet.h" @@ -72,21 +64,21 @@ */ static inline int packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long datalen, + size_t datalen, packet_queue_listener_state_t *listen_state) { /* * Look for a matching listener */ /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1); + size_t packet_len = 17 + strlen(FwdNotReq); unsigned char *p; LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners); char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; int rc; if(listen_state->state == libssh2_NB_state_idle) { - unsigned long offset = (sizeof("forwarded-tcpip") - 1) + 5; + size_t offset = strlen("forwarded-tcpip") + 5; size_t temp_len = 0; struct string_buf buf; buf.data = data; @@ -133,10 +125,10 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, "Data too short extracting sport"); } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Remote received connection from %s:%ld to %s:%ld", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Remote received connection from %s:%u to %s:%u", listen_state->shost, listen_state->sport, - listen_state->host, listen_state->port); + listen_state->host, listen_state->port)); listen_state->state = libssh2_NB_state_allocated; } @@ -145,8 +137,8 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, while(listn) { if((listn->port == (int) listen_state->port) && (strlen(listn->host) == listen_state->host_len) && - (memcmp (listn->host, listen_state->host, - listen_state->host_len) == 0)) { + (memcmp(listn->host, listen_state->host, + listen_state->host_len) == 0)) { /* This is our listener */ LIBSSH2_CHANNEL *channel = NULL; listen_state->channel = NULL; @@ -156,8 +148,8 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, (listn->queue_maxsize <= listn->queue_size)) { /* Queue is full */ failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Listener queue full, ignoring"); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Listener queue full, ignoring")); listen_state->state = libssh2_NB_state_sent; break; } @@ -174,7 +166,7 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, listen_state->channel = channel; channel->session = session; - channel->channel_type_len = sizeof("forwarded-tcpip") - 1; + channel->channel_type_len = strlen("forwarded-tcpip"); channel->channel_type = LIBSSH2_ALLOC(session, channel-> channel_type_len + @@ -206,14 +198,14 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, listen_state->initial_window_size; channel->local.packet_size = listen_state->packet_size; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Connection queued: channel %lu/%lu " - "win %lu/%lu packet %lu/%lu", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Connection queued: channel %u/%u " + "win %u/%u packet %u/%u", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, - channel->remote.packet_size); + channel->remote.packet_size)); p = listen_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; @@ -261,7 +253,7 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; _libssh2_store_u32(&p, listen_state->sender_channel); _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1); + _libssh2_store_str(&p, FwdNotReq, strlen(FwdNotReq)); _libssh2_htonu32(p, 0); rc = _libssh2_transport_send(session, listen_state->packet, @@ -285,19 +277,19 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, */ static inline int packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long datalen, + size_t datalen, packet_x11_open_state_t *x11open_state) { int failure_code = SSH_OPEN_CONNECT_FAILED; /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); + size_t packet_len = 17 + strlen(X11FwdUnAvil); unsigned char *p; LIBSSH2_CHANNEL *channel = x11open_state->channel; int rc; if(x11open_state->state == libssh2_NB_state_idle) { - unsigned long offset = (sizeof("x11") - 1) + 5; + size_t offset = strlen("x11") + 5; size_t temp_len = 0; struct string_buf buf; buf.data = data; @@ -346,10 +338,10 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, goto x11_exit; } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "X11 Connection Received from %s:%ld on channel %lu", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "X11 Connection Received from %s:%u on channel %u", x11open_state->shost, x11open_state->sport, - x11open_state->sender_channel); + x11open_state->sender_channel)); x11open_state->state = libssh2_NB_state_allocated; } @@ -365,7 +357,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, } channel->session = session; - channel->channel_type_len = sizeof("x11") - 1; + channel->channel_type_len = strlen("x11"); channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1); @@ -391,14 +383,14 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, channel->local.window_size = x11open_state->initial_window_size; channel->local.packet_size = x11open_state->packet_size; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "X11 Connection established: channel %lu/%lu " - "win %lu/%lu packet %lu/%lu", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "X11 Connection established: channel %u/%u " + "win %u/%u packet %u/%u", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, - channel->remote.packet_size); + channel->remote.packet_size)); p = x11open_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; _libssh2_store_u32(&p, channel->remote.id); @@ -439,12 +431,12 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, else failure_code = SSH_OPEN_RESOURCE_SHORTAGE; /* fall-trough */ - x11_exit: +x11_exit: p = x11open_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; _libssh2_store_u32(&p, x11open_state->sender_channel); _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1); + _libssh2_store_str(&p, X11FwdUnAvil, strlen(X11FwdUnAvil)); _libssh2_htonu32(p, 0); rc = _libssh2_transport_send(session, x11open_state->packet, packet_len, @@ -460,6 +452,171 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, return 0; } +/* + * packet_authagent_open + * + * Open a connection to authentication agent + */ +static inline int +packet_authagent_open(LIBSSH2_SESSION * session, + unsigned char *data, size_t datalen, + packet_authagent_state_t *authagent_state) +{ + int failure_code = SSH_OPEN_CONNECT_FAILED; + /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ + size_t packet_len = 17 + strlen(X11FwdUnAvil); + unsigned char *p; + LIBSSH2_CHANNEL *channel = authagent_state->channel; + int rc; + struct string_buf buf; + size_t offset = strlen("auth-agent@openssh.org") + 5; + + buf.data = data; + buf.dataptr = buf.data; + buf.len = datalen; + + buf.dataptr += offset; + + if(datalen < offset) { + return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Unexpected packet size"); + } + + if(authagent_state->state == libssh2_NB_state_idle) { + if(_libssh2_get_u32(&buf, &(authagent_state->sender_channel))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting channel"); + } + if(_libssh2_get_u32(&buf, &(authagent_state->initial_window_size))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting window size"); + } + if(_libssh2_get_u32(&buf, &(authagent_state->packet_size))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting packet"); + } + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Auth Agent Connection Received on channel %u", + authagent_state->sender_channel)); + + authagent_state->state = libssh2_NB_state_allocated; + } + + if(session->authagent) { + if(authagent_state->state == libssh2_NB_state_allocated) { + channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); + authagent_state->channel = channel; + + if(!channel) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "allocate a channel for new connection"); + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + goto authagent_exit; + } + memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); + + channel->session = session; + channel->channel_type_len = strlen("auth agent"); + channel->channel_type = LIBSSH2_ALLOC(session, + channel->channel_type_len + + 1); + if(!channel->channel_type) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "allocate a channel for new connection"); + LIBSSH2_FREE(session, channel); + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + goto authagent_exit; + } + memcpy(channel->channel_type, "auth agent", + channel->channel_type_len + 1); + + channel->remote.id = authagent_state->sender_channel; + channel->remote.window_size_initial = + LIBSSH2_CHANNEL_WINDOW_DEFAULT; + channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT; + channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT; + + channel->local.id = _libssh2_channel_nextid(session); + channel->local.window_size_initial = + authagent_state->initial_window_size; + channel->local.window_size = authagent_state->initial_window_size; + channel->local.packet_size = authagent_state->packet_size; + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Auth Agent Connection established: channel " + "%u/%u win %u/%u packet %u/%u", + channel->local.id, channel->remote.id, + channel->local.window_size, + channel->remote.window_size, + channel->local.packet_size, + channel->remote.packet_size)); + + p = authagent_state->packet; + *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; + _libssh2_store_u32(&p, channel->remote.id); + _libssh2_store_u32(&p, channel->local.id); + _libssh2_store_u32(&p, channel->remote.window_size_initial); + _libssh2_store_u32(&p, channel->remote.packet_size); + + authagent_state->state = libssh2_NB_state_created; + } + + if(authagent_state->state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, authagent_state->packet, 17, + NULL, 0); + if(rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + else if(rc) { + authagent_state->state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send channel open " + "confirmation"); + } + + /* Link the channel into the session */ + _libssh2_list_add(&session->channels, &channel->node); + + /* mess with stuff so we don't keep reading the same packet + over and over */ + session->packet.total_num = 0; + session->fullpacket_state = libssh2_NB_state_idle; + + /* Pass control to the callback, they may turn right around and + and free the channel, or actually use it */ + + LIBSSH2_AUTHAGENT(channel); + + authagent_state->state = libssh2_NB_state_idle; + return 0; + } + } + else + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + + /* fall-through */ +authagent_exit: + p = authagent_state->packet; + *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; + _libssh2_store_u32(&p, authagent_state->sender_channel); + _libssh2_store_u32(&p, failure_code); + _libssh2_store_str(&p, AuthAgentUnavail, strlen(AuthAgentUnavail)); + _libssh2_htonu32(p, 0); + + rc = _libssh2_transport_send(session, authagent_state->packet, packet_len, + NULL, 0); + if(rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + else if(rc) { + authagent_state->state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, "Unable to send open failure"); + } + authagent_state->state = libssh2_NB_state_idle; + return 0; +} + /* * _libssh2_packet_add * @@ -467,14 +624,13 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, * layer when it has received a packet. * * The input pointer 'data' is pointing to allocated data that this function - * is asked to deal with so on failure OR success, it must be freed fine. - * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN. + * will be freed unless return the code is LIBSSH2_ERROR_EAGAIN. * * This function will always be called with 'datalen' greater than zero. */ int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, - size_t datalen, int macstate) + size_t datalen, int macstate, uint32_t seq) { int rc = 0; unsigned char *message = NULL; @@ -487,9 +643,9 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, switch(session->packAdd_state) { case libssh2_NB_state_idle: - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Packet type %d received, length=%d", - (int) msg, (int) datalen); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Packet type %u received, length=%ld", + (unsigned int) msg, (long) datalen)); if((macstate == LIBSSH2_MAC_INVALID) && (!session->macerror || @@ -513,10 +669,76 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, goto libssh2_packet_add_jump_point4; case libssh2_NB_state_jump5: goto libssh2_packet_add_jump_point5; + case libssh2_NB_state_jumpauthagent: + goto libssh2_packet_add_jump_authagent; default: /* nothing to do */ break; } + if(session->state & LIBSSH2_STATE_INITIAL_KEX) { + if(msg == SSH_MSG_KEXINIT) { + if(!session->kex_strict) { + if(datalen < 17) { + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return _libssh2_error(session, + LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting kex"); + } + else { + const unsigned char *strict = + (unsigned char *)"kex-strict-s-v00@openssh.com"; + struct string_buf buf; + unsigned char *algs = NULL; + size_t algs_len = 0; + + buf.data = (unsigned char *)data; + buf.dataptr = buf.data; + buf.len = datalen; + buf.dataptr += 17; /* advance past type and cookie */ + + if(_libssh2_get_string(&buf, &algs, &algs_len)) { + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return _libssh2_error(session, + LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Algs too short"); + } + + if(algs_len == 0 || + _libssh2_kex_agree_instr(algs, algs_len, strict, 28)) { + session->kex_strict = 1; + } + } + } + + if(session->kex_strict && seq) { + LIBSSH2_FREE(session, data); + session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; + session->packAdd_state = libssh2_NB_state_idle; + libssh2_session_disconnect(session, "strict KEX violation: " + "KEXINIT was not the first packet"); + + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "strict KEX violation: " + "KEXINIT was not the first packet"); + } + } + + if(session->kex_strict && session->fullpacket_required_type && + session->fullpacket_required_type != msg) { + LIBSSH2_FREE(session, data); + session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; + session->packAdd_state = libssh2_NB_state_idle; + libssh2_session_disconnect(session, "strict KEX violation: " + "unexpected packet type"); + + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "strict KEX violation: " + "unexpected packet type"); + } + } + if(session->packAdd_state == libssh2_NB_state_allocated) { /* A couple exceptions to the packet adding rule: */ switch(msg) { @@ -547,9 +769,9 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, language_len); } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Disconnect(%d): %s(%s)", reason, - message, language); + message, language)); } LIBSSH2_FREE(session, data); @@ -606,15 +828,85 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, } /* - * _libssh2_debug will actually truncate this for us so + * _libssh2_debug() will actually truncate this for us so * that it's not an inordinate about of data */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Debug Packet: %s", message); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Debug Packet: %s", message)); LIBSSH2_FREE(session, data); session->packAdd_state = libssh2_NB_state_idle; return 0; + /* + byte SSH_MSG_EXT_INFO + uint32 nr-extensions + [repeat "nr-extensions" times] + string extension-name [RFC8308] + string extension-value (binary) + */ + + case SSH_MSG_EXT_INFO: + if(datalen >= 5) { + uint32_t nr_extensions = 0; + struct string_buf buf; + buf.data = (unsigned char *)data; + buf.dataptr = buf.data; + buf.len = datalen; + buf.dataptr += 1; /* advance past type */ + + if(_libssh2_get_u32(&buf, &nr_extensions) != 0) { + rc = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid extension info received"); + } + + while(rc == 0 && nr_extensions > 0) { + + size_t name_len = 0; + size_t value_len = 0; + unsigned char *name = NULL; + unsigned char *value = NULL; + + nr_extensions -= 1; + + _libssh2_get_string(&buf, &name, &name_len); + _libssh2_get_string(&buf, &value, &value_len); + + if(name && value) { + _libssh2_debug((session, + LIBSSH2_TRACE_KEX, + "Server to Client extension %.*s: %.*s", + (int)name_len, name, + (int)value_len, value)); + } + + if(name_len == 15 && + memcmp(name, "server-sig-algs", 15) == 0) { + if(session->server_sign_algorithms) { + LIBSSH2_FREE(session, + session->server_sign_algorithms); + } + + session->server_sign_algorithms = + LIBSSH2_ALLOC(session, + value_len + 1); + + if(session->server_sign_algorithms) { + memcpy(session->server_sign_algorithms, + value, value_len); + session->server_sign_algorithms[value_len] = '\0'; + } + else { + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "memory for server sign algo"); + } + } + } + } + + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return rc; + /* byte SSH_MSG_GLOBAL_REQUEST string request name in US-ASCII only @@ -629,17 +921,17 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, len = _libssh2_ntohu32(data + 1); if((len <= (UINT_MAX - 6)) && (datalen >= (6 + len))) { want_reply = data[5 + len]; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Received global request type %.*s (wr %X)", - len, data + 5, want_reply); + (int)len, data + 5, want_reply)); } if(want_reply) { static const unsigned char packet = SSH_MSG_REQUEST_FAILURE; - libssh2_packet_add_jump_point5: +libssh2_packet_add_jump_point5: session->packAdd_state = libssh2_NB_state_jump5; rc = _libssh2_transport_send(session, &packet, 1, NULL, 0); if(rc == LIBSSH2_ERROR_EAGAIN) @@ -661,7 +953,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, /* streamid(4) */ data_head += 4; - /* fall-through */ + LIBSSH2_FALLTHROUGH(); /* byte SSH_MSG_CHANNEL_DATA @@ -691,12 +983,12 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(msg == SSH_MSG_CHANNEL_EXTENDED_DATA) stream_id = _libssh2_ntohu32(data + 5); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "%d bytes packet_add() for %lu/%lu/%lu", - (int) (datalen - data_head), + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "%ld bytes packet_add() for %u/%u/%u", + (long) (datalen - data_head), channelp->local.id, channelp->remote.id, - stream_id); + stream_id)); } #endif if((channelp->remote.extended_data_ignore_mode == @@ -705,30 +997,31 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, /* Pretend we didn't receive this */ LIBSSH2_FREE(session, data); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Ignoring extended data and refunding %d bytes", - (int) (datalen - 13)); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Ignoring extended data and refunding %ld bytes", + (long) (datalen - 13))); if(channelp->read_avail + datalen - data_head >= channelp->remote.window_size) datalen = channelp->remote.window_size - channelp->read_avail + data_head; - channelp->remote.window_size -= datalen - data_head; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "shrinking window size by %lu bytes to %lu, " - "read_avail %lu", - datalen - data_head, + channelp->remote.window_size -= (uint32_t)(datalen - + data_head); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "shrinking window size by %ld bytes to %u, " + "read_avail %ld", + (long) (datalen - data_head), channelp->remote.window_size, - channelp->read_avail); + (long) channelp->read_avail)); session->packAdd_channelp = channelp; /* Adjust the window based on the block we just freed */ - libssh2_packet_add_jump_point1: +libssh2_packet_add_jump_point1: session->packAdd_state = libssh2_NB_state_jump1; rc = _libssh2_channel_receive_window_adjust(session-> packAdd_channelp, - datalen - 13, + (uint32_t)(datalen - 13), 1, NULL); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -746,8 +1039,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, * Spec says we MAY ignore bytes sent beyond * packet_size */ - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "Packet contains more data than we offered" " to receive, truncating"); datalen = channelp->remote.packet_size + data_head; @@ -757,8 +1049,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, * Spec says we MAY ignore bytes sent beyond * window_size */ - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "The current receive window is full," " data ignored"); LIBSSH2_FREE(session, data); @@ -770,8 +1061,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(channelp->read_avail + datalen - data_head > channelp->remote.window_size) { - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "Remote sent more data than current " "window allows, truncating"); datalen = channelp->remote.window_size - @@ -783,11 +1073,11 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, * from an upper layer */ channelp->read_avail += datalen - data_head; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "increasing read_avail by %lu bytes to %lu/%lu", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "increasing read_avail by %ld bytes to %ld/%u", (long)(datalen - data_head), (long)channelp->read_avail, - (long)channelp->remote.window_size); + channelp->remote.window_size)); break; @@ -805,11 +1095,11 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, /* We may have freed already, just quietly ignore this... */ ; else { - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "EOF received for channel %lu/%lu", + "EOF received for channel %u/%u", channelp->local.id, - channelp->remote.id); + channelp->remote.id)); channelp->remote.eof = 1; } LIBSSH2_FREE(session, data); @@ -833,45 +1123,47 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if((len + 9) < datalen) want_reply = data[len + 9]; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Channel %d received request type %.*s (wr %X)", - channel, len, data + 9, want_reply); + "Channel %u received request type %.*s (wr %X)", + channel, (int)len, data + 9, want_reply)); - if(len == sizeof("exit-status") - 1 - && (sizeof("exit-status") - 1 + 9) <= datalen + if(len == strlen("exit-status") + && (strlen("exit-status") + 9) <= datalen && !memcmp("exit-status", data + 9, - sizeof("exit-status") - 1)) { + strlen("exit-status"))) { /* we've got "exit-status" packet. Set the session value */ if(datalen >= 20) channelp = _libssh2_channel_locate(session, channel); - if(channelp && (sizeof("exit-status") + 13) <= datalen) { + if(channelp && (strlen("exit-status") + 14) <= datalen) { channelp->exit_status = - _libssh2_ntohu32(data + 9 + sizeof("exit-status")); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Exit status %lu received for " - "channel %lu/%lu", + _libssh2_ntohu32(data + 10 + + strlen("exit-status")); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Exit status %d received for " + "channel %u/%u", channelp->exit_status, channelp->local.id, - channelp->remote.id); + channelp->remote.id)); } } - else if(len == sizeof("exit-signal") - 1 - && (sizeof("exit-signal") - 1 + 9) <= datalen + else if(len == strlen("exit-signal") + && (strlen("exit-signal") + 9) <= datalen && !memcmp("exit-signal", data + 9, - sizeof("exit-signal") - 1)) { + strlen("exit-signal"))) { /* command terminated due to signal */ if(datalen >= 20) channelp = _libssh2_channel_locate(session, channel); - if(channelp && (sizeof("exit-signal") + 13) <= datalen) { + if(channelp && (strlen("exit-signal") + 14) <= datalen) { /* set signal name (without SIG prefix) */ uint32_t namelen = - _libssh2_ntohu32(data + 9 + sizeof("exit-signal")); + _libssh2_ntohu32(data + 10 + + strlen("exit-signal")); if(namelen <= UINT_MAX - 1) { channelp->exit_signal = @@ -884,18 +1176,18 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(!channelp->exit_signal) rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "memory for signal name"); - else if((sizeof("exit-signal") + 13 + namelen <= + else if((strlen("exit-signal") + 14 + namelen <= datalen)) { memcpy(channelp->exit_signal, - data + 13 + sizeof("exit-signal"), namelen); + data + 14 + strlen("exit-signal"), namelen); channelp->exit_signal[namelen] = '\0'; /* TODO: save error message and language tag */ - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Exit signal %s received for " - "channel %lu/%lu", + "channel %u/%u", channelp->exit_signal, channelp->local.id, - channelp->remote.id); + channelp->remote.id)); } } } @@ -903,7 +1195,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(want_reply) { unsigned char packet[5]; - libssh2_packet_add_jump_point4: +libssh2_packet_add_jump_point4: session->packAdd_state = libssh2_NB_state_jump4; packet[0] = SSH_MSG_CHANNEL_FAILURE; memcpy(&packet[1], data + 1, 4); @@ -932,10 +1224,10 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, session->packAdd_state = libssh2_NB_state_idle; return 0; } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Close received for channel %lu/%lu", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Close received for channel %u/%u", channelp->local.id, - channelp->remote.id); + channelp->remote.id)); channelp->remote.close = 1; channelp->remote.eof = 1; @@ -955,35 +1247,50 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, case SSH_MSG_CHANNEL_OPEN: if(datalen < 17) ; - else if((datalen >= (sizeof("forwarded-tcpip") + 4)) && - ((sizeof("forwarded-tcpip") - 1) == + else if((datalen >= (strlen("forwarded-tcpip") + 5)) && + (strlen("forwarded-tcpip") == _libssh2_ntohu32(data + 1)) && (memcmp(data + 5, "forwarded-tcpip", - sizeof("forwarded-tcpip") - 1) == 0)) { + strlen("forwarded-tcpip")) == 0)) { /* init the state struct */ memset(&session->packAdd_Qlstn_state, 0, sizeof(session->packAdd_Qlstn_state)); - libssh2_packet_add_jump_point2: +libssh2_packet_add_jump_point2: session->packAdd_state = libssh2_NB_state_jump2; rc = packet_queue_listener(session, data, datalen, &session->packAdd_Qlstn_state); } - else if((datalen >= (sizeof("x11") + 4)) && - ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) && - (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) { + else if((datalen >= (strlen("x11") + 5)) && + ((strlen("x11")) == _libssh2_ntohu32(data + 1)) && + (memcmp(data + 5, "x11", strlen("x11")) == 0)) { /* init the state struct */ memset(&session->packAdd_x11open_state, 0, sizeof(session->packAdd_x11open_state)); - libssh2_packet_add_jump_point3: +libssh2_packet_add_jump_point3: session->packAdd_state = libssh2_NB_state_jump3; rc = packet_x11_open(session, data, datalen, &session->packAdd_x11open_state); } + else if((datalen >= (strlen("auth-agent@openssh.com") + 5)) && + (strlen("auth-agent@openssh.com") == + _libssh2_ntohu32(data + 1)) && + (memcmp(data + 5, "auth-agent@openssh.com", + strlen("auth-agent@openssh.com")) == 0)) { + + /* init the state struct */ + memset(&session->packAdd_authagent_state, 0, + sizeof(session->packAdd_authagent_state)); + +libssh2_packet_add_jump_authagent: + session->packAdd_state = libssh2_NB_state_jumpauthagent; + rc = packet_authagent_open(session, data, datalen, + &session->packAdd_authagent_state); + } if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -1007,13 +1314,13 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(channelp) { channelp->local.window_size += bytestoadd; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Window adjust for channel %lu/%lu, " - "adding %lu bytes, new window_size=%lu", + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Window adjust for channel %u/%u, " + "adding %u bytes, new window_size=%u", channelp->local.id, channelp->remote.id, bytestoadd, - channelp->local.window_size); + channelp->local.window_size)); } } LIBSSH2_FREE(session, data); @@ -1030,8 +1337,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, LIBSSH2_PACKET *packetp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET)); if(!packetp) { - _libssh2_debug(session, LIBSSH2_ERROR_ALLOC, - "memory for packet"); + _libssh2_debug((session, LIBSSH2_ERROR_ALLOC, + "memory for packet")); LIBSSH2_FREE(session, data); session->packAdd_state = libssh2_NB_state_idle; return LIBSSH2_ERROR_ALLOC; @@ -1054,7 +1361,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, * Well, it's already in the brigade, * let's just call back into ourselves */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Renegotiating Keys")); session->packAdd_state = libssh2_NB_state_sent2; } @@ -1099,8 +1407,9 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, { LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Looking for packet of type: %d", (int) packet_type); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Looking for packet of type: %u", + (unsigned int)packet_type)); while(packet) { if(packet->data[0] == packet_type @@ -1118,6 +1427,15 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, return 0; } + else if(session->kex_strict && + (session->state & LIBSSH2_STATE_INITIAL_KEX)) { + libssh2_session_disconnect(session, "strict KEX violation: " + "unexpected packet type"); + + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "strict KEX violation: " + "unexpected packet type"); + } packet = _libssh2_list_next(&packet->node); } return -1; @@ -1137,12 +1455,12 @@ _libssh2_packet_askv(LIBSSH2_SESSION * session, const unsigned char *match_buf, size_t match_len) { - int i, packet_types_len = strlen((char *) packet_types); + size_t i, packet_types_len = strlen((const char *) packet_types); for(i = 0; i < packet_types_len; i++) { - if(0 == _libssh2_packet_ask(session, packet_types[i], data, - data_len, match_ofs, - match_buf, match_len)) { + if(_libssh2_packet_ask(session, packet_types[i], data, + data_len, match_ofs, + match_buf, match_len) == 0) { return 0; } } @@ -1169,8 +1487,8 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, { if(state->start == 0) { if(_libssh2_packet_ask(session, packet_type, data, data_len, - match_ofs, match_buf, - match_len) == 0) { + match_ofs, match_buf, + match_len) == 0) { /* A packet was available in the packet brigade */ return 0; } @@ -1179,7 +1497,10 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, } while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - int ret = _libssh2_transport_read(session); + int ret; + session->fullpacket_required_type = packet_type; + ret = _libssh2_transport_read(session); + session->fullpacket_required_type = 0; if(ret == LIBSSH2_ERROR_EAGAIN) return ret; else if(ret < 0) { @@ -1196,8 +1517,8 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, } else if(ret == 0) { /* nothing available, wait until data arrives or we time out */ - long left = LIBSSH2_READ_TIMEOUT - (long)(time(NULL) - - state->start); + long left = session->packet_read_timeout - (long)(time(NULL) - + state->start); if(left <= 0) { state->start = 0; @@ -1234,15 +1555,15 @@ _libssh2_packet_burn(LIBSSH2_SESSION * session, all_packets[254] = 0; if(_libssh2_packet_askv(session, all_packets, &data, &data_len, 0, - NULL, 0) == 0) { + NULL, 0) == 0) { i = data[0]; /* A packet was available in the packet brigade, burn it */ LIBSSH2_FREE(session, data); return i; } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Blocking until packet becomes available to burn"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Blocking until packet becomes available to burn")); *state = libssh2_NB_state_created; } @@ -1263,7 +1584,7 @@ _libssh2_packet_burn(LIBSSH2_SESSION * session, /* Be lazy, let packet_ask pull it out of the brigade */ if(0 == _libssh2_packet_ask(session, (unsigned char)ret, - &data, &data_len, 0, NULL, 0)) { + &data, &data_len, 0, NULL, 0)) { /* Smoke 'em if you got 'em */ LIBSSH2_FREE(session, data); *state = libssh2_NB_state_idle; @@ -1292,7 +1613,7 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session, packet_requirev_state_t * state) { if(_libssh2_packet_askv(session, packet_types, data, data_len, match_ofs, - match_buf, match_len) == 0) { + match_buf, match_len) == 0) { /* One of the packets listed was available in the packet brigade */ state->start = 0; return 0; @@ -1309,7 +1630,7 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session, return ret; } if(ret <= 0) { - long left = LIBSSH2_READ_TIMEOUT - + long left = session->packet_read_timeout - (long)(time(NULL) - state->start); if(left <= 0) { @@ -1323,9 +1644,9 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session, if(strchr((char *) packet_types, ret)) { /* Be lazy, let packet_ask pull it out of the brigade */ - int ret = _libssh2_packet_askv(session, packet_types, data, - data_len, match_ofs, match_buf, - match_len); + ret = _libssh2_packet_askv(session, packet_types, data, + data_len, match_ofs, match_buf, + match_len); state->start = 0; return ret; } @@ -1335,4 +1656,3 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session, state->start = 0; return LIBSSH2_ERROR_SOCKET_DISCONNECT; } - diff --git a/uppsrc/Core/SSH/libssh2/packet.h b/uppsrc/Core/SSH/libssh2/packet.h index 79018bcf1..955351e5f 100644 --- a/uppsrc/Core/SSH/libssh2/packet.h +++ b/uppsrc/Core/SSH/libssh2/packet.h @@ -1,8 +1,8 @@ -#ifndef __LIBSSH2_PACKET_H -#define __LIBSSH2_PACKET_H +#ifndef LIBSSH2_PACKET_H +#define LIBSSH2_PACKET_H /* - * Copyright (C) 2010 by Daniel Stenberg - * Author: Daniel Stenberg + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -37,6 +37,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ int _libssh2_packet_read(LIBSSH2_SESSION * session); @@ -71,6 +72,6 @@ int _libssh2_packet_burn(LIBSSH2_SESSION * session, int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data, unsigned long data_len); int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, - size_t datalen, int macstate); + size_t datalen, int macstate, uint32_t seq); -#endif /* __LIBSSH2_PACKET_H */ +#endif /* LIBSSH2_PACKET_H */ diff --git a/uppsrc/Core/SSH/libssh2/pem.c b/uppsrc/Core/SSH/libssh2/pem.c index 3416bd528..c9ab77469 100644 --- a/uppsrc/Core/SSH/libssh2/pem.c +++ b/uppsrc/Core/SSH/libssh2/pem.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2007 The Written Word, Inc. - * Copyright (C) 2008, Simon Josefsson +/* Copyright (C) The Written Word, Inc. + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,6 +34,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -100,7 +102,8 @@ static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED"; static unsigned char hex_decode(char digit) { - return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0'); + return (unsigned char) + ((digit >= 'A') ? (0xA + (digit - 'A')) : (digit - '0')); } int @@ -108,12 +111,12 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const unsigned char *passphrase, - FILE * fp, unsigned char **data, unsigned int *datalen) + FILE * fp, unsigned char **data, size_t *datalen) { char line[LINE_SIZE]; unsigned char iv[LINE_SIZE]; char *b64data = NULL; - unsigned int b64datalen = 0; + size_t b64datalen = 0; int ret; const LIBSSH2_CRYPT_METHOD *method = NULL; @@ -123,8 +126,7 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, if(readline(line, LINE_SIZE, fp)) { return -1; } - } - while(strcmp(line, headerbegin) != 0); + } while(strcmp(line, headerbegin) != 0); if(readline(line, LINE_SIZE, fp)) { return -1; @@ -141,7 +143,8 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, } all_methods = libssh2_crypt_methods(); - while((cur_method = *all_methods++)) { + /* !checksrc! disable EQUALSNULL 1 */ + while((cur_method = *all_methods++) != NULL) { if(*cur_method->pem_annotation && memcmp(line, cur_method->pem_annotation, strlen(cur_method->pem_annotation)) == 0) { @@ -152,12 +155,12 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, } /* None of the available crypt methods were able to decrypt the key */ - if(method == NULL) + if(!method) return -1; /* Decode IV from hex */ for(i = 0; i < method->iv_len; ++i) { - iv[i] = hex_decode(iv[2*i]) << 4; + iv[i] = (unsigned char)(hex_decode(iv[2*i]) << 4); iv[i] |= hex_decode(iv[2*i + 1]); } @@ -198,13 +201,14 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, return -1; } - if(libssh2_base64_decode(session, (char **) data, datalen, + if(_libssh2_base64_decode(session, (char **) data, datalen, b64data, b64datalen)) { ret = -1; goto out; } if(method) { +#if LIBSSH2_MD5_PEM /* Set up decryption */ int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0; int blocksize = method->blocksize; @@ -213,24 +217,26 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, libssh2_md5_ctx fingerprint_ctx; /* Perform key derivation (PBKDF1/MD5) */ - if(!libssh2_md5_init(&fingerprint_ctx)) { + if(!libssh2_md5_init(&fingerprint_ctx) || + !libssh2_md5_update(fingerprint_ctx, passphrase, + strlen((char *)passphrase)) || + !libssh2_md5_update(fingerprint_ctx, iv, 8) || + !libssh2_md5_final(fingerprint_ctx, secret)) { ret = -1; goto out; } - libssh2_md5_update(fingerprint_ctx, passphrase, - strlen((char *)passphrase)); - libssh2_md5_update(fingerprint_ctx, iv, 8); - libssh2_md5_final(fingerprint_ctx, secret); if(method->secret_len > MD5_DIGEST_LENGTH) { - if(!libssh2_md5_init(&fingerprint_ctx)) { + if(!libssh2_md5_init(&fingerprint_ctx) || + !libssh2_md5_update(fingerprint_ctx, + secret, MD5_DIGEST_LENGTH) || + !libssh2_md5_update(fingerprint_ctx, + passphrase, strlen((char *)passphrase)) || + !libssh2_md5_update(fingerprint_ctx, iv, 8) || + !libssh2_md5_final(fingerprint_ctx, + secret + MD5_DIGEST_LENGTH)) { ret = -1; goto out; } - libssh2_md5_update(fingerprint_ctx, secret, MD5_DIGEST_LENGTH); - libssh2_md5_update(fingerprint_ctx, passphrase, - strlen((char *)passphrase)); - libssh2_md5_update(fingerprint_ctx, iv, 8); - libssh2_md5_final(fingerprint_ctx, secret + MD5_DIGEST_LENGTH); } /* Initialize the decryption */ @@ -256,9 +262,8 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, goto out; } - while(len_decrypted <= (int)*datalen - blocksize) { - if(method->crypt(session, *data + len_decrypted, blocksize, - &abstract)) { + if(method->flags & LIBSSH2_CRYPT_FLAG_REQUIRES_FULL_PACKET) { + if(method->crypt(session, 0, *data, *datalen, &abstract, 0)) { ret = LIBSSH2_ERROR_DECRYPT; _libssh2_explicit_zero((char *)secret, sizeof(secret)); method->dtor(session, &abstract); @@ -266,8 +271,25 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, LIBSSH2_FREE(session, *data); goto out; } + } + else { + while(len_decrypted <= (int)*datalen - blocksize) { + if(method->crypt(session, 0, *data + len_decrypted, blocksize, + &abstract, + len_decrypted == 0 ? FIRST_BLOCK : + ((len_decrypted == (int)*datalen - blocksize) ? + LAST_BLOCK : MIDDLE_BLOCK) + )) { + ret = LIBSSH2_ERROR_DECRYPT; + _libssh2_explicit_zero((char *)secret, sizeof(secret)); + method->dtor(session, &abstract); + _libssh2_explicit_zero(*data, *datalen); + LIBSSH2_FREE(session, *data); + goto out; + } - len_decrypted += blocksize; + len_decrypted += blocksize; + } } /* Account for padding */ @@ -278,10 +300,14 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, /* Clean up */ _libssh2_explicit_zero((char *)secret, sizeof(secret)); method->dtor(session, &abstract); +#else + ret = -1; + goto out; +#endif } ret = 0; - out: +out: if(b64data) { _libssh2_explicit_zero(b64data, b64datalen); LIBSSH2_FREE(session, b64data); @@ -294,11 +320,11 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const char *filedata, size_t filedata_len, - unsigned char **data, unsigned int *datalen) + unsigned char **data, size_t *datalen) { char line[LINE_SIZE]; char *b64data = NULL; - unsigned int b64datalen = 0; + size_t b64datalen = 0; size_t off = 0; int ret; @@ -308,8 +334,7 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { return -1; } - } - while(strcmp(line, headerbegin) != 0); + } while(strcmp(line, headerbegin) != 0); *line = '\0'; @@ -343,14 +368,14 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, return -1; } - if(libssh2_base64_decode(session, (char **) data, datalen, + if(_libssh2_base64_decode(session, (char **) data, datalen, b64data, b64datalen)) { ret = -1; goto out; } ret = 0; - out: +out: if(b64data) { _libssh2_explicit_zero(b64data, b64datalen); LIBSSH2_FREE(session, b64data); @@ -382,7 +407,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, unsigned char *key_part = NULL; unsigned char *iv_part = NULL; unsigned char *f = NULL; - unsigned int f_len = 0; + size_t f_len = 0; int ret = 0, keylen = 0, ivlen = 0, total_len = 0; size_t kdf_len = 0, tmp_len = 0, salt_len = 0; @@ -390,10 +415,10 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, *decrypted_buf = NULL; /* decode file */ - if(libssh2_base64_decode(session, (char **)&f, &f_len, - b64data, b64datalen)) { - ret = -1; - goto out; + if(_libssh2_base64_decode(session, (char **)&f, &f_len, + b64data, b64datalen)) { + ret = -1; + goto out; } /* Parse the file */ @@ -425,7 +450,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) || tmp_len == 0) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "kdfname is missing"); + "kdfname is missing"); goto out; } @@ -440,7 +465,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, kdf_buf.len = kdf_len; } - if((passphrase == NULL || strlen((const char *)passphrase) == 0) && + if((!passphrase || strlen((const char *)passphrase) == 0) && strcmp((const char *)ciphername, "none") != 0) { /* passphrase required */ ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; @@ -456,8 +481,8 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, if(!strcmp((const char *)kdfname, "none") && strcmp((const char *)ciphername, "none") != 0) { - ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO, - "invalid format"); + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "invalid format"); goto out; } @@ -478,7 +503,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Private key data not found"); + "Private key data not found"); goto out; } @@ -490,7 +515,8 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method; all_methods = libssh2_crypt_methods(); - while((cur_method = *all_methods++)) { + /* !checksrc! disable EQUALSNULL 1 */ + while((cur_method = *all_methods++) != NULL) { if(*cur_method->name && memcmp(ciphername, cur_method->name, strlen(cur_method->name)) == 0) { @@ -500,9 +526,9 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, /* None of the available crypt methods were able to decrypt the key */ - if(method == NULL) { + if(!method) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "No supported cipher found"); + "No supported cipher found"); goto out; } } @@ -517,16 +543,15 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, total_len = keylen + ivlen; key = LIBSSH2_CALLOC(session, total_len); - if(key == NULL) { + if(!key) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Could not alloc key"); + "Could not alloc key"); goto out; } - if(strcmp((const char *)kdfname, "bcrypt") == 0 && - passphrase != NULL) { + if(strcmp((const char *)kdfname, "bcrypt") == 0 && passphrase) { if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) || - (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) { + (_libssh2_get_u32(&kdf_buf, &rounds) != 0)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "kdf contains unexpected values"); LIBSSH2_FREE(session, key); @@ -545,7 +570,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, } else { ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED, - "bcrypted without passphrase"); + "bcrypted without passphrase"); LIBSSH2_FREE(session, key); goto out; } @@ -554,14 +579,14 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, blocksize = method->blocksize; key_part = LIBSSH2_CALLOC(session, keylen); - if(key_part == NULL) { + if(!key_part) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Could not alloc key part"); goto out; } iv_part = LIBSSH2_CALLOC(session, ivlen); - if(iv_part == NULL) { + if(!iv_part) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Could not alloc iv part"); goto out; @@ -572,7 +597,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, /* Initialize the decryption */ if(method->init(session, method, iv_part, &free_iv, key_part, - &free_secret, 0, &abstract)) { + &free_secret, 0, &abstract)) { ret = LIBSSH2_ERROR_DECRYPT; goto out; } @@ -584,19 +609,59 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, goto out; } - while((size_t)len_decrypted <= decrypted.len - blocksize) { - if(method->crypt(session, decrypted.data + len_decrypted, - blocksize, - &abstract)) { + if(method->flags & LIBSSH2_CRYPT_FLAG_REQUIRES_FULL_PACKET) { + if(method->crypt(session, 0, decrypted.data, + decrypted.len, + &abstract, + MIDDLE_BLOCK)) { ret = LIBSSH2_ERROR_DECRYPT; method->dtor(session, &abstract); goto out; } - - len_decrypted += blocksize; } + else { + while((size_t)len_decrypted <= decrypted.len - blocksize) { + /* We always pass MIDDLE_BLOCK here because OpenSSH Key Files + * do not use AAD to authenticate the length. + * Furthermore, the authentication tag is appended after the + * encrypted key, and the length of the authentication tag is + * not included in the key length, so we check it after the + * loop. + */ + if(method->crypt(session, 0, decrypted.data + len_decrypted, + blocksize, + &abstract, + MIDDLE_BLOCK)) { + ret = LIBSSH2_ERROR_DECRYPT; + method->dtor(session, &abstract); + goto out; + } - /* No padding */ + len_decrypted += blocksize; + } + + /* No padding */ + + /* for the AES GCM methods, the 16 byte authentication tag is + * appended to the encrypted key */ + if(strcmp(method->name, "aes256-gcm@openssh.com") == 0 || + strcmp(method->name, "aes128-gcm@openssh.com") == 0) { + if(!_libssh2_check_length(&decoded, 16)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "GCM auth tag missing"); + method->dtor(session, &abstract); + goto out; + } + if(method->crypt(session, 0, decoded.dataptr, 16, &abstract, + LAST_BLOCK)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT, + "GCM auth tag invalid"); + method->dtor(session, &abstract); + goto out; + } + decoded.dataptr += 16; + } + } method->dtor(session, &abstract); } @@ -606,13 +671,13 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, if(_libssh2_get_u32(&decrypted, &check1) != 0 || _libssh2_get_u32(&decrypted, &check2) != 0 || check1 != check2) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Private key unpack failed (correct password?)"); - ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; - goto out; + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Private key unpack failed (correct password?)"); + ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; + goto out; } - if(decrypted_buf != NULL) { + if(decrypted_buf) { /* copy data to out-going buffer */ struct string_buf *out_buf = _libssh2_string_buf_new(session); if(!out_buf) { @@ -623,7 +688,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, } out_buf->data = LIBSSH2_CALLOC(session, decrypted.len); - if(out_buf->data == NULL) { + if(!out_buf->data) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for " "decrypted struct"); @@ -668,7 +733,7 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, { char line[LINE_SIZE]; char *b64data = NULL; - unsigned int b64datalen = 0; + size_t b64datalen = 0; int ret = 0; /* read file */ @@ -679,8 +744,7 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, if(readline(line, LINE_SIZE, fp)) { return -1; } - } - while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0); + } while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0); if(readline(line, LINE_SIZE, fp)) { return -1; @@ -719,7 +783,7 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, ret = _libssh2_openssh_pem_parse_data(session, passphrase, (const char *)b64data, - (size_t)b64datalen, + b64datalen, decrypted_buf); if(b64data) { @@ -740,11 +804,11 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, { char line[LINE_SIZE]; char *b64data = NULL; - unsigned int b64datalen = 0; + size_t b64datalen = 0; size_t off = 0; int ret; - if(filedata == NULL || filedata_len <= 0) + if(!filedata || filedata_len <= 0) return _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Error parsing PEM: filedata missing"); @@ -754,18 +818,18 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, if(off >= filedata_len) return _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Error parsing PEM: offset out of bounds"); + "Error parsing PEM: " + "OpenSSH header not found"); if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { return -1; } - } - while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0); + } while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0); *line = '\0'; do { - if (*line) { + if(*line) { char *tmp; size_t linelen; @@ -814,7 +878,7 @@ out: static int read_asn1_length(const unsigned char *data, - unsigned int datalen, unsigned int *len) + size_t datalen, size_t *len) { unsigned int lenlen; int nextpos; @@ -848,9 +912,9 @@ read_asn1_length(const unsigned char *data, } int -_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) +_libssh2_pem_decode_sequence(unsigned char **data, size_t *datalen) { - unsigned int len; + size_t len; int lenlen; if(*datalen < 1) { @@ -876,10 +940,10 @@ _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) } int -_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, +_libssh2_pem_decode_integer(unsigned char **data, size_t *datalen, unsigned char **i, unsigned int *ilen) { - unsigned int len; + size_t len; int lenlen; if(*datalen < 1) { @@ -902,7 +966,7 @@ _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, *datalen -= lenlen; *i = *data; - *ilen = len; + *ilen = (unsigned int)len; *data += len; *datalen -= len; diff --git a/uppsrc/Core/SSH/libssh2/poly1305.c b/uppsrc/Core/SSH/libssh2/poly1305.c new file mode 100644 index 000000000..2d7b23248 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/poly1305.c @@ -0,0 +1,206 @@ +/* + * Public Domain poly1305 from Andrew Moon + * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + * Copyright not intended 2024. + * + * SPDX-License-Identifier: SAX-PD-2.0 + */ + +/* $OpenBSD: poly1305.c,v 1.3 2013/12/19 22:57:13 djm Exp $ */ + +#include "libssh2_priv.h" + +#include "poly1305.h" + +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) + +#define U8TO32_LE(p) \ + (((uint32_t)((p)[0])) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LE(p, v) \ + do { \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); \ + } while (0) + +void +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, + size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { + uint32_t t0; + uint32_t t1; + uint32_t t2; + uint32_t t3; + uint32_t h0; + uint32_t h1; + uint32_t h2; + uint32_t h3; + uint32_t h4; + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t s1; + uint32_t s2; + uint32_t s3; + uint32_t s4; + uint32_t b; + uint32_t nb; + size_t j; + uint64_t t[5]; + uint64_t f0; + uint64_t f1; + uint64_t f2; + uint64_t f3; + uint32_t g0; + uint32_t g1; + uint32_t g2; + uint32_t g3; + uint32_t g4; + uint64_t c; + unsigned char mp[16]; + + /* clamp key */ + t0 = U8TO32_LE(key + 0); + t1 = U8TO32_LE(key + 4); + t2 = U8TO32_LE(key + 8); + t3 = U8TO32_LE(key + 12); + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if(inlen < 16) + goto poly1305_donna_atmost15bytes; + +poly1305_donna_16bytes: + m += 16; + inlen -= 16; + + t0 = U8TO32_LE(m-16); + t1 = U8TO32_LE(m-12); + t2 = U8TO32_LE(m-8); + t3 = U8TO32_LE(m-4); + + h0 += t0 & 0x3ffffff; + h1 += ((uint32_t)((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff); + h2 += ((uint32_t)((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff); + h3 += ((uint32_t)((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff); + h4 += (t3 >> 8) | (1 << 24); + + +poly1305_donna_mul: + t[0] = mul32x32_64(h0, r0) + mul32x32_64(h1, s4) + mul32x32_64(h2, s3) + + mul32x32_64(h3, s2) + mul32x32_64(h4, s1); + t[1] = mul32x32_64(h0, r1) + mul32x32_64(h1, r0) + mul32x32_64(h2, s4) + + mul32x32_64(h3, s3) + mul32x32_64(h4, s2); + t[2] = mul32x32_64(h0, r2) + mul32x32_64(h1, r1) + mul32x32_64(h2, r0) + + mul32x32_64(h3, s4) + mul32x32_64(h4, s3); + t[3] = mul32x32_64(h0, r3) + mul32x32_64(h1, r2) + mul32x32_64(h2, r1) + + mul32x32_64(h3, r0) + mul32x32_64(h4, s4); + t[4] = mul32x32_64(h0, r4) + mul32x32_64(h1, r3) + mul32x32_64(h2, r2) + + mul32x32_64(h3, r1) + mul32x32_64(h4, r0); + + h0 = (uint32_t)t[0] & 0x3ffffff; + c = (t[0] >> 26); + + t[1] += c; + h1 = (uint32_t)t[1] & 0x3ffffff; + b = (uint32_t)(t[1] >> 26); + + t[2] += b; + h2 = (uint32_t)t[2] & 0x3ffffff; + b = (uint32_t)(t[2] >> 26); + + t[3] += b; + h3 = (uint32_t)t[3] & 0x3ffffff; + b = (uint32_t)(t[3] >> 26); + + t[4] += b; + h4 = (uint32_t)t[4] & 0x3ffffff; + b = (uint32_t)(t[4] >> 26); + + h0 += b * 5; + + if(inlen >= 16) + goto poly1305_donna_16bytes; + + /* final bytes */ +poly1305_donna_atmost15bytes: + if(!inlen) + goto poly1305_donna_finish; + + for(j = 0; j < inlen; j++) mp[j] = m[j]; + mp[j++] = 1; + for(; j < 16; j++) + mp[j] = 0; + + inlen = 0; + + t0 = U8TO32_LE(mp + 0); + t1 = U8TO32_LE(mp + 4); + t2 = U8TO32_LE(mp + 8); + t3 = U8TO32_LE(mp + 12); + + h0 += t0 & 0x3ffffff; + h1 += ((uint32_t)((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff); + h2 += ((uint32_t)((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff); + h3 += ((uint32_t)((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff); + h4 += (t3 >> 8); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; + + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); + + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); + U32TO8_LE(&out[12], f3); +} diff --git a/uppsrc/Core/SSH/libssh2/poly1305.h b/uppsrc/Core/SSH/libssh2/poly1305.h new file mode 100644 index 000000000..21efca93f --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/poly1305.h @@ -0,0 +1,20 @@ +/* $OpenBSD: poly1305.h,v 1.4 2014/05/02 03:27:54 djm Exp $ */ + +/* + * Public Domain poly1305 from Andrew Moon + * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + * Copyright not intended 2024. + * + * SPDX-License-Identifier: SAX-PD-2.0 + */ + +#ifndef POLY1305_H +#define POLY1305_H + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 + +void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen, + const u_char key[POLY1305_KEYLEN]); + +#endif /* POLY1305_H */ diff --git a/uppsrc/Core/SSH/libssh2/publickey.c b/uppsrc/Core/SSH/libssh2/publickey.c index f26c6327d..9c9fa6188 100644 --- a/uppsrc/Core/SSH/libssh2/publickey.c +++ b/uppsrc/Core/SSH/libssh2/publickey.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2010-2014 by Daniel Stenberg +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,6 +34,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -105,7 +107,7 @@ static const LIBSSH2_PUBLICKEY_CODE_LIST publickey_status_codes[] = { */ static void publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, - LIBSSH2_SESSION *session, int status) + LIBSSH2_SESSION *session, unsigned long status) { const char *msg; @@ -114,7 +116,7 @@ publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, status = 7; } - if(status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) { + if(status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) { msg = "unknown"; } else { @@ -136,14 +138,14 @@ publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey, LIBSSH2_CHANNEL *channel = pkey->channel; LIBSSH2_SESSION *session = channel->session; unsigned char buffer[4]; - int rc; + ssize_t rc; *data = NULL; /* default to nothing returned */ *data_len = 0; if(pkey->receive_state == libssh2_NB_state_idle) { rc = _libssh2_channel_read(channel, 0, (char *) buffer, 4); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc != 4) { return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, @@ -166,9 +168,9 @@ publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey, rc = _libssh2_channel_read(channel, 0, (char *) pkey->receive_packet, pkey->receive_packet_len); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } - else if(rc != (int)pkey->receive_packet_len) { + else if(rc != (ssize_t)pkey->receive_packet_len) { LIBSSH2_FREE(session, pkey->receive_packet); pkey->receive_packet = NULL; pkey->receive_state = libssh2_NB_state_idle; @@ -234,7 +236,7 @@ publickey_response_success(LIBSSH2_PUBLICKEY * pkey) size_t data_len; int response; - while(1) { + for(;;) { int rc = publickey_packet_receive(pkey, &data, &data_len); if(rc == LIBSSH2_ERROR_EAGAIN) { return rc; @@ -272,7 +274,7 @@ publickey_response_success(LIBSSH2_PUBLICKEY * pkey) return 0; publickey_status_error(pkey, session, status); - return -1; + goto err_exit; } default: LIBSSH2_FREE(session, data); @@ -287,7 +289,7 @@ publickey_response_success(LIBSSH2_PUBLICKEY * pkey) data = NULL; } } - /* never reached, but include `return` to silence compiler warnings */ +err_exit: return -1; } @@ -310,8 +312,8 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) session->pkeyInit_pkey = NULL; session->pkeyInit_channel = NULL; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Initializing publickey subsystem"); + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, + "Initializing publickey subsystem")); session->pkeyInit_state = libssh2_NB_state_allocated; } @@ -387,28 +389,29 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) session->pkeyInit_buffer_sent = 0; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Sending publickey advertising version %d support", - (int) LIBSSH2_PUBLICKEY_VERSION); + (int) LIBSSH2_PUBLICKEY_VERSION)); session->pkeyInit_state = libssh2_NB_state_sent2; } if(session->pkeyInit_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->pkeyInit_channel, 0, - session->pkeyInit_buffer, - 19 - session->pkeyInit_buffer_sent); - if(rc == LIBSSH2_ERROR_EAGAIN) { + ssize_t nwritten; + nwritten = _libssh2_channel_write(session->pkeyInit_channel, 0, + session->pkeyInit_buffer, + 19 - session->pkeyInit_buffer_sent); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending publickey version packet"); return NULL; } - else if(rc < 0) { - _libssh2_error(session, rc, + else if(nwritten < 0) { + _libssh2_error(session, (int)nwritten, "Unable to send publickey version packet"); goto err_exit; } - session->pkeyInit_buffer_sent += rc; + session->pkeyInit_buffer_sent += nwritten; if(session->pkeyInit_buffer_sent < 19) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Need to be called again to complete this"); @@ -419,7 +422,7 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) } if(session->pkeyInit_state == libssh2_NB_state_sent3) { - while(1) { + for(;;) { unsigned char *s; rc = publickey_packet_receive(session->pkeyInit_pkey, &session->pkeyInit_data, @@ -511,16 +514,16 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) session->pkeyInit_pkey->version = _libssh2_ntohu32(s); if(session->pkeyInit_pkey->version > LIBSSH2_PUBLICKEY_VERSION) { - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Truncate remote publickey version " - "from %lu", - session->pkeyInit_pkey->version); + "from %u", + session->pkeyInit_pkey->version)); session->pkeyInit_pkey->version = LIBSSH2_PUBLICKEY_VERSION; } - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Enabling publickey subsystem version %lu", - session->pkeyInit_pkey->version); + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, + "Enabling publickey subsystem version %u", + session->pkeyInit_pkey->version)); LIBSSH2_FREE(session, session->pkeyInit_data); session->pkeyInit_data = NULL; session->pkeyInit_state = libssh2_NB_state_idle; @@ -538,7 +541,7 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) } /* Never reached except by direct goto */ - err_exit: +err_exit: session->pkeyInit_state = libssh2_NB_state_sent4; if(session->pkeyInit_channel) { rc = _libssh2_channel_close(session->pkeyInit_channel); @@ -607,8 +610,8 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, if(pkey->add_state == libssh2_NB_state_idle) { pkey->add_packet = NULL; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, "Adding %s publickey", - name); + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, + "Adding %s publickey", name)); if(pkey->version == 1) { for(i = 0; i < num_attrs; i++) { @@ -639,25 +642,25 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, } pkey->add_s = pkey->add_packet; - _libssh2_htonu32(pkey->add_s, packet_len - 4); + _libssh2_htonu32(pkey->add_s, (uint32_t)(packet_len - 4)); pkey->add_s += 4; _libssh2_htonu32(pkey->add_s, sizeof("add") - 1); pkey->add_s += 4; memcpy(pkey->add_s, "add", sizeof("add") - 1); pkey->add_s += sizeof("add") - 1; if(pkey->version == 1) { - _libssh2_htonu32(pkey->add_s, comment_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)comment_len); pkey->add_s += 4; if(comment) { memcpy(pkey->add_s, comment, comment_len); pkey->add_s += comment_len; } - _libssh2_htonu32(pkey->add_s, name_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)name_len); pkey->add_s += 4; memcpy(pkey->add_s, name, name_len); pkey->add_s += name_len; - _libssh2_htonu32(pkey->add_s, blob_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)blob_len); pkey->add_s += 4; memcpy(pkey->add_s, blob, blob_len); pkey->add_s += blob_len; @@ -665,23 +668,23 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, else { /* Version == 2 */ - _libssh2_htonu32(pkey->add_s, name_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)name_len); pkey->add_s += 4; memcpy(pkey->add_s, name, name_len); pkey->add_s += name_len; - _libssh2_htonu32(pkey->add_s, blob_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)blob_len); pkey->add_s += 4; memcpy(pkey->add_s, blob, blob_len); pkey->add_s += blob_len; *(pkey->add_s++) = overwrite ? 0x01 : 0; - _libssh2_htonu32(pkey->add_s, num_attrs); + _libssh2_htonu32(pkey->add_s, (uint32_t)num_attrs); pkey->add_s += 4; for(i = 0; i < num_attrs; i++) { - _libssh2_htonu32(pkey->add_s, attrs[i].name_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)attrs[i].name_len); pkey->add_s += 4; memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len); pkey->add_s += attrs[i].name_len; - _libssh2_htonu32(pkey->add_s, attrs[i].value_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)attrs[i].value_len); pkey->add_s += 4; memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len); pkey->add_s += attrs[i].value_len; @@ -689,21 +692,22 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, } } - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Sending publickey \"add\" packet: " "type=%s blob_len=%ld num_attrs=%ld", - name, blob_len, num_attrs); + name, blob_len, num_attrs)); pkey->add_state = libssh2_NB_state_created; } if(pkey->add_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, pkey->add_packet, - (pkey->add_s - pkey->add_packet)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, pkey->add_packet, + (pkey->add_s - pkey->add_packet)); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((pkey->add_s - pkey->add_packet) != rc) { + else if((pkey->add_s - pkey->add_packet) != nwritten) { LIBSSH2_FREE(session, pkey->add_packet); pkey->add_packet = NULL; return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, @@ -758,36 +762,37 @@ libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey, } pkey->remove_s = pkey->remove_packet; - _libssh2_htonu32(pkey->remove_s, packet_len - 4); + _libssh2_htonu32(pkey->remove_s, (uint32_t)(packet_len - 4)); pkey->remove_s += 4; _libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1); pkey->remove_s += 4; memcpy(pkey->remove_s, "remove", sizeof("remove") - 1); pkey->remove_s += sizeof("remove") - 1; - _libssh2_htonu32(pkey->remove_s, name_len); + _libssh2_htonu32(pkey->remove_s, (uint32_t)name_len); pkey->remove_s += 4; memcpy(pkey->remove_s, name, name_len); pkey->remove_s += name_len; - _libssh2_htonu32(pkey->remove_s, blob_len); + _libssh2_htonu32(pkey->remove_s, (uint32_t)blob_len); pkey->remove_s += 4; memcpy(pkey->remove_s, blob, blob_len); pkey->remove_s += blob_len; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Sending publickey \"remove\" packet: " "type=%s blob_len=%ld", - name, blob_len); + name, blob_len)); pkey->remove_state = libssh2_NB_state_created; } if(pkey->remove_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, pkey->remove_packet, - (pkey->remove_s - pkey->remove_packet)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, pkey->remove_packet, + (pkey->remove_s - pkey->remove_packet)); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((pkey->remove_s - pkey->remove_packet) != rc) { + else if((pkey->remove_s - pkey->remove_packet) != nwritten) { LIBSSH2_FREE(session, pkey->remove_packet); pkey->remove_packet = NULL; pkey->remove_state = libssh2_NB_state_idle; @@ -835,28 +840,29 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, pkey->listFetch_data = NULL; pkey->listFetch_s = pkey->listFetch_buffer; - _libssh2_htonu32(pkey->listFetch_s, buffer_len - 4); + _libssh2_htonu32(pkey->listFetch_s, (uint32_t)(buffer_len - 4)); pkey->listFetch_s += 4; _libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1); pkey->listFetch_s += 4; memcpy(pkey->listFetch_s, "list", sizeof("list") - 1); pkey->listFetch_s += sizeof("list") - 1; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey \"list\" packet"); + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, + "Sending publickey \"list\" packet")); pkey->listFetch_state = libssh2_NB_state_created; } if(pkey->listFetch_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, - pkey->listFetch_buffer, - (pkey->listFetch_s - - pkey->listFetch_buffer)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, + pkey->listFetch_buffer, + (pkey->listFetch_s - + pkey->listFetch_buffer)); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((pkey->listFetch_s - pkey->listFetch_buffer) != rc) { + else if((pkey->listFetch_s - pkey->listFetch_buffer) != nwritten) { pkey->listFetch_state = libssh2_NB_state_idle; return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet"); @@ -865,7 +871,7 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, pkey->listFetch_state = libssh2_NB_state_sent; } - while(1) { + for(;;) { rc = publickey_packet_receive(pkey, &pkey->listFetch_data, &pkey->listFetch_data_len); if(rc == LIBSSH2_ERROR_EAGAIN) { @@ -1197,7 +1203,7 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, } /* Only reached via explicit goto */ - err_exit: +err_exit: if(pkey->listFetch_data) { LIBSSH2_FREE(session, pkey->listFetch_data); pkey->listFetch_data = NULL; diff --git a/uppsrc/Core/SSH/libssh2/scp.c b/uppsrc/Core/SSH/libssh2/scp.c index 8cb3d65c3..8a8e7d9ea 100644 --- a/uppsrc/Core/SSH/libssh2/scp.c +++ b/uppsrc/Core/SSH/libssh2/scp.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2009-2019 by Daniel Stenberg - * Copyright (c) 2004-2008, Sara Golemon +/* Copyright (C) Daniel Stenberg + * Copyright (C) Sara Golemon * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,15 +34,24 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include -#include #include "channel.h" #include "session.h" +#include /* strtoll(), _strtoi64(), strtol() */ + +#if defined(HAVE_STRTOLL) +#define scpsize_strtol strtoll +#elif defined(HAVE_STRTOI64) +#define scpsize_strtol _strtoi64 +#else +#define scpsize_strtol strtol +#endif /* Max. length of a quoted string after libssh2_shell_quotearg() processing */ #define _libssh2_shell_quotedsize(s) (3 * strlen(s) + 2) @@ -112,7 +121,7 @@ References: o csh-compatible quotation (special handling for '!' etc.), see - http://www.grymoire.com/Unix/Csh.html#toc-uh-10 + https://www.grymoire.com/Unix/Csh.html#toc-uh-10 Return value: Length of the resulting string (not counting the terminating '\0'), @@ -122,9 +131,9 @@ until then it is kept static and in this source file. */ -static unsigned +static size_t shell_quotearg(const char *path, unsigned char *buf, - unsigned bufsize) + size_t bufsize) { const char *src; unsigned char *dst, *endp; @@ -270,7 +279,7 @@ shell_quotearg(const char *path, unsigned char *buf, static LIBSSH2_CHANNEL * scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) { - int cmd_len; + size_t cmd_len; int rc; int tmp_err_code; const char *tmp_err_msg; @@ -282,7 +291,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) session->scpRecv_atime = 0; session->scpRecv_command_len = - _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0); + _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb ? 1 : 0); session->scpRecv_command = LIBSSH2_ALLOC(session, session->scpRecv_command_len); @@ -296,18 +305,30 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) snprintf((char *)session->scpRecv_command, session->scpRecv_command_len, - "scp -%sf ", sb?"p":""); + "scp -%sf ", sb ? "p" : ""); cmd_len = strlen((char *)session->scpRecv_command); - cmd_len += shell_quotearg(path, - &session->scpRecv_command[cmd_len], - session->scpRecv_command_len - cmd_len); + + if(!session->flag.quote_paths) { + size_t path_len; + + path_len = strlen(path); + + /* no NUL-termination needed, so memcpy will do */ + memcpy(&session->scpRecv_command[cmd_len], path, path_len); + cmd_len += path_len; + } + else { + cmd_len += shell_quotearg(path, + &session->scpRecv_command[cmd_len], + session->scpRecv_command_len - cmd_len); + } /* the command to exec should _not_ be NUL-terminated */ session->scpRecv_command_len = cmd_len; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP receive"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, + "Opening channel for SCP receive")); session->scpRecv_state = libssh2_NB_state_created; } @@ -356,7 +377,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) LIBSSH2_FREE(session, session->scpRecv_command); session->scpRecv_command = NULL; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sending initial wakeup")); /* SCP ACK */ session->scpRecv_response[0] = '\0'; @@ -364,8 +385,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent1) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending initial wakeup"); @@ -384,14 +405,15 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) if((session->scpRecv_state == libssh2_NB_state_sent2) || (session->scpRecv_state == libssh2_NB_state_sent3)) { while(sb && (session->scpRecv_response_len < - LIBSSH2_SCP_RESPONSE_BUFLEN)) { + LIBSSH2_SCP_RESPONSE_BUFLEN)) { unsigned char *s, *p; if(session->scpRecv_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); + rc = (int)_libssh2_channel_read(session->scpRecv_channel, 0, + (char *) session-> + scpRecv_response + + session->scpRecv_response_len, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response"); @@ -435,9 +457,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) /* zero terminate the error */ err_msg[err_len] = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "got %02x %s", session->scpRecv_response[0], - err_msg); + err_msg)); _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Failed to recv file"); @@ -550,8 +572,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent3) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting to send SCP ACK"); @@ -561,9 +583,10 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) goto scp_recv_error; } - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "mtime = %ld, atime = %ld", - session->scpRecv_mtime, session->scpRecv_atime); + session->scpRecv_mtime, + session->scpRecv_atime)); /* We *should* check that atime.usec is valid, but why let that stop use? */ @@ -586,17 +609,18 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) char *s, *p, *e = NULL; if(session->scpRecv_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); + rc = (int)_libssh2_channel_read(session->scpRecv_channel, 0, + (char *) session-> + scpRecv_response + + session->scpRecv_response_len, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response"); return NULL; } else if(rc < 0) { - /* error, bail out*/ + /* error, bail out */ _libssh2_error(session, rc, "Failed reading SCP response"); goto scp_recv_error; } @@ -678,7 +702,6 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) *(p++) = '\0'; /* Make sure we don't get fooled by leftover values */ - session->scpRecv_mode = strtol(s, &e, 8); if(e && *e) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, @@ -713,8 +736,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent6) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending SCP ACK"); @@ -723,9 +746,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) else if(rc != 1) { goto scp_recv_error; } - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "mode = 0%lo size = %ld", session->scpRecv_mode, - session->scpRecv_size); + (long)session->scpRecv_size)); /* We *should* check that basename is valid, but why let that stop us? */ @@ -741,14 +764,14 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) sb->st_mtime = session->scpRecv_mtime; sb->st_atime = session->scpRecv_atime; - sb->st_size = session->scpRecv_size; + sb->st_size = (libssh2_struct_stat_size)session->scpRecv_size; sb->st_mode = (unsigned short)session->scpRecv_mode; } session->scpRecv_state = libssh2_NB_state_idle; return session->scpRecv_channel; - scp_recv_empty_channel: +scp_recv_empty_channel: /* the code only jumps here as a result of a zero read from channel_read() so we check EOF status to avoid getting stuck in a loop */ if(libssh2_channel_eof(session->scpRecv_channel)) @@ -757,11 +780,11 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) else return session->scpRecv_channel; /* fall-through */ - scp_recv_error: +scp_recv_error: tmp_err_code = session->err_code; tmp_err_msg = session->err_msg; while(libssh2_channel_free(session->scpRecv_channel) == - LIBSSH2_ERROR_EAGAIN); + LIBSSH2_ERROR_EAGAIN); session->err_code = tmp_err_code; session->err_msg = tmp_err_msg; session->scpRecv_channel = NULL; @@ -769,6 +792,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) return NULL; } +#ifndef LIBSSH2_NO_DEPRECATED /* * libssh2_scp_recv * @@ -780,7 +804,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) * */ LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb) +libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb) { LIBSSH2_CHANNEL *ptr; @@ -805,6 +829,7 @@ libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb) return ptr; } +#endif /* * libssh2_scp_recv2 @@ -823,7 +848,7 @@ libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, } /* - * scp_send() + * scp_send * * Send a file using SCP * @@ -832,7 +857,7 @@ static LIBSSH2_CHANNEL * scp_send(LIBSSH2_SESSION * session, const char *path, int mode, libssh2_int64_t size, time_t mtime, time_t atime) { - int cmd_len; + size_t cmd_len; int rc; int tmp_err_code; const char *tmp_err_msg; @@ -840,7 +865,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_idle) { session->scpSend_command_len = _libssh2_shell_quotedsize(path) + sizeof("scp -t ") + - ((mtime || atime)?1:0); + ((mtime || atime) ? 1 : 0); session->scpSend_command = LIBSSH2_ALLOC(session, session->scpSend_command_len); @@ -854,18 +879,31 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, snprintf((char *)session->scpSend_command, session->scpSend_command_len, - "scp -%st ", (mtime || atime)?"p":""); + "scp -%st ", (mtime || atime) ? "p" : ""); cmd_len = strlen((char *)session->scpSend_command); - cmd_len += shell_quotearg(path, - &session->scpSend_command[cmd_len], - session->scpSend_command_len - cmd_len); + + if(!session->flag.quote_paths) { + size_t path_len; + + path_len = strlen(path); + + /* no NUL-termination needed, so memcpy will do */ + memcpy(&session->scpSend_command[cmd_len], path, path_len); + cmd_len += path_len; + + } + else { + cmd_len += shell_quotearg(path, + &session->scpSend_command[cmd_len], + session->scpSend_command_len - cmd_len); + } /* the command to exec should _not_ be NUL-terminated */ session->scpSend_command_len = cmd_len; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP send"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, + "Opening channel for SCP send")); /* Allocate a channel */ session->scpSend_state = libssh2_NB_state_created; @@ -922,8 +960,8 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent1) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response from remote"); @@ -936,7 +974,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(!rc) /* remain in the same state */ goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote"); goto scp_send_error; @@ -947,8 +985,8 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, snprintf((char *) session->scpSend_response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", (long)mtime, (long)atime); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sent %s", + session->scpSend_response)); } session->scpSend_state = libssh2_NB_state_sent2; @@ -957,9 +995,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, /* Send mtime and atime to be used for file */ if(mtime || atime) { if(session->scpSend_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); + rc = (int)_libssh2_channel_write(session->scpSend_channel, 0, + session->scpSend_response, + session->scpSend_response_len); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending time data for SCP file"); @@ -976,8 +1014,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent3) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response"); @@ -990,7 +1029,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(!rc) /* remain in the same state */ goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid SCP ACK response"); goto scp_send_error; @@ -1018,16 +1057,16 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %" LIBSSH2_INT64_T_FORMAT " %s\n", mode, size, base); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sent %s", + session->scpSend_response)); session->scpSend_state = libssh2_NB_state_sent5; } if(session->scpSend_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); + rc = (int)_libssh2_channel_write(session->scpSend_channel, 0, + session->scpSend_response, + session->scpSend_response_len); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block send core file data for SCP file"); @@ -1044,8 +1083,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent6) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response"); @@ -1059,7 +1099,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(rc == 0) goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { size_t err_len; char *err_msg; @@ -1073,13 +1113,13 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, } /* Read the remote error message */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - err_msg, err_len); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + err_msg, err_len); if(rc > 0) { err_msg[err_len] = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "got %02x %s", session->scpSend_response[0], - err_msg); + err_msg)); } LIBSSH2_FREE(session, err_msg); _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, @@ -1091,7 +1131,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, session->scpSend_state = libssh2_NB_state_idle; return session->scpSend_channel; - scp_send_empty_channel: +scp_send_empty_channel: /* the code only jumps here as a result of a zero read from channel_read() so we check EOF status to avoid getting stuck in a loop */ if(libssh2_channel_eof(session->scpSend_channel)) { @@ -1101,7 +1141,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else return session->scpSend_channel; /* fall-through */ - scp_send_error: +scp_send_error: tmp_err_code = session->err_code; tmp_err_msg = session->err_msg; while(libssh2_channel_free(session->scpSend_channel) == diff --git a/uppsrc/Core/SSH/libssh2/session.c b/uppsrc/Core/SSH/libssh2/session.c index 212560b88..2d77b05e9 100644 --- a/uppsrc/Core/SSH/libssh2/session.c +++ b/uppsrc/Core/SSH/libssh2/session.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2007 Sara Golemon - * Copyright (c) 2009-2015 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,35 +35,45 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include + +#ifdef _WIN32 +#include /* for socklen_t */ +#endif #ifdef HAVE_UNISTD_H #include #endif -#include -#include - -#ifdef HAVE_GETTIMEOFDAY -#include -#endif #ifdef HAVE_ALLOCA_H #include #endif +#include +#include +#include + #include "transport.h" #include "session.h" #include "channel.h" #include "mac.h" -#include "misc.h" + +#if defined(_WIN32) +#define libssh2_usec_t long +#elif defined(__APPLE__) +#define libssh2_usec_t suseconds_t +#else +#undef libssh2_usec_t +#endif /* libssh2_default_alloc */ static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc) { - (void) abstract; + (void)abstract; return malloc(count); } @@ -72,7 +82,7 @@ LIBSSH2_ALLOC_FUNC(libssh2_default_alloc) static LIBSSH2_FREE_FUNC(libssh2_default_free) { - (void) abstract; + (void)abstract; free(ptr); } @@ -81,7 +91,7 @@ LIBSSH2_FREE_FUNC(libssh2_default_free) static LIBSSH2_REALLOC_FUNC(libssh2_default_realloc) { - (void) abstract; + (void)abstract; return realloc(ptr, count); } @@ -96,8 +106,8 @@ LIBSSH2_REALLOC_FUNC(libssh2_default_realloc) static int banner_receive(LIBSSH2_SESSION * session) { - int ret; - int banner_len; + ssize_t ret; + size_t banner_len; if(session->banner_TxRx_state == libssh2_NB_state_idle) { banner_len = 0; @@ -108,25 +118,25 @@ banner_receive(LIBSSH2_SESSION * session) banner_len = session->banner_TxRx_total_send; } - while((banner_len < (int) sizeof(session->banner_TxRx_banner)) && - ((banner_len == 0) - || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) { + while((banner_len < sizeof(session->banner_TxRx_banner)) && + ((banner_len == 0) + || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) { char c = '\0'; /* no incoming block yet! */ session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; ret = LIBSSH2_RECV(session, &c, 1, - LIBSSH2_SOCKET_RECV_FLAGS(session)); + LIBSSH2_SOCKET_RECV_FLAGS(session)); if(ret < 0) { if(session->api_block_mode || (ret != -EAGAIN)) /* ignore EAGAIN when non-blocking */ - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error recving %d bytes: %d", 1, -ret); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Error recving %d bytes: %ld", 1, (long)-ret)); } else - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Recved %d bytes banner", ret); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Recved %ld bytes banner", (long)ret)); if(ret < 0) { if(ret == -EAGAIN) { @@ -147,6 +157,10 @@ banner_receive(LIBSSH2_SESSION * session) return LIBSSH2_ERROR_SOCKET_DISCONNECT; } + if((c == '\r' || c == '\n') && banner_len == 0) { + continue; + } + if(c == '\0') { /* NULLs are not allowed in SSH banners */ session->banner_TxRx_state = libssh2_NB_state_idle; @@ -158,8 +172,8 @@ banner_receive(LIBSSH2_SESSION * session) } while(banner_len && - ((session->banner_TxRx_banner[banner_len - 1] == '\n') || - (session->banner_TxRx_banner[banner_len - 1] == '\r'))) { + ((session->banner_TxRx_banner[banner_len - 1] == '\n') || + (session->banner_TxRx_banner[banner_len - 1] == '\r'))) { banner_len--; } @@ -180,8 +194,8 @@ banner_receive(LIBSSH2_SESSION * session) } memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len); session->remote.banner[banner_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Received Banner: %s", - session->remote.banner); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Received Banner: %s", + session->remote.banner)); return LIBSSH2_ERROR_NONE; } @@ -199,11 +213,8 @@ static int banner_send(LIBSSH2_SESSION * session) { char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF; - int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1; + size_t banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1; ssize_t ret; -#ifdef LIBSSH2DEBUG - char banner_dup[256]; -#endif if(session->banner_TxRx_state == libssh2_NB_state_idle) { if(session->local.banner) { @@ -212,18 +223,22 @@ banner_send(LIBSSH2_SESSION * session) banner = (char *) session->local.banner; } #ifdef LIBSSH2DEBUG - /* Hack and slash to avoid sending CRLF in debug output */ - if(banner_len < 256) { - memcpy(banner_dup, banner, banner_len - 2); - banner_dup[banner_len - 2] = '\0'; - } - else { - memcpy(banner_dup, banner, 255); - banner_dup[255] = '\0'; - } + { + char banner_dup[256]; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Sending Banner: %s", - banner_dup); + /* Hack and slash to avoid sending CRLF in debug output */ + if(banner_len < 256) { + memcpy(banner_dup, banner, banner_len - 2); + banner_dup[banner_len - 2] = '\0'; + } + else { + memcpy(banner_dup, banner, 255); + banner_dup[255] = '\0'; + } + + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Sending Banner: %s", banner_dup)); + } #endif session->banner_TxRx_state = libssh2_NB_state_created; @@ -233,20 +248,21 @@ banner_send(LIBSSH2_SESSION * session) session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; ret = LIBSSH2_SEND(session, - banner + session->banner_TxRx_total_send, - banner_len - session->banner_TxRx_total_send, - LIBSSH2_SOCKET_SEND_FLAGS(session)); - if(ret < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", - banner_len - session->banner_TxRx_total_send, -ret); - else - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Sent %d/%d bytes at %p+%d", ret, + banner + session->banner_TxRx_total_send, banner_len - session->banner_TxRx_total_send, - banner, session->banner_TxRx_total_send); + LIBSSH2_SOCKET_SEND_FLAGS(session)); + if(ret < 0) + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Error sending %ld bytes: %ld", + (long)(banner_len - session->banner_TxRx_total_send), + (long)-ret)); + else + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Sent %ld/%ld bytes at %p+%ld", (long)ret, + (long)(banner_len - session->banner_TxRx_total_send), + (void *)banner, (long)session->banner_TxRx_total_send)); - if(ret != (banner_len - session->banner_TxRx_total_send)) { + if(ret != (ssize_t)(banner_len - session->banner_TxRx_total_send)) { if(ret >= 0 || ret == -EAGAIN) { /* the whole packet could not be sent, save the what was */ session->socket_block_directions = @@ -276,8 +292,6 @@ static int session_nonblock(libssh2_socket_t sockfd, /* operate on this */ int nonblock /* TRUE or FALSE */ ) { -#undef SETBLOCK -#define SETBLOCK 0 #ifdef HAVE_O_NONBLOCK /* most recent unix versions */ int flags; @@ -287,66 +301,39 @@ session_nonblock(libssh2_socket_t sockfd, /* operate on this */ return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); else return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); -#undef SETBLOCK -#define SETBLOCK 1 -#endif - -#if defined(HAVE_FIONBIO) && (SETBLOCK == 0) - /* older unix versions and VMS*/ +#elif defined(HAVE_FIONBIO) + /* older unix versions and VMS */ int flags; flags = nonblock; return ioctl(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 2 -#endif - -#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0) - /* Windows? */ - unsigned long flags; - flags = nonblock; - - return ioctlsocket(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 3 -#endif - -#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0) +#elif defined(HAVE_IOCTLSOCKET_CASE) /* presumably for Amiga */ return IoctlSocket(sockfd, FIONBIO, (long) nonblock); -#undef SETBLOCK -#define SETBLOCK 4 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0) +#elif defined(HAVE_SO_NONBLOCK) /* BeOS */ long b = nonblock ? 1 : 0; return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); -#undef SETBLOCK -#define SETBLOCK 5 -#endif +#elif defined(_WIN32) + unsigned long flags; -#ifdef HAVE_DISABLED_NONBLOCKING + flags = nonblock; + return ioctlsocket(sockfd, FIONBIO, &flags); +#else + (void)sockfd; + (void)nonblock; return 0; /* returns success */ -#undef SETBLOCK -#define SETBLOCK 6 -#endif - -#if(SETBLOCK == 0) -#error "no non-blocking method was found/used/set" #endif } /* - * get_socket_nonblocking() + * get_socket_nonblocking * * gets the given blocking or non-blocking state of the socket. */ static int -get_socket_nonblocking(int sockfd) +get_socket_nonblocking(libssh2_socket_t sockfd) { /* operate on this */ -#undef GETBLOCK -#define GETBLOCK 0 #ifdef HAVE_O_NONBLOCK /* most recent unix versions */ int flags = fcntl(sockfd, F_GETFL, 0); @@ -356,26 +343,7 @@ get_socket_nonblocking(int sockfd) return 1; } return (flags & O_NONBLOCK); -#undef GETBLOCK -#define GETBLOCK 1 -#endif - -#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0) - /* Windows? */ - unsigned int option_value; - socklen_t option_len = sizeof(option_value); - - if(getsockopt - (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) { - /* Assume blocking on error */ - return 1; - } - return (int) option_value; -#undef GETBLOCK -#define GETBLOCK 2 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0) +#elif defined(HAVE_SO_NONBLOCK) /* BeOS */ long b; if(getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) { @@ -383,12 +351,7 @@ get_socket_nonblocking(int sockfd) return 1; } return (int) b; -#undef GETBLOCK -#define GETBLOCK 5 -#endif - -#if defined(SO_STATE) && defined(__VMS) && (GETBLOCK == 0) - +#elif defined(SO_STATE) && defined(__VMS) /* VMS TCP/IP Services */ size_t sockstat = 0; @@ -396,23 +359,27 @@ get_socket_nonblocking(int sockfd) size_t size = sizeof(int); callstat = getsockopt(sockfd, SOL_SOCKET, SO_STATE, - (char *)&sockstat, &size); - if(callstat == -1) return 0; - if((sockstat&SS_NBIO) != 0) return 1; + (char *)&sockstat, &size); + if(callstat == -1) { + return 0; + } + if((sockstat&SS_NBIO) != 0) { + return 1; + } return 0; +#elif defined(_WIN32) + unsigned int option_value; + socklen_t option_len = sizeof(option_value); -#undef GETBLOCK -#define GETBLOCK 6 -#endif - -#ifdef HAVE_DISABLED_NONBLOCKING + if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, + (void *) &option_value, &option_len)) { + /* Assume blocking on error */ + return 1; + } + return (int) option_value; +#else + (void)sockfd; return 1; /* returns blocking */ -#undef GETBLOCK -#define GETBLOCK 7 -#endif - -#if(GETBLOCK == 0) -#error "no non-blocking method was found/used/get" #endif } @@ -442,8 +409,8 @@ libssh2_session_banner_set(LIBSSH2_SESSION * session, const char *banner) /* first zero terminate like this so that the debug output is nice */ session->local.banner[banner_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting local Banner: %s", - session->local.banner); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Setting local Banner: %s", + session->local.banner)); session->local.banner[banner_len++] = '\r'; session->local.banner[banner_len++] = '\n'; session->local.banner[banner_len] = '\0'; @@ -451,6 +418,7 @@ libssh2_session_banner_set(LIBSSH2_SESSION * session, const char *banner) return 0; } +#ifndef LIBSSH2_NO_DEPRECATED /* libssh2_banner_set * Set the local banner. DEPRECATED VERSION */ @@ -459,6 +427,7 @@ libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner) { return libssh2_session_banner_set(session, banner); } +#endif /* * libssh2_session_init_ex @@ -500,15 +469,92 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), session->abstract = abstract; session->api_timeout = 0; /* timeout-free API by default */ session->api_block_mode = 1; /* blocking API by default */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "New session resource allocated"); + session->state = LIBSSH2_STATE_INITIAL_KEX; + session->fullpacket_required_type = 0; + session->packet_read_timeout = LIBSSH2_DEFAULT_READ_TIMEOUT; + session->flag.quote_paths = 1; /* default behavior is to quote paths + for the scp subsystem */ + session->kex = NULL; + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "New session resource allocated")); _libssh2_init_if_needed(); } return session; } /* - * libssh2_session_callback_set + * libssh2_session_callback_set2 + * + * Set (or reset) a callback function + * Returns the prior address + */ +LIBSSH2_API libssh2_cb_generic * +libssh2_session_callback_set2(LIBSSH2_SESSION *session, int cbtype, + libssh2_cb_generic *callback) +{ + libssh2_cb_generic *oldcb; + + switch(cbtype) { + case LIBSSH2_CALLBACK_IGNORE: + oldcb = (libssh2_cb_generic *)session->ssh_msg_ignore; + session->ssh_msg_ignore = (LIBSSH2_IGNORE_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_DEBUG: + oldcb = (libssh2_cb_generic *)session->ssh_msg_debug; + session->ssh_msg_debug = (LIBSSH2_DEBUG_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_DISCONNECT: + oldcb = (libssh2_cb_generic *)session->ssh_msg_disconnect; + session->ssh_msg_disconnect = (LIBSSH2_DISCONNECT_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_MACERROR: + oldcb = (libssh2_cb_generic *)session->macerror; + session->macerror = (LIBSSH2_MACERROR_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_X11: + oldcb = (libssh2_cb_generic *)session->x11; + session->x11 = (LIBSSH2_X11_OPEN_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_SEND: + oldcb = (libssh2_cb_generic *)session->send; + session->send = (LIBSSH2_SEND_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_RECV: + oldcb = (libssh2_cb_generic *)session->recv; + session->recv = (LIBSSH2_RECV_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_AUTHAGENT: + oldcb = (libssh2_cb_generic *)session->authagent; + session->authagent = (LIBSSH2_AUTHAGENT_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_AUTHAGENT_IDENTITIES: + oldcb = (libssh2_cb_generic *)session->addLocalIdentities; + session->addLocalIdentities = + (LIBSSH2_ADD_IDENTITIES_FUNC((*)))callback; + return oldcb; + + case LIBSSH2_CALLBACK_AUTHAGENT_SIGN: + oldcb = (libssh2_cb_generic *)session->agentSignCallback; + session->agentSignCallback = + (LIBSSH2_AUTHAGENT_SIGN_FUNC((*)))callback; + return oldcb; + } + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", + cbtype)); + + return NULL; +} + +/* + * libssh2_session_callback_set (DEPRECATED, DO NOT USE!) * * Set (or reset) a callback function * Returns the prior address @@ -516,59 +562,31 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), * ALERT: this function relies on that we can typecast function pointers * to void pointers, which isn't allowed in ISO C! */ +#ifdef _MSC_VER +#pragma warning(push) +/* 'type cast': from data pointer to function pointer */ +#pragma warning(disable:4054) +/* 'type cast': from function pointer to data pointer */ +#pragma warning(disable:4055) +#else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" +#endif LIBSSH2_API void * libssh2_session_callback_set(LIBSSH2_SESSION * session, int cbtype, void *callback) { - void *oldcb; - - switch(cbtype) { - case LIBSSH2_CALLBACK_IGNORE: - oldcb = session->ssh_msg_ignore; - session->ssh_msg_ignore = callback; - return oldcb; - - case LIBSSH2_CALLBACK_DEBUG: - oldcb = session->ssh_msg_debug; - session->ssh_msg_debug = callback; - return oldcb; - - case LIBSSH2_CALLBACK_DISCONNECT: - oldcb = session->ssh_msg_disconnect; - session->ssh_msg_disconnect = callback; - return oldcb; - - case LIBSSH2_CALLBACK_MACERROR: - oldcb = session->macerror; - session->macerror = callback; - return oldcb; - - case LIBSSH2_CALLBACK_X11: - oldcb = session->x11; - session->x11 = callback; - return oldcb; - - case LIBSSH2_CALLBACK_SEND: - oldcb = session->send; - session->send = callback; - return oldcb; - - case LIBSSH2_CALLBACK_RECV: - oldcb = session->recv; - session->recv = callback; - return oldcb; - } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", - cbtype); - - return NULL; + return (void *)libssh2_session_callback_set2(session, cbtype, + (libssh2_cb_generic *)callback); } +#ifdef _MSC_VER +#pragma warning(pop) +#else #pragma GCC diagnostic pop +#endif /* - * _libssh2_wait_socket() + * _libssh2_wait_socket * * Utility function that waits for action on the socket. Returns 0 when ready * to run again or error on timeout. @@ -598,8 +616,8 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) dir = libssh2_session_block_directions(session); if(!dir) { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Nothing to wait for in wait_socket"); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Nothing to wait for in wait_socket")); /* To avoid that we hang below just because there's nothing set to wait for, we timeout on 1 second to also avoid busy-looping during this condition */ @@ -638,7 +656,7 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) sockets[0].events |= POLLOUT; - rc = poll(sockets, 1, has_timeout?ms_to_next: -1); + rc = poll(sockets, 1, has_timeout ? (int)ms_to_next : -1); } #else { @@ -649,21 +667,39 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) struct timeval tv; tv.tv_sec = ms_to_next / 1000; +#ifdef libssh2_usec_t + tv.tv_usec = (libssh2_usec_t)((ms_to_next - tv.tv_sec*1000) * 1000); +#else tv.tv_usec = (ms_to_next - tv.tv_sec*1000) * 1000; +#endif if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) { FD_ZERO(&rfd); +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif FD_SET(session->socket_fd, &rfd); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif readfd = &rfd; } if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) { FD_ZERO(&wfd); +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif FD_SET(session->socket_fd, &wfd); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif writefd = &wfd; } - rc = select(session->socket_fd + 1, readfd, writefd, NULL, + rc = select((int)(session->socket_fd + 1), readfd, writefd, NULL, has_timeout ? &tv : NULL); } #endif @@ -672,6 +708,18 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) "Timed out waiting on socket"); } if(rc < 0) { + int err; +#ifdef _WIN32 + err = _libssh2_wsa2errno(); +#else + err = errno; +#endif + /* Profiling tools that use SIGPROF can cause EINTR responses. + poll() / select() do not set any descriptor states on EINTR, + but some fds may be ready, so the caller should try again */ + if(err == EINTR) + return 0; + return _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Error waiting on socket"); } @@ -685,8 +733,8 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) int rc; if(session->startup_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "session_startup for socket %d", sock); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "session_startup for socket %ld", (long)sock)); if(LIBSSH2_INVALID_SOCKET == sock) { /* Did we forget something? */ return _libssh2_error(session, LIBSSH2_ERROR_BAD_SOCKET, @@ -730,7 +778,7 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) else if(rc) return _libssh2_error(session, rc, "Failed getting banner"); - } while(strncmp("SSH-", (char *)session->remote.banner, 4)); + } while(strncmp("SSH-", (const char *)session->remote.banner, 4)); session->startup_state = libssh2_NB_state_sent1; } @@ -747,8 +795,8 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) } if(session->startup_state == libssh2_NB_state_sent2) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Requesting userauth service"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Requesting userauth service")); /* Request the userauth service */ session->startup_service[0] = SSH_MSG_SERVICE_REQUEST; @@ -780,7 +828,9 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) &session->startup_data_len, 0, NULL, 0, &session->startup_req_state); if(rc) - return rc; + return _libssh2_error(session, rc, + "Failed to get response to " + "ssh-userauth request"); if(session->startup_data_len < 5) { return _libssh2_error(session, LIBSSH2_ERROR_PROTO, @@ -792,7 +842,8 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) if((session->startup_service_length != (sizeof("ssh-userauth") - 1)) - || strncmp("ssh-userauth", (char *) session->startup_data + 5, + || strncmp("ssh-userauth", + (const char *) session->startup_data + 5, session->startup_service_length)) { LIBSSH2_FREE(session, session->startup_data); session->startup_data = NULL; @@ -812,7 +863,7 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) } /* - * libssh2_session_handshake() + * libssh2_session_handshake * * session: LIBSSH2_SESSION struct allocated and owned by the calling program * sock: *must* be populated with an opened and connected socket. @@ -824,13 +875,14 @@ libssh2_session_handshake(LIBSSH2_SESSION *session, libssh2_socket_t sock) { int rc; - BLOCK_ADJUST(rc, session, session_startup(session, sock) ); + BLOCK_ADJUST(rc, session, session_startup(session, sock)); return rc; } +#ifndef LIBSSH2_NO_DEPRECATED /* - * libssh2_session_startup() + * libssh2_session_startup * * DEPRECATED. Use libssh2_session_handshake() instead! This function is not * portable enough. @@ -845,9 +897,10 @@ libssh2_session_startup(LIBSSH2_SESSION *session, int sock) { return libssh2_session_handshake(session, (libssh2_socket_t) sock); } +#endif /* - * libssh2_session_free + * session_free * * Frees the memory allocated to the session * Also closes and frees any channels attached to this session @@ -862,16 +915,16 @@ session_free(LIBSSH2_SESSION *session) int packets_left = 0; if(session->free_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Freeing session resource", - session->remote.banner); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Freeing session resource %p", + (void *)session->remote.banner)); session->free_state = libssh2_NB_state_created; } if(session->free_state == libssh2_NB_state_created) { - while((ch = _libssh2_list_first(&session->channels))) { - + /* !checksrc! disable EQUALSNULL 1 */ + while((ch = _libssh2_list_first(&session->channels)) != NULL) { rc = _libssh2_channel_free(ch); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -881,7 +934,8 @@ session_free(LIBSSH2_SESSION *session) } if(session->free_state == libssh2_NB_state_sent) { - while((l = _libssh2_list_first(&session->listeners))) { + /* !checksrc! disable EQUALSNULL 1 */ + while((l = _libssh2_list_first(&session->listeners)) != NULL) { rc = _libssh2_channel_forward_cancel(l); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -890,6 +944,11 @@ session_free(LIBSSH2_SESSION *session) session->free_state = libssh2_NB_state_sent1; } + if(session->kex && session->kex->cleanup) { + session->kex->cleanup(session, + &session->startup_key_state.key_state_low); + } + if(session->state & LIBSSH2_STATE_NEWKEYS) { /* hostkey */ if(session->hostkey && session->hostkey->dtor) { @@ -981,6 +1040,12 @@ session_free(LIBSSH2_SESSION *session) if(session->remote.lang_prefs) { LIBSSH2_FREE(session, session->remote.lang_prefs); } + if(session->server_sign_algorithms) { + LIBSSH2_FREE(session, session->server_sign_algorithms); + } + if(session->sign_algo_prefs) { + LIBSSH2_FREE(session, session->sign_algo_prefs); + } /* * Make sure all memory used in the state variables are free @@ -994,6 +1059,9 @@ session_free(LIBSSH2_SESSION *session) if(session->userauth_list_data) { LIBSSH2_FREE(session, session->userauth_list_data); } + if(session->userauth_banner) { + LIBSSH2_FREE(session, session->userauth_banner); + } if(session->userauth_pswd_data) { LIBSSH2_FREE(session, session->userauth_pswd_data); } @@ -1058,10 +1126,11 @@ session_free(LIBSSH2_SESSION *session) } /* Cleanup all remaining packets */ - while((pkg = _libssh2_list_first(&session->packets))) { + /* !checksrc! disable EQUALSNULL 1 */ + while((pkg = _libssh2_list_first(&session->packets)) != NULL) { packets_left++; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "packet left with id %d", pkg->data[0]); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "packet left with id %d", pkg->data[0])); /* unlink the node */ _libssh2_list_remove(&pkg->node); @@ -1069,15 +1138,16 @@ session_free(LIBSSH2_SESSION *session) LIBSSH2_FREE(session, pkg->data); LIBSSH2_FREE(session, pkg); } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Extra packets left %d", packets_left); + (void)packets_left; + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Extra packets left %d", packets_left)); if(session->socket_prev_blockstate) { /* if the socket was previously blocking, put it back so */ rc = session_nonblock(session->socket_fd, 0); if(rc) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unable to reset socket's blocking state"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "unable to reset socket's blocking state")); } } @@ -1107,13 +1177,13 @@ libssh2_session_free(LIBSSH2_SESSION * session) { int rc; - BLOCK_ADJUST(rc, session, session_free(session) ); + BLOCK_ADJUST(rc, session, session_free(session)); return rc; } /* - * libssh2_session_disconnect_ex + * session_disconnect */ static int session_disconnect(LIBSSH2_SESSION *session, int reason, @@ -1121,13 +1191,13 @@ session_disconnect(LIBSSH2_SESSION *session, int reason, const char *lang) { unsigned char *s; - unsigned long descr_len = 0, lang_len = 0; + size_t descr_len = 0, lang_len = 0; int rc; if(session->disconnect_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Disconnecting: reason=%d, desc=%s, lang=%s", reason, - description, lang); + description, lang)); if(description) descr_len = strlen(description); @@ -1138,6 +1208,10 @@ session_disconnect(LIBSSH2_SESSION *session, int reason, return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "too long description"); + if(lang_len > 256) + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "too long language string"); + /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */ session->disconnect_data_len = descr_len + lang_len + 13; @@ -1147,14 +1221,14 @@ session_disconnect(LIBSSH2_SESSION *session, int reason, _libssh2_store_u32(&s, reason); _libssh2_store_str(&s, description, descr_len); /* store length only, lang is sent separately */ - _libssh2_store_u32(&s, lang_len); + _libssh2_store_u32(&s, (uint32_t)lang_len); session->disconnect_state = libssh2_NB_state_created; } rc = _libssh2_transport_send(session, session->disconnect_data, session->disconnect_data_len, - (unsigned char *)lang, lang_len); + (const unsigned char *)lang, lang_len); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -1171,6 +1245,7 @@ libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *desc, const char *lang) { int rc; + session->state &= ~LIBSSH2_STATE_INITIAL_KEX; session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; BLOCK_ADJUST(rc, session, session_disconnect(session, reason, desc, lang)); @@ -1303,7 +1378,7 @@ libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg, } if(errmsg_len) { - *errmsg_len = msglen; + *errmsg_len = (int)msglen; } return session->err_code; @@ -1336,7 +1411,7 @@ libssh2_session_set_last_error(LIBSSH2_SESSION* session, LIBSSH2_ERR_FLAG_DUP); } -/* Libssh2_session_flag +/* libssh2_session_flag * * Set/Get session flags * @@ -1352,6 +1427,9 @@ libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value) case LIBSSH2_FLAG_COMPRESS: session->flag.compress = value; break; + case LIBSSH2_FLAG_QUOTE_PATHS: + session->flag.quote_paths = value; + break; default: /* unknown flag */ return LIBSSH2_ERROR_INVAL; @@ -1370,8 +1448,8 @@ int _libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking) { int bl = session->api_block_mode; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Setting blocking mode %s", blocking?"ON":"OFF"); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Setting blocking mode %s", blocking ? "ON" : "OFF")); session->api_block_mode = blocking; return bl; @@ -1385,7 +1463,7 @@ _libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking) LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking) { - (void) _libssh2_session_set_blocking(session, blocking); + (void)_libssh2_session_set_blocking(session, blocking); } /* libssh2_session_get_blocking @@ -1420,6 +1498,30 @@ libssh2_session_get_timeout(LIBSSH2_SESSION * session) return session->api_timeout; } +/* libssh2_session_set_read_timeout + * + * Set a session's timeout (in sec) when reading packets, + * or 0 to use default of 60 seconds. + */ +LIBSSH2_API void +libssh2_session_set_read_timeout(LIBSSH2_SESSION * session, long timeout) +{ + if(timeout <= 0) { + timeout = LIBSSH2_DEFAULT_READ_TIMEOUT; + } + session->packet_read_timeout = timeout; +} + +/* libssh2_session_get_read_timeout + * + * Returns a session's timeout. Default is 60 seconds. + */ +LIBSSH2_API long +libssh2_session_get_read_timeout(LIBSSH2_SESSION * session) +{ + return session->packet_read_timeout; +} + /* * libssh2_poll_channel_read * @@ -1513,7 +1615,7 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) switch(fds[i].type) { case LIBSSH2_POLLFD_SOCKET: sockets[i].fd = fds[i].fd.socket; - sockets[i].events = fds[i].events; + sockets[i].events = (short)fds[i].events; sockets[i].revents = 0; break; @@ -1553,19 +1655,40 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) switch(fds[i].type) { case LIBSSH2_POLLFD_SOCKET: if(fds[i].events & LIBSSH2_POLLFD_POLLIN) { +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif FD_SET(fds[i].fd.socket, &rfds); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif if(fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket; } if(fds[i].events & LIBSSH2_POLLFD_POLLOUT) { +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif FD_SET(fds[i].fd.socket, &wfds); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif if(fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket; } break; case LIBSSH2_POLLFD_CHANNEL: +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif FD_SET(fds[i].fd.channel->session->socket_fd, &rfds); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif if(fds[i].fd.channel->session->socket_fd > maxfd) maxfd = fds[i].fd.channel->session->socket_fd; if(!session) @@ -1573,7 +1696,14 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) break; case LIBSSH2_POLLFD_LISTENER: +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif FD_SET(fds[i].fd.listener->session->socket_fd, &rfds); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif if(fds[i].fd.listener->session->socket_fd > maxfd) maxfd = fds[i].fd.listener->session->socket_fd; if(!session) @@ -1675,23 +1805,15 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) } #ifdef HAVE_POLL -#ifdef HAVE_LIBSSH2_GETTIMEOFDAY { struct timeval tv_begin, tv_end; - _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); - sysret = poll(sockets, nfds, timeout_remaining); - _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); + gettimeofday(&tv_begin, NULL); + sysret = poll(sockets, nfds, (int)timeout_remaining); + gettimeofday(&tv_end, NULL); timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; } -#else - /* If the platform doesn't support gettimeofday, - * then just make the call non-blocking and walk away - */ - sysret = poll(sockets, nfds, timeout_remaining); - timeout_remaining = 0; -#endif /* HAVE_GETTIMEOFDAY */ if(sysret > 0) { for(i = 0; i < nfds; i++) { @@ -1737,30 +1859,31 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) } #elif defined(HAVE_SELECT) tv.tv_sec = timeout_remaining / 1000; +#ifdef libssh2_usec_t + tv.tv_usec = (libssh2_usec_t)((timeout_remaining % 1000) * 1000); +#else tv.tv_usec = (timeout_remaining % 1000) * 1000; -#ifdef HAVE_LIBSSH2_GETTIMEOFDAY +#endif + { struct timeval tv_begin, tv_end; - _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); - sysret = select(maxfd + 1, &rfds, &wfds, NULL, &tv); - _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); + gettimeofday(&tv_begin, NULL); + sysret = select((int)(maxfd + 1), &rfds, &wfds, NULL, &tv); + gettimeofday(&tv_end, NULL); timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; } -#else - /* If the platform doesn't support gettimeofday, - * then just make the call non-blocking and walk away - */ - sysret = select(maxfd + 1, &rfds, &wfds, NULL, &tv); - timeout_remaining = 0; -#endif if(sysret > 0) { for(i = 0; i < nfds; i++) { switch(fds[i].type) { case LIBSSH2_POLLFD_SOCKET: +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif if(FD_ISSET(fds[i].fd.socket, &rfds)) { fds[i].revents |= LIBSSH2_POLLFD_POLLIN; } @@ -1770,6 +1893,9 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) if(fds[i].revents) { active_fds++; } +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif break; case LIBSSH2_POLLFD_CHANNEL: @@ -1822,10 +1948,10 @@ LIBSSH2_API const char * libssh2_session_banner_get(LIBSSH2_SESSION *session) { /* to avoid a coredump when session is NULL */ - if(NULL == session) + if(!session) return NULL; - if(NULL == session->remote.banner) + if(!session->remote.banner) return NULL; return (const char *) session->remote.banner; diff --git a/uppsrc/Core/SSH/libssh2/session.h b/uppsrc/Core/SSH/libssh2/session.h index 9f8f2c706..d4fc5755e 100644 --- a/uppsrc/Core/SSH/libssh2/session.h +++ b/uppsrc/Core/SSH/libssh2/session.h @@ -1,8 +1,8 @@ -#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 +#ifndef LIBSSH2_SESSION_H +#define LIBSSH2_SESSION_H +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -37,31 +37,32 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* Conveniance-macros to allow code like this; - int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock) ); + int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock)); - int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock) ); + int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock)); - The point of course being to make sure that while in non-blocking mode - these always return no matter what the return code is, but in blocking mode - it blocks if EAGAIN is the reason for the return from the underlying - function. + The point being to make sure that while in non-blocking mode these always + return no matter what the return code is, but in blocking mode it blocks + if EAGAIN is the reason for the return from the underlying function. */ #define BLOCK_ADJUST(rc, sess, x) \ do { \ - time_t entry_time = time(NULL); \ - do { \ - rc = x; \ - /* the order of the check below is important to properly deal with \ - the case when the 'sess' is freed */ \ - if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \ - break; \ - rc = _libssh2_wait_socket(sess, entry_time); \ - } while(!rc); \ + time_t entry_time = time(NULL); \ + do { \ + rc = x; \ + /* the order of the check below is important to properly \ + deal with the case when the 'sess' is freed */ \ + if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \ + break; \ + rc = _libssh2_wait_socket(sess, entry_time); \ + } while(!rc); \ } while(0) /* @@ -72,15 +73,15 @@ */ #define BLOCK_ADJUST_ERRNO(ptr, sess, x) \ do { \ - time_t entry_time = time(NULL); \ - int rc; \ - do { \ - ptr = x; \ - if(!sess->api_block_mode || \ - (ptr != NULL) || \ - (libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN) ) \ - break; \ - rc = _libssh2_wait_socket(sess, entry_time); \ + time_t entry_time = time(NULL); \ + int rc; \ + do { \ + ptr = x; \ + if(!sess->api_block_mode || \ + (ptr != NULL) || \ + (libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN)) \ + break; \ + rc = _libssh2_wait_socket(sess, entry_time); \ } while(!rc); \ } while(0) @@ -90,4 +91,4 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t entry_time); /* this is the lib-internal set blocking function */ int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking); -#endif /* __LIBSSH2_SESSION_H */ +#endif /* LIBSSH2_SESSION_H */ diff --git a/uppsrc/Core/SSH/libssh2/sftp.c b/uppsrc/Core/SSH/libssh2/sftp.c index ac7ee0162..6ede31110 100644 --- a/uppsrc/Core/SSH/libssh2/sftp.c +++ b/uppsrc/Core/SSH/libssh2/sftp.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2008, Sara Golemon - * Copyright (c) 2007 Eli Fant - * Copyright (c) 2009-2019 by Daniel Stenberg +/* Copyright (C) Sara Golemon + * Copyright (C) Eli Fant + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,21 +35,26 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include - #include "libssh2_priv.h" #include "libssh2_sftp.h" + #include "channel.h" #include "session.h" #include "sftp.h" -/* Note: Version 6 was documented at the time of writing - * However it was marked as "DO NOT IMPLEMENT" due to pending changes - * - * This release of libssh2 implements Version 5 with automatic downgrade +#include +#include /* strtol() */ + +/* This release of libssh2 implements Version 5 with automatic downgrade * based on server's declaration + * https://www.ietf.org/archive/id/draft-ietf-secsh-filexfer-05.txt + * + * Version 6: + * https://www.ietf.org/archive/id/draft-ietf-secsh-filexfer-13.txt */ /* SFTP packet types */ @@ -98,39 +103,6 @@ static int sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type, size_t *data_len); static void sftp_packet_flush(LIBSSH2_SFTP *sftp); -/* sftp_attrsize - * Size that attr with this flagset will occupy when turned into a bin struct - */ -static int sftp_attrsize(unsigned long flags) -{ - return (4 + /* flags(4) */ - ((flags & LIBSSH2_SFTP_ATTR_SIZE) ? 8 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_UIDGID) ? 8 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) ? 4 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_ACMODTIME) ? 8 : 0)); - /* atime + mtime as u32 */ -} - -/* _libssh2_store_u64 - */ -static void _libssh2_store_u64(unsigned char **ptr, libssh2_uint64_t value) -{ - uint32_t msl = (uint32_t)(value >> 32); - unsigned char *buf = *ptr; - - buf[0] = (unsigned char)((msl >> 24) & 0xFF); - buf[1] = (unsigned char)((msl >> 16) & 0xFF); - buf[2] = (unsigned char)((msl >> 8) & 0xFF); - buf[3] = (unsigned char)( msl & 0xFF); - - buf[4] = (unsigned char)((value >> 24) & 0xFF); - buf[5] = (unsigned char)((value >> 16) & 0xFF); - buf[6] = (unsigned char)((value >> 8) & 0xFF); - buf[7] = (unsigned char)( value & 0xFF); - - *ptr += 8; -} - /* * Search list of zombied FXP_READ request IDs. * @@ -160,10 +132,10 @@ remove_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) struct sftp_zombie_requests *zombie = find_zombie_request(sftp, request_id); if(zombie) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Removing request ID %ld from the list of " + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Removing request ID %u from the list of " "zombie requests", - request_id); + request_id)); _libssh2_list_remove(&zombie->node); LIBSSH2_FREE(session, zombie); @@ -177,14 +149,14 @@ add_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) struct sftp_zombie_requests *zombie; - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Marking request ID %ld as a zombie request", request_id); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Marking request ID %u as a zombie request", request_id)); zombie = LIBSSH2_ALLOC(sftp->channel->session, sizeof(struct sftp_zombie_requests)); if(!zombie) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "malloc fail for zombie request ID"); + "malloc fail for zombie request ID"); else { zombie->request_id = request_id; _libssh2_list_add(&sftp->zombie_requests, &zombie->node); @@ -192,9 +164,7 @@ add_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) } } -/* - * sftp_packet_add - * +/* sftp_packet_add * Add a packet to the SFTP packet brigade */ static int @@ -209,9 +179,9 @@ sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, return LIBSSH2_ERROR_OUT_OF_BOUNDARY; } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Received packet type %d (len %d)", - (int) data[0], data_len); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Received packet type %u (len %lu)", + (unsigned int)data[0], (unsigned long)data_len)); /* * Experience shows that if we mess up EAGAIN handling somewhere or @@ -250,14 +220,15 @@ sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, case SSH_FXP_EXTENDED_REPLY: break; default: + sftp->last_errno = LIBSSH2_FX_OK; return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Out of sync with the world"); } request_id = _libssh2_ntohu32(&data[1]); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Received packet id %d", - request_id); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Received packet id %d", + request_id)); /* Don't add the packet if it answers a request we've given up on. */ if((data[0] == SSH_FXP_STATUS || data[0] == SSH_FXP_DATA) @@ -287,9 +258,7 @@ sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, return LIBSSH2_ERROR_NONE; } -/* - * sftp_packet_read - * +/* sftp_packet_read * Frame an SFTP packet off the channel */ static int @@ -301,8 +270,9 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) ssize_t rc; unsigned long recv_window; int packet_type; + uint32_t request_id; - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "recv packet"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "recv packet")); switch(sftp->packet_state) { case libssh2_NB_state_sent: /* EAGAIN from window adjusting */ @@ -316,12 +286,12 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) packet = sftp->partial_packet; - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "partial read cont, len: %lu", sftp->partial_len); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "partial read cont, len: %u", sftp->partial_len)); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "partial read cont, already recvd: %lu", - sftp->partial_received); - /* fall-through */ + (unsigned long)sftp->partial_received)); + LIBSSH2_FALLTHROUGH(); default: if(!packet) { /* only do this if there's not already a packet buffer allocated @@ -329,49 +299,59 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) /* each packet starts with a 32 bit length field */ rc = _libssh2_channel_read(channel, 0, - (char *)&sftp->partial_size[ - sftp->partial_size_len], - 4 - sftp->partial_size_len); + (char *)&sftp->packet_header[ + sftp->packet_header_len], + sizeof(sftp->packet_header) - + sftp->packet_header_len); if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; + return (int)rc; else if(rc < 0) - return _libssh2_error(session, rc, "channel read"); + return _libssh2_error(session, (int)rc, "channel read"); - sftp->partial_size_len += rc; + sftp->packet_header_len += rc; - if(4 != sftp->partial_size_len) - /* we got a short read for the length part */ + if(sftp->packet_header_len != sizeof(sftp->packet_header)) + /* we got a short read for the header part */ return LIBSSH2_ERROR_EAGAIN; - sftp->partial_len = _libssh2_ntohu32(sftp->partial_size); + /* parse SFTP packet header */ + sftp->partial_len = _libssh2_ntohu32(sftp->packet_header); + packet_type = sftp->packet_header[4]; + request_id = _libssh2_ntohu32(sftp->packet_header + 5); + /* make sure we don't proceed if the packet size is unreasonably large */ - if(sftp->partial_len > LIBSSH2_SFTP_PACKET_MAXLEN) { + if(sftp->partial_len > LIBSSH2_SFTP_PACKET_MAXLEN && + /* exception: response to SSH_FXP_READDIR request */ + !(sftp->readdir_state != libssh2_NB_state_idle && + sftp->readdir_request_id == request_id && + packet_type == SSH_FXP_NAME)) { libssh2_channel_flush(channel); - sftp->partial_size_len = 0; + sftp->packet_header_len = 0; return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "SFTP packet too large"); } - if(sftp->partial_len == 0) + if(sftp->partial_len < 5) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate empty SFTP packet"); + "Invalid SFTP packet size"); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Data begin - Packet Length: %lu", - sftp->partial_len); + (unsigned long)sftp->partial_len)); packet = LIBSSH2_ALLOC(session, sftp->partial_len); if(!packet) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate SFTP packet"); - sftp->partial_size_len = 0; - sftp->partial_received = 0; /* how much of the packet already - received */ + sftp->packet_header_len = 0; sftp->partial_packet = packet; + /* copy over packet type(4) and request id(1) */ + sftp->partial_received = 5; + memcpy(packet, sftp->packet_header + 4, 5); - window_adjust: +window_adjust: recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); if(sftp->partial_len > recv_window) { @@ -382,12 +362,12 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) 1, NULL); /* store the state so that we continue with the correct operation at next invoke */ - sftp->packet_state = (rc == LIBSSH2_ERROR_EAGAIN)? - libssh2_NB_state_sent: + sftp->packet_state = (rc == LIBSSH2_ERROR_EAGAIN) ? + libssh2_NB_state_sent : libssh2_NB_state_idle; if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; + return (int)rc; } } @@ -405,12 +385,12 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) * knows how to continue on the next invoke. */ sftp->packet_state = libssh2_NB_state_sent1; - return rc; + return (int)rc; } else if(rc < 0) { LIBSSH2_FREE(session, packet); sftp->partial_packet = NULL; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for SFTP packet"); } sftp->partial_received += rc; @@ -424,7 +404,7 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) rc = sftp_packet_add(sftp, packet, sftp->partial_len); if(rc) { LIBSSH2_FREE(session, packet); - return rc; + return (int)rc; } else { return packet_type; @@ -432,8 +412,8 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) } /* WON'T REACH */ } -/* - * sftp_packetlist_flush + +/* sftp_packetlist_flush * * Remove all pending packets in the packet_list and the corresponding one(s) * in the SFTP packet brigade. @@ -474,7 +454,7 @@ static void sftp_packetlist_flush(LIBSSH2_SFTP_HANDLE *handle) /* - * sftp_packet_ask() + * sftp_packet_ask * * Checks if there's a matching SFTP packet available. */ @@ -523,19 +503,19 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type, LIBSSH2_SESSION *session = sftp->channel->session; int rc; - if(data == NULL || data_len == NULL || required_size == 0) { + if(!data || !data_len || required_size == 0) { return LIBSSH2_ERROR_BAD_USE; } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Requiring packet %d id %ld", - (int) packet_type, request_id); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Requiring packet %u id %u", + (unsigned int) packet_type, request_id)); if(sftp_packet_ask(sftp, packet_type, request_id, data, data_len) == 0) { /* The right packet was available in the packet brigade */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", - (int) packet_type); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Got %u", + (unsigned int) packet_type)); - if (*data_len < required_size) { + if(*data_len < required_size) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } @@ -550,10 +530,10 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type, /* data was read, check the queue again */ if(!sftp_packet_ask(sftp, packet_type, request_id, data, data_len)) { /* The right packet was available in the packet brigade */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", - (int) packet_type); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Got %d", + (unsigned int) packet_type)); - if (*data_len < required_size) { + if(*data_len < required_size) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } @@ -577,7 +557,7 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, int i; int rc; - if(data == NULL || data_len == NULL || required_size == 0) { + if(!data || !data_len || required_size == 0) { return LIBSSH2_ERROR_BAD_USE; } @@ -588,14 +568,14 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, while(sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) { for(i = 0; i < num_valid_responses; i++) { if(sftp_packet_ask(sftp, valid_responses[i], request_id, - data, data_len) == 0) { + data, data_len) == 0) { /* * Set to zero before all returns to say * the timeout is not active */ sftp->requirev_start = 0; - if (*data_len < required_size) { + if(*data_len < required_size) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } @@ -611,7 +591,7 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, else if(rc <= 0) { /* prevent busy-looping */ long left = - LIBSSH2_READ_TIMEOUT - + sftp->channel->session->packet_read_timeout - (long)(time(NULL) - sftp->requirev_start); if(left <= 0) { @@ -630,6 +610,19 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, return LIBSSH2_ERROR_SOCKET_DISCONNECT; } +/* sftp_attrsize + * Size that attr with this flagset will occupy when turned into a bin struct + */ +static int sftp_attrsize(unsigned long flags) +{ + return 4 + /* flags(4) */ + ((flags & LIBSSH2_SFTP_ATTR_SIZE) ? 8 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_UIDGID) ? 8 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) ? 4 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_ACMODTIME) ? 8 : 0); + /* atime + mtime as u32 */ +} + /* sftp_attr2bin * Populate attributes into an SFTP block */ @@ -638,8 +631,10 @@ sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs) { unsigned char *s = p; uint32_t flag_mask = - LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID | - LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME; + LIBSSH2_SFTP_ATTR_SIZE | + LIBSSH2_SFTP_ATTR_UIDGID | + LIBSSH2_SFTP_ATTR_PERMISSIONS | + LIBSSH2_SFTP_ATTR_ACMODTIME; /* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */ @@ -649,32 +644,32 @@ sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs) return 4; } - _libssh2_store_u32(&s, attrs->flags & flag_mask); + _libssh2_store_u32(&s, (uint32_t)(attrs->flags & flag_mask)); if(attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { _libssh2_store_u64(&s, attrs->filesize); } if(attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { - _libssh2_store_u32(&s, attrs->uid); - _libssh2_store_u32(&s, attrs->gid); + _libssh2_store_u32(&s, (uint32_t)attrs->uid); + _libssh2_store_u32(&s, (uint32_t)attrs->gid); } if(attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { - _libssh2_store_u32(&s, attrs->permissions); + _libssh2_store_u32(&s, (uint32_t)attrs->permissions); } if(attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { - _libssh2_store_u32(&s, attrs->atime); - _libssh2_store_u32(&s, attrs->mtime); + _libssh2_store_u32(&s, (uint32_t)attrs->atime); + _libssh2_store_u32(&s, (uint32_t)attrs->mtime); } - return (s - p); + return s - p; } /* sftp_bin2attr */ -static int +static ssize_t sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, size_t data_len) { @@ -684,13 +679,13 @@ sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, buf.dataptr = buf.data; buf.len = data_len; - if(_libssh2_get_u32(&buf, &flags) != 0) { + if(_libssh2_get_u32(&buf, &flags)) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } attrs->flags = flags; if(attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { - if(_libssh2_get_u64(&buf, &(attrs->filesize)) != 0) { + if(_libssh2_get_u64(&buf, &(attrs->filesize))) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } } @@ -698,8 +693,8 @@ sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, if(attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { uint32_t uid = 0; uint32_t gid = 0; - if(_libssh2_get_u32(&buf, &uid) != 0 || - _libssh2_get_u32(&buf, &gid) != 0) { + if(_libssh2_get_u32(&buf, &uid) || + _libssh2_get_u32(&buf, &gid)) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } attrs->uid = uid; @@ -708,7 +703,7 @@ sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, if(attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { uint32_t permissions; - if(_libssh2_get_u32(&buf, &permissions) != 0) { + if(_libssh2_get_u32(&buf, &permissions)) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } attrs->permissions = permissions; @@ -717,15 +712,36 @@ sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, if(attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { uint32_t atime; uint32_t mtime; - if(_libssh2_get_u32(&buf, &atime) != 0 || - _libssh2_get_u32(&buf, &mtime) != 0) { + if(_libssh2_get_u32(&buf, &atime) || + _libssh2_get_u32(&buf, &mtime)) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } attrs->atime = atime; attrs->mtime = mtime; } - return (buf.dataptr - buf.data); + /* Parse extended data, if present, to avoid stream parsing errors */ + if(attrs->flags & LIBSSH2_SFTP_ATTR_EXTENDED) { + uint32_t extended_count; + uint32_t i; + size_t etype_len; + unsigned char *etype; + size_t edata_len; + unsigned char *edata; + + if(_libssh2_get_u32(&buf, &extended_count)) { + return LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } + + for(i = 0; i < extended_count; ++i) { + if(_libssh2_get_string(&buf, &etype, &etype_len) || + _libssh2_get_string(&buf, &edata, &edata_len)) { + return LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } + } + } + + return buf.dataptr - buf.data; } /* ************ @@ -741,8 +757,8 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) { LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract); - (void) session_abstract; - (void) channel; + (void)session_abstract; + (void)channel; /* Free the partial packet storage for sftp_packet_read */ if(sftp->partial_packet) { @@ -757,23 +773,21 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) LIBSSH2_FREE(session, sftp); } -/* - * sftp_init - * +/* sftp_init * Startup an SFTP session */ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) { unsigned char *data; - size_t data_len; + size_t data_len = 0; ssize_t rc; LIBSSH2_SFTP *sftp_handle; struct string_buf buf; unsigned char *endp; if(session->sftpInit_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Initializing SFTP subsystem"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Initializing SFTP subsystem")); /* * The 'sftpInit_sftp' and 'sftpInit_channel' struct fields within the @@ -787,7 +801,7 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) * including *EAGAIN). */ - assert(session->sftpInit_sftp == NULL); + assert(!session->sftpInit_sftp); session->sftpInit_sftp = NULL; session->sftpInit_state = libssh2_NB_state_created; } @@ -860,10 +874,10 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) _libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION); session->sftpInit_sent = 0; /* nothing's sent yet */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Sending FXP_INIT packet advertising " "version %d support", - (int) LIBSSH2_SFTP_VERSION); + (int) LIBSSH2_SFTP_VERSION)); session->sftpInit_state = libssh2_NB_state_sent2; } @@ -896,6 +910,22 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) } } + if(session->sftpInit_state == libssh2_NB_state_error_closing) { + rc = _libssh2_channel_free(session->sftpInit_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block closing channel"); + return NULL; + } + session->sftpInit_channel = NULL; + if(session->sftpInit_sftp) { + LIBSSH2_FREE(session, session->sftpInit_sftp); + session->sftpInit_sftp = NULL; + } + session->sftpInit_state = libssh2_NB_state_idle; + return NULL; + } + rc = sftp_packet_require(sftp_handle, SSH_FXP_VERSION, 0, &data, &data_len, 5); if(rc == LIBSSH2_ERROR_EAGAIN) { @@ -912,7 +942,7 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) goto sftp_init_error; } else if(rc) { - _libssh2_error(session, rc, + _libssh2_error(session, (int)rc, "Timeout waiting for response from SFTP subsystem"); goto sftp_init_error; } @@ -922,37 +952,59 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) buf.len = data_len; endp = &buf.data[data_len]; - if(_libssh2_get_u32(&buf, &(sftp_handle->version)) != 0) { + if(_libssh2_get_u32(&buf, &(sftp_handle->version))) { LIBSSH2_FREE(session, data); rc = LIBSSH2_ERROR_BUFFER_TOO_SMALL; goto sftp_init_error; } if(sftp_handle->version > LIBSSH2_SFTP_VERSION) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Truncating remote SFTP version from %lu", - sftp_handle->version); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Truncating remote SFTP version from %u", + sftp_handle->version)); sftp_handle->version = LIBSSH2_SFTP_VERSION; } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Enabling SFTP version %lu compatibility", - sftp_handle->version); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Enabling SFTP version %u compatibility", + sftp_handle->version)); while(buf.dataptr < endp) { unsigned char *extname, *extdata; + size_t extname_len, extdata_len; + uint32_t extversion = 0; - if(_libssh2_get_string(&buf, &extname, NULL)) { + if(_libssh2_get_string(&buf, &extname, &extname_len)) { LIBSSH2_FREE(session, data); _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, "Data too short when extracting extname"); goto sftp_init_error; } - if(_libssh2_get_string(&buf, &extdata, NULL)) { + if(_libssh2_get_string(&buf, &extdata, &extdata_len)) { LIBSSH2_FREE(session, data); _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, "Data too short when extracting extdata"); goto sftp_init_error; } + + if(extdata_len > 0) { + char *extversion_str; + extversion_str = (char *)LIBSSH2_ALLOC(session, extdata_len + 1); + if(!extversion_str) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for SSH_FXP_VERSION " + "packet"); + goto sftp_init_error; + } + memcpy(extversion_str, extdata, extdata_len); + extversion_str[extdata_len] = '\0'; + extversion = (uint32_t)strtol(extversion_str, NULL, 10); + LIBSSH2_FREE(session, extversion_str); + } + if(extname_len == 24 + && strncmp("posix-rename@openssh.com", (char *)extname, 24) == 0) { + sftp_handle->posix_rename_version = extversion; + } + } LIBSSH2_FREE(session, data); @@ -971,21 +1023,12 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) return sftp_handle; - sftp_init_error: - while(_libssh2_channel_free(session->sftpInit_channel) == - LIBSSH2_ERROR_EAGAIN); - session->sftpInit_channel = NULL; - if(session->sftpInit_sftp) { - LIBSSH2_FREE(session, session->sftpInit_sftp); - session->sftpInit_sftp = NULL; - } - session->sftpInit_state = libssh2_NB_state_idle; +sftp_init_error: + session->sftpInit_state = libssh2_NB_state_error_closing; return NULL; } -/* - * libssh2_sftp_init - * +/* libssh2_sftp_init * Startup an SFTP session */ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session) @@ -1005,9 +1048,7 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session) return ptr; } -/* - * sftp_shutdown - * +/* sftp_shutdown * Shuts down the SFTP subsystem */ static int @@ -1103,7 +1144,7 @@ libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) static LIBSSH2_SFTP_HANDLE * sftp_open(LIBSSH2_SFTP *sftp, const char *filename, size_t filename_len, uint32_t flags, long mode, - int open_type) + int open_type, LIBSSH2_SFTP_ATTRIBUTES *attrs_in) { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; @@ -1113,14 +1154,19 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, }; unsigned char *s; ssize_t rc; - int open_file = (open_type == LIBSSH2_SFTP_OPENFILE)?1:0; + int open_file = (open_type == LIBSSH2_SFTP_OPENFILE) ? 1 : 0; if(sftp->open_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + + if(attrs_in) { + memcpy(&attrs, attrs_in, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); + } + /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + flags(4) */ - sftp->open_packet_len = filename_len + 13 + - (open_file? (4 + - sftp_attrsize(LIBSSH2_SFTP_ATTR_PERMISSIONS)) : 0); + sftp->open_packet_len = (uint32_t)(filename_len + 13 + + (open_file ? (4 + sftp_attrsize(attrs.flags)) : 0)); /* surprise! this starts out with nothing sent */ sftp->open_packet_sent = 0; @@ -1137,7 +1183,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, LIBSSH2_SFTP_ATTR_PFILETYPE_DIR); _libssh2_store_u32(&s, sftp->open_packet_len - 4); - *(s++) = open_file? SSH_FXP_OPEN : SSH_FXP_OPENDIR; + *(s++) = open_file ? SSH_FXP_OPEN : SSH_FXP_OPENDIR; sftp->open_request_id = sftp->request_id++; _libssh2_store_u32(&s, sftp->open_request_id); _libssh2_store_str(&s, filename, filename_len); @@ -1147,8 +1193,8 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, s += sftp_attr2bin(s, &attrs); } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Sending %s open request", - open_file? "file" : "directory"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Sending %s open request", + open_file ? "file" : "directory")); sftp->open_state = libssh2_NB_state_created; } @@ -1165,7 +1211,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, return NULL; } else if(rc < 0) { - _libssh2_error(session, rc, "Unable to send FXP_OPEN*"); + _libssh2_error(session, (int)rc, "Unable to send FXP_OPEN*"); LIBSSH2_FREE(session, sftp->open_packet); sftp->open_packet = NULL; sftp->open_state = libssh2_NB_state_idle; @@ -1185,7 +1231,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, } if(sftp->open_state == libssh2_NB_state_sent) { - size_t data_len; + size_t data_len = 0; unsigned char *data; static const unsigned char fopen_responses[2] = { SSH_FXP_HANDLE, SSH_FXP_STATUS }; @@ -1207,7 +1253,8 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, } sftp->open_state = libssh2_NB_state_idle; if(rc) { - _libssh2_error(session, rc, "Timeout waiting for status message"); + _libssh2_error(session, (int)rc, + "Timeout waiting for status message"); return NULL; } @@ -1228,8 +1275,8 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, sftp->last_errno = _libssh2_ntohu32(data + 5); if(LIBSSH2_FX_OK == sftp->last_errno) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "got HANDLE FXOK!"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "got HANDLE FXOK")); LIBSSH2_FREE(session, data); @@ -1258,9 +1305,9 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, if(badness) { _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Failed opening remote file"); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "got FXP_STATUS %d", - sftp->last_errno); + sftp->last_errno)); LIBSSH2_FREE(session, data); return NULL; } @@ -1304,7 +1351,8 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, fp->u.file.offset = 0; fp->u.file.offset_sent = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Open command successful"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Open command successful")); return fp; } return NULL; @@ -1323,16 +1371,31 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, return NULL; BLOCK_ADJUST_ERRNO(hnd, sftp->channel->session, - sftp_open(sftp, filename, filename_len, flags, mode, - open_type)); + sftp_open(sftp, filename, filename_len, (uint32_t)flags, + mode, open_type, NULL)); return hnd; } -/* - * sftp_read - * +/* libssh2_sftp_open_ex_r + */ +LIBSSH2_API LIBSSH2_SFTP_HANDLE * +libssh2_sftp_open_ex_r(LIBSSH2_SFTP *sftp, const char *filename, + size_t filename_len, unsigned long flags, long mode, + int open_type, LIBSSH2_SFTP_ATTRIBUTES *attrs) +{ + LIBSSH2_SFTP_HANDLE *hnd; + + if(!sftp) + return NULL; + + BLOCK_ADJUST_ERRNO(hnd, sftp->channel->session, + sftp_open(sftp, filename, filename_len, (uint32_t)flags, + mode, open_type, attrs)); + return hnd; +} + +/* sftp_read * Read from an SFTP file handle - * */ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, size_t buffer_size) @@ -1382,13 +1445,14 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, switch(sftp->read_state) { case libssh2_NB_state_idle: + sftp->last_errno = LIBSSH2_FX_OK; /* Some data may already have been read from the server in the previous call but didn't fit in the buffer at the time. If so, we return that now as we can't risk being interrupted later with data partially written to the buffer. */ if(filep->data_left) { - size_t copy = MIN(buffer_size, filep->data_left); + size_t copy = LIBSSH2_MIN(buffer_size, filep->data_left); memcpy(buffer, &filep->data[ filep->data_len - filep->data_left], copy); @@ -1452,8 +1516,8 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, allows, expand it! */ rc = _libssh2_channel_receive_window_adjust(sftp->channel, - max_read_ahead*8, - 1, NULL); + (uint32_t)(max_read_ahead * 8), + 1, NULL); /* if this returns EAGAIN, we will get back to this function at next call */ assert(rc != LIBSSH2_ERROR_EAGAIN || !filep->data_left); @@ -1468,12 +1532,12 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */ - uint32_t packet_len = (uint32_t)handle->handle_len + 25; + uint32_t packet_len = (uint32_t)(handle->handle_len + 25); uint32_t request_id; - uint32_t size = count; + uint32_t size = (uint32_t)count; if(size < buffer_size) - size = buffer_size; + size = (uint32_t)buffer_size; if(size > MAX_SFTP_READ_SIZE) size = MAX_SFTP_READ_SIZE; @@ -1502,13 +1566,15 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, /* add this new entry LAST in the list */ _libssh2_list_add(&handle->packet_list, &chunk->node); - count -= MIN(size, count); /* deduct the size we used, as we might - * have to create more packets */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "read request id %d sent (offset: %d, size: %d)", - request_id, (int)chunk->offset, (int)chunk->len); + /* deduct the size we used, as we might have to create + more packets */ + count -= LIBSSH2_MIN(size, count); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "read request id %d sent (offset: %lu, size: %lu)", + request_id, (unsigned long)chunk->offset, + (unsigned long)chunk->len)); } - /* FALL-THROUGH */ + LIBSSH2_FALLTHROUGH(); case libssh2_NB_state_sent: sftp->read_state = libssh2_NB_state_idle; @@ -1548,7 +1614,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, /* move on to the next chunk with data to send */ chunk = _libssh2_list_next(&chunk->node); } - /* FALL-THROUGH */ + LIBSSH2_FALLTHROUGH(); case libssh2_NB_state_sent2: @@ -1561,7 +1627,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, while(chunk) { unsigned char *data; - size_t data_len; + size_t data_len = 0; uint32_t rc32; static const unsigned char read_responses[2] = { SSH_FXP_DATA, SSH_FXP_STATUS @@ -1582,7 +1648,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, rc = sftp_packet_requirev(sftp, 2, read_responses, chunk->request_id, &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN && bytes_in_buffer != 0) { + if(rc == LIBSSH2_ERROR_EAGAIN && bytes_in_buffer) { /* do not return EAGAIN if we have already * written data into the buffer */ return bytes_in_buffer; @@ -1628,7 +1694,6 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP READ error"); } - break; case SSH_FXP_DATA: if(chunk->offset != filep->offset) { @@ -1636,7 +1701,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, requested, which shouldn't happen for normal files. See: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 #section-6.4 - */ + */ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Read Packet At Unexpected Offset"); } @@ -1667,7 +1732,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, /* getting the full packet would overflow the buffer, so only get the correct amount and keep the remainder */ - rc32 = (uint32_t)buffer_size - bytes_in_buffer; + rc32 = (uint32_t)(buffer_size - bytes_in_buffer); /* store data to keep for next call */ filep->data = data; @@ -1717,7 +1782,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, break; default: - assert(!"State machine error; unrecognised read state"); + assert(0); /* State machine error; unrecognised read state */ } /* we should never reach this point */ @@ -1751,16 +1816,18 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; uint32_t num_names; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 13; + uint32_t packet_len = (uint32_t)(handle->handle_len + 13); unsigned char *s, *data; static const unsigned char read_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS }; ssize_t retcode; if(sftp->readdir_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + if(handle->u.dir.names_left) { /* * A prior request returned more than one directory entry, @@ -1772,7 +1839,7 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t filename_len; size_t longentry_len; size_t names_packet_len = handle->u.dir.names_packet_len; - int attr_len = 0; + ssize_t attr_len = 0; if(names_packet_len >= 4) { s = (unsigned char *) handle->u.dir.next_name; @@ -1813,7 +1880,7 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, goto end; } - if(longentry && (longentry_maxlen>1)) { + if(longentry && (longentry_maxlen > 1)) { longentry_len = real_longentry_len; if(longentry_len >= longentry_maxlen || @@ -1852,14 +1919,14 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, handle->u.dir.next_name = (char *) s; handle->u.dir.names_packet_len = names_packet_len; - end: if((--handle->u.dir.names_left) == 0) LIBSSH2_FREE(session, handle->u.dir.names_packet); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "libssh2_sftp_readdir_ex() return %d", - filename_len); +end: + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "libssh2_sftp_readdir_ex() return %lu", + (unsigned long)filename_len)); return (ssize_t)filename_len; } @@ -1881,8 +1948,8 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, } if(sftp->readdir_state == libssh2_NB_state_created) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Reading entries from directory handle"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Reading entries from directory handle")); retcode = _libssh2_channel_write(channel, 0, sftp->readdir_packet, packet_len); if(retcode == LIBSSH2_ERROR_EAGAIN) { @@ -1916,19 +1983,20 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, } else if(retcode) { sftp->readdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, retcode, + return _libssh2_error(session, (int)retcode, "Timeout waiting for status message"); } if(data[0] == SSH_FXP_STATUS) { - retcode = _libssh2_ntohu32(data + 5); + unsigned int rerrno; + rerrno = _libssh2_ntohu32(data + 5); LIBSSH2_FREE(session, data); - if(retcode == LIBSSH2_FX_EOF) { + if(rerrno == LIBSSH2_FX_EOF) { sftp->readdir_state = libssh2_NB_state_idle; return 0; } else { - sftp->last_errno = retcode; + sftp->last_errno = rerrno; sftp->readdir_state = libssh2_NB_state_idle; return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error"); @@ -1938,8 +2006,8 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, sftp->readdir_state = libssh2_NB_state_idle; num_names = _libssh2_ntohu32(data + 5); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%lu entries returned", - num_names); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "%u entries returned", + num_names)); if(!num_names) { LIBSSH2_FREE(session, data); return 0; @@ -1964,17 +2032,16 @@ libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *hnd, char *buffer, size_t longentry_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs) { - int rc; + ssize_t rc; if(!hnd) return LIBSSH2_ERROR_BAD_USE; BLOCK_ADJUST(rc, hnd->sftp->channel->session, sftp_readdir(hnd, buffer, buffer_maxlen, longentry, longentry_maxlen, attrs)); - return rc; + return (int)rc; /* FIXME: -> ssize_t */ } -/* - * sftp_write +/* sftp_write * * Write data to an SFTP handle. Returns the number of bytes written, or * a negative error code. @@ -2017,10 +2084,10 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; uint32_t retcode; uint32_t packet_len; - unsigned char *s, *data; + unsigned char *s, *data = NULL; ssize_t rc; struct sftp_pipeline_chunk *chunk; struct sftp_pipeline_chunk *next; @@ -2031,6 +2098,7 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, switch(sftp->write_state) { default: case libssh2_NB_state_idle: + sftp->last_errno = LIBSSH2_FX_OK; /* Number of bytes sent off that haven't been acked and therefore we will get passed in here again. @@ -2039,8 +2107,8 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, acked but we haven't been able to return as such yet, so we will get that data as well passed in here again. */ - already = (size_t) (handle->u.file.offset_sent - - handle->u.file.offset)+ + already = (size_t)(handle->u.file.offset_sent - + handle->u.file.offset)+ handle->u.file.acked; if(count >= already) { @@ -2056,12 +2124,13 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, while(count) { /* TODO: Possibly this should have some logic to prevent a very very small fraction to be left but lets ignore that for now */ - uint32_t size = MIN(MAX_SFTP_OUTGOING_SIZE, count); + uint32_t size = + (uint32_t)(LIBSSH2_MIN(MAX_SFTP_OUTGOING_SIZE, count)); uint32_t request_id; /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */ - packet_len = handle->handle_len + size + 25; + packet_len = (uint32_t)(handle->handle_len + size + 25); chunk = LIBSSH2_ALLOC(session, packet_len + sizeof(struct sftp_pipeline_chunk)); @@ -2119,7 +2188,8 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, chunk = _libssh2_list_next(&chunk->node); } - /* fall-through */ + LIBSSH2_FALLTHROUGH(); + case libssh2_NB_state_sent: sftp->write_state = libssh2_NB_state_idle; @@ -2206,7 +2276,7 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, acked += handle->u.file.acked; if(acked) { - ssize_t ret = MIN(acked, org_count); + ssize_t ret = LIBSSH2_MIN(acked, org_count); /* we got data acked so return that amount, but no more than what was asked to get sent! */ @@ -2244,15 +2314,17 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) LIBSSH2_SESSION *session = channel->session; /* 34 = packet_len(4) + packet_type(1) + request_id(4) + string_len(4) + strlen("fsync@openssh.com")(17) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 34; - size_t data_len; - unsigned char *packet, *s, *data; + uint32_t packet_len = (uint32_t)(handle->handle_len + 34); + size_t data_len = 0; + unsigned char *packet, *s, *data = NULL; ssize_t rc; uint32_t retcode; if(sftp->fsync_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Issuing fsync command"); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Issuing fsync command")); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -2295,7 +2367,7 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) rc = sftp_packet_require(sftp, SSH_FXP_STATUS, sftp->fsync_request_id, &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { @@ -2306,7 +2378,7 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) } else if(rc) { sftp->fsync_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for FXP EXTENDED REPLY"); } @@ -2339,9 +2411,7 @@ libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *hnd) } -/* - * sftp_fstat - * +/* sftp_fstat * Get or Set stat on a file */ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, @@ -2350,18 +2420,20 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = - handle->handle_len + 13 + (setstat ? sftp_attrsize(attrs->flags) : 0); - unsigned char *s, *data; + uint32_t packet_len = (uint32_t)(handle->handle_len + 13 + + (setstat ? sftp_attrsize(attrs->flags) : 0)); + unsigned char *s, *data = NULL; static const unsigned char fstat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS }; ssize_t rc; if(sftp->fstat_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Issuing %s command", - setstat ? "set-stat" : "stat"); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Issuing %s command", + setstat ? "set-stat" : "stat")); s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->fstat_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -2386,7 +2458,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, rc = _libssh2_channel_write(channel, 0, sftp->fstat_packet, packet_len); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if((ssize_t)packet_len != rc) { LIBSSH2_FREE(session, sftp->fstat_packet); @@ -2406,7 +2478,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, sftp->fstat_request_id, &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; + return (int)rc; else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { LIBSSH2_FREE(session, data); @@ -2416,7 +2488,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, } else if(rc) { sftp->fstat_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Timeout waiting for status message"); } @@ -2575,14 +2647,16 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 13; + uint32_t packet_len = (uint32_t)(handle->handle_len + 13); unsigned char *s, *data = NULL; int rc = 0; if(handle->close_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Closing handle"); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Closing handle")); s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len); if(!handle->close_packet) { handle->close_state = libssh2_NB_state_idle; @@ -2602,12 +2676,13 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) } if(handle->close_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, handle->close_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, handle->close_packet, + packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((ssize_t)packet_len != rc) { + else if((ssize_t)packet_len != nwritten) { handle->close_state = libssh2_NB_state_idle; rc = _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_CLOSE command"); @@ -2649,7 +2724,7 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) } else { - int retcode = _libssh2_ntohu32(data + 5); + uint32_t retcode = _libssh2_ntohu32(data + 5); LIBSSH2_FREE(session, data); if(retcode != LIBSSH2_FX_OK) { @@ -2705,15 +2780,18 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; + size_t data_len = 0; + uint32_t retcode; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */ - uint32_t packet_len = filename_len + 13; - unsigned char *s, *data; + uint32_t packet_len = (uint32_t)(filename_len + 13); + unsigned char *s, *data = NULL; int rc; if(sftp->unlink_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Unlinking %s", filename); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Unlinking %s", filename)); s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->unlink_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -2730,12 +2808,13 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, } if(sftp->unlink_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->unlink_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, sftp->unlink_packet, + packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((ssize_t)packet_len != rc) { + else if((ssize_t)packet_len != nwritten) { LIBSSH2_FREE(session, sftp->unlink_packet); sftp->unlink_packet = NULL; sftp->unlink_state = libssh2_NB_state_idle; @@ -2797,9 +2876,7 @@ libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, return rc; } -/* - * sftp_rename - * +/* sftp_rename * Rename a file on the remote server */ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, @@ -2809,24 +2886,26 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; int retcode; uint32_t packet_len = - source_filename_len + dest_filename_len + 17 + (sftp->version >= - 5 ? 4 : 0); + source_filename_len + dest_filename_len + 17 + + (sftp->version >= 5 ? 4 : 0); /* packet_len(4) + packet_type(1) + request_id(4) + source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */ - unsigned char *data; + unsigned char *data = NULL; ssize_t rc; - if(sftp->version < 2) { - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Server does not support RENAME"); - } - if(sftp->rename_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Renaming %s to %s", - source_filename, dest_filename); + sftp->last_errno = LIBSSH2_FX_OK; + + if(sftp->version < 2) { + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Server does not support RENAME"); + } + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Renaming %s to %s", + source_filename, dest_filename)); sftp->rename_s = sftp->rename_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->rename_packet) { @@ -2844,7 +2923,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, _libssh2_store_str(&sftp->rename_s, dest_filename, dest_filename_len); if(sftp->version >= 5) - _libssh2_store_u32(&sftp->rename_s, flags); + _libssh2_store_u32(&sftp->rename_s, (uint32_t)flags); sftp->rename_state = libssh2_NB_state_created; } @@ -2853,7 +2932,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, rc = _libssh2_channel_write(channel, 0, sftp->rename_packet, sftp->rename_s - sftp->rename_packet); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if((ssize_t)packet_len != rc) { LIBSSH2_FREE(session, sftp->rename_packet); @@ -2872,7 +2951,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, sftp->rename_request_id, &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { @@ -2883,7 +2962,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, } else if(rc) { sftp->rename_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for FXP STATUS"); } @@ -2939,9 +3018,137 @@ libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, return rc; } -/* - * sftp_fstatvfs - * +static int +sftp_posix_rename(LIBSSH2_SFTP *sftp, const char *source_filename, + size_t source_filename_len, + const char *dest_filename, + size_t dest_filename_len) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + uint32_t packet_len; + size_t data_len = 0; + unsigned char *packet, *s, *data = NULL; + ssize_t rc; + uint32_t retcode; + + if(sftp->posix_rename_version != 1) { + return _libssh2_error(session, LIBSSH2_FX_OP_UNSUPPORTED, + "Server does not support" + "posix-rename@openssh.com"); + } + + if(source_filename_len > UINT32_MAX || + dest_filename_len > UINT32_MAX || + 45 + source_filename_len + dest_filename_len > UINT32_MAX) { + return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Input too large" + "posix-rename@openssh.com"); + } + + packet_len = (uint32_t)(45 + source_filename_len + dest_filename_len); + + /* 45 = packet_len(4) + packet_type(1) + request_id(4) + + string_len(4) + strlen("posix-rename@openssh.com")(24) + + oldpath_len(4) + source_filename_len + + newpath_len(4) + dest_filename_len */ + + if(sftp->posix_rename_state == libssh2_NB_state_idle) { + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Issuing posix_rename command")); + s = packet = LIBSSH2_ALLOC(session, packet_len); + if(!packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_EXTENDED " + "packet"); + } + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_EXTENDED; + sftp->posix_rename_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->posix_rename_request_id); + _libssh2_store_str(&s, "posix-rename@openssh.com", 24); + _libssh2_store_str(&s, source_filename, source_filename_len); + _libssh2_store_str(&s, dest_filename, dest_filename_len); + + sftp->posix_rename_state = libssh2_NB_state_created; + } + else { + packet = sftp->posix_rename_packet; + } + + if(sftp->posix_rename_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, packet, packet_len); + if(rc == LIBSSH2_ERROR_EAGAIN || + (0 <= rc && rc < (ssize_t)packet_len)) { + sftp->posix_rename_packet = packet; + return LIBSSH2_ERROR_EAGAIN; + } + + LIBSSH2_FREE(session, packet); + sftp->posix_rename_packet = NULL; + + if(rc < 0) { + sftp->posix_rename_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "_libssh2_channel_write() failed"); + } + sftp->posix_rename_state = libssh2_NB_state_sent; + } + + rc = sftp_packet_require(sftp, SSH_FXP_STATUS, + sftp->posix_rename_request_id, + &data, &data_len, 9); + if(rc == LIBSSH2_ERROR_EAGAIN) { + return (int)rc; + } + else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { + if(data_len > 0) { + LIBSSH2_FREE(session, data); + } + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP posix_rename packet too short"); + } + else if(rc) { + sftp->posix_rename_state = libssh2_NB_state_idle; + return (int)_libssh2_error(session, (int)rc, + "Error waiting for FXP EXTENDED REPLY"); + } + + sftp->posix_rename_state = libssh2_NB_state_idle; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + + if(retcode != LIBSSH2_FX_OK) { + sftp->last_errno = retcode; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "posix_rename failed"); + } + + return 0; +} + +/* libssh2_sftp_posix_rename_ex + * Rename a file on the remote server using the posix-rename@openssh.com + * extension. + */ +LIBSSH2_API int +libssh2_sftp_posix_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, + size_t source_filename_len, + const char *dest_filename, + size_t dest_filename_len) +{ + int rc; + if(!sftp) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_posix_rename(sftp, source_filename, source_filename_len, + dest_filename, dest_filename_len)); + return rc; +} + +/* sftp_fstatvfs * Get file system statistics */ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) @@ -2949,20 +3156,22 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) + handle_len (4) */ /* 20 = strlen ("fstatvfs@openssh.com") */ - uint32_t packet_len = handle->handle_len + 20 + 17; - unsigned char *packet, *s, *data; + uint32_t packet_len = (uint32_t)(handle->handle_len + 20 + 17); + unsigned char *packet, *s, *data = NULL; ssize_t rc; unsigned int flag; static const unsigned char responses[2] = { SSH_FXP_EXTENDED_REPLY, SSH_FXP_STATUS }; if(sftp->fstatvfs_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Getting file system statistics"); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Getting file system statistics")); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3006,7 +3215,7 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { @@ -3017,12 +3226,12 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) } else if(rc) { sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for FXP EXTENDED REPLY"); } if(data[0] == SSH_FXP_STATUS) { - int retcode = _libssh2_ntohu32(data + 5); + uint32_t retcode = _libssh2_ntohu32(data + 5); sftp->fstatvfs_state = libssh2_NB_state_idle; LIBSSH2_FREE(session, data); sftp->last_errno = retcode; @@ -3075,9 +3284,7 @@ libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) return rc; } -/* - * sftp_statvfs - * +/* sftp_statvfs * Get file system statistics */ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, @@ -3085,20 +3292,22 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) + path_len (4) */ /* 19 = strlen ("statvfs@openssh.com") */ uint32_t packet_len = path_len + 19 + 17; - unsigned char *packet, *s, *data; + unsigned char *packet, *s, *data = NULL; ssize_t rc; unsigned int flag; static const unsigned char responses[2] = { SSH_FXP_EXTENDED_REPLY, SSH_FXP_STATUS }; if(sftp->statvfs_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Getting file system statistics of %s", path); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Getting file system statistics of %s", path)); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3141,7 +3350,7 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, rc = sftp_packet_requirev(sftp, 2, responses, sftp->statvfs_request_id, &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { @@ -3152,12 +3361,12 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, } else if(rc) { sftp->statvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for FXP EXTENDED REPLY"); } if(data[0] == SSH_FXP_STATUS) { - int retcode = _libssh2_ntohu32(data + 5); + uint32_t retcode = _libssh2_ntohu32(data + 5); sftp->statvfs_state = libssh2_NB_state_idle; LIBSSH2_FREE(session, data); sftp->last_errno = retcode; @@ -3206,15 +3415,13 @@ libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, int rc; if(!sftp || !st) return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, sftp_statvfs(sftp, path, path_len, - st)); + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_statvfs(sftp, path, (unsigned int)path_len, st)); return rc; } -/* - * sftp_mkdir - * +/* sftp_mkdir * Create an SFTP directory */ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, @@ -3225,10 +3432,10 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUTES attrs = { 0, 0, 0, 0, 0, 0, 0 }; - size_t data_len; - int retcode; + size_t data_len = 0; + uint32_t retcode; ssize_t packet_len; - unsigned char *packet, *s, *data; + unsigned char *packet, *s, *data = NULL; int rc; if(mode != LIBSSH2_SFTP_DEFAULT_MODE) { @@ -3241,8 +3448,10 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, packet_len = path_len + 13 + sftp_attrsize(attrs.flags); if(sftp->mkdir_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Creating directory %s with mode 0%lo", path, mode); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Creating directory %s with mode 0%lo", path, mode)); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3250,7 +3459,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, "packet"); } - _libssh2_store_u32(&s, packet_len - 4); + _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); *(s++) = SSH_FXP_MKDIR; sftp->mkdir_request_id = sftp->request_id++; _libssh2_store_u32(&s, sftp->mkdir_request_id); @@ -3265,12 +3474,13 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, } if(sftp->mkdir_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, packet, packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { sftp->mkdir_packet = packet; - return rc; + return (int)nwritten; } - if(packet_len != rc) { + if(packet_len != nwritten) { LIBSSH2_FREE(session, packet); sftp->mkdir_state = libssh2_NB_state_idle; return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, @@ -3305,7 +3515,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_FREE(session, data); if(retcode == LIBSSH2_FX_OK) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "OK!"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "OK")); return 0; } else { @@ -3315,9 +3525,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, } } -/* - * libssh2_sftp_mkdir_ex - * +/* libssh2_sftp_mkdir_ex * Create an SFTP directory */ LIBSSH2_API int @@ -3340,16 +3548,18 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; + size_t data_len = 0; + uint32_t retcode; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ ssize_t packet_len = path_len + 13; - unsigned char *s, *data; + unsigned char *s, *data = NULL; int rc; if(sftp->rmdir_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Removing directory: %s", - path); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Removing directory: %s", + path)); s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->rmdir_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3357,7 +3567,7 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, "packet"); } - _libssh2_store_u32(&s, packet_len - 4); + _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); *(s++) = SSH_FXP_RMDIR; sftp->rmdir_request_id = sftp->request_id++; _libssh2_store_u32(&s, sftp->rmdir_request_id); @@ -3367,12 +3577,13 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, } if(sftp->rmdir_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->rmdir_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, sftp->rmdir_packet, + packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if(packet_len != rc) { + else if(packet_len != nwritten) { LIBSSH2_FREE(session, sftp->rmdir_packet); sftp->rmdir_packet = NULL; sftp->rmdir_state = libssh2_NB_state_idle; @@ -3442,22 +3653,24 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ ssize_t packet_len = path_len + 13 + ((stat_type == LIBSSH2_SFTP_SETSTAT) ? sftp_attrsize(attrs->flags) : 0); - unsigned char *s, *data; + unsigned char *s, *data = NULL; static const unsigned char stat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS }; int rc; if(sftp->stat_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s", + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "%s %s", (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : (stat_type == - LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path); + LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path)); s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->stat_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3465,7 +3678,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, "packet"); } - _libssh2_store_u32(&s, packet_len - 4); + _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); switch(stat_type) { case LIBSSH2_SFTP_SETSTAT: @@ -3491,11 +3704,13 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, } if(sftp->stat_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->stat_packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, + sftp->stat_packet, packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if(packet_len != rc) { + else if(packet_len != nwritten) { LIBSSH2_FREE(session, sftp->stat_packet); sftp->stat_packet = NULL; sftp->stat_state = libssh2_NB_state_idle; @@ -3528,7 +3743,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, sftp->stat_state = libssh2_NB_state_idle; if(data[0] == SSH_FXP_STATUS) { - int retcode; + uint32_t retcode; retcode = _libssh2_ntohu32(data + 5); LIBSSH2_FREE(session, data); @@ -3580,22 +3795,25 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len, link_len; + size_t data_len = 0, link_len; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ ssize_t packet_len = path_len + 13 + ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0); - unsigned char *s, *data; + unsigned char *s, *data = NULL; static const unsigned char link_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS }; int retcode; - if((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) { - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Server does not support SYMLINK or READLINK"); - } - if(sftp->symlink_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + + if((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) { + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Server does not support SYMLINK or" + " READLINK"); + } + s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->symlink_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3603,13 +3821,14 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, "SYMLINK/READLINK/REALPATH packet"); } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s on %s", + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "%s %s on %s", (link_type == LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading", (link_type == - LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path); + LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", + path)); - _libssh2_store_u32(&s, packet_len - 4); + _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); switch(link_type) { case LIBSSH2_SFTP_REALPATH: @@ -3638,7 +3857,7 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, ssize_t rc = _libssh2_channel_write(channel, 0, sftp->symlink_packet, packet_len); if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; + return (int)rc; else if(packet_len != rc) { LIBSSH2_FREE(session, sftp->symlink_packet); sftp->symlink_packet = NULL; diff --git a/uppsrc/Core/SSH/libssh2/sftp.h b/uppsrc/Core/SSH/libssh2/sftp.h index 129b8f085..264f823bc 100644 --- a/uppsrc/Core/SSH/libssh2/sftp.h +++ b/uppsrc/Core/SSH/libssh2/sftp.h @@ -1,8 +1,8 @@ -#ifndef __LIBSSH2_SFTP_H -#define __LIBSSH2_SFTP_H +#ifndef LIBSSH2_SFTP_PRIV_H +#define LIBSSH2_SFTP_PRIV_H /* - * Copyright (C) 2010 - 2012 by Daniel Stenberg - * Author: Daniel Stenberg + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -37,6 +37,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ /* @@ -67,10 +68,6 @@ struct sftp_zombie_requests { uint32_t request_id; }; -#ifndef MIN -#define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - struct _LIBSSH2_SFTP_PACKET { struct list_node node; /* linked list header */ @@ -81,7 +78,8 @@ struct _LIBSSH2_SFTP_PACKET typedef struct _LIBSSH2_SFTP_PACKET LIBSSH2_SFTP_PACKET; -#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */ +/* Increasing from 256 to 4092 since OpenSSH doesn't honor it. */ +#define SFTP_HANDLE_MAXLEN 4092 /* according to spec, this should be 256! */ struct _LIBSSH2_SFTP_HANDLE { @@ -140,7 +138,7 @@ struct _LIBSSH2_SFTP { LIBSSH2_CHANNEL *channel; - uint32_t request_id, version; + uint32_t request_id, version, posix_rename_version; struct list_head packets; @@ -153,9 +151,10 @@ struct _LIBSSH2_SFTP uint32_t last_errno; /* Holder for partial packet, use in libssh2_sftp_packet_read() */ - unsigned char partial_size[4]; /* buffer for size field */ - size_t partial_size_len; /* size field length */ - unsigned char *partial_packet; /* The data */ + unsigned char packet_header[9]; + /* packet size (4) packet type (1) request id (4) */ + size_t packet_header_len; /* packet_header length */ + unsigned char *partial_packet; /* The data, with header */ uint32_t partial_len; /* Desired number of bytes */ size_t partial_received; /* Bytes received so far */ @@ -204,6 +203,11 @@ struct _LIBSSH2_SFTP unsigned char *rename_s; uint32_t rename_request_id; + /* State variables used in libssh2_sftp_posix_rename_ex() */ + libssh2_nonblocking_states posix_rename_state; + unsigned char *posix_rename_packet; + uint32_t posix_rename_request_id; + /* State variables used in libssh2_sftp_fstatvfs() */ libssh2_nonblocking_states fstatvfs_state; unsigned char *fstatvfs_packet; @@ -235,4 +239,4 @@ struct _LIBSSH2_SFTP uint32_t symlink_request_id; }; -#endif /* __LIBSSH2_SFTP_H */ +#endif /* LIBSSH2_SFTP_PRIV_H */ diff --git a/uppsrc/Core/SSH/libssh2/transport.c b/uppsrc/Core/SSH/libssh2/transport.c index 17af3e4da..e1120656c 100644 --- a/uppsrc/Core/SSH/libssh2/transport.c +++ b/uppsrc/Core/SSH/libssh2/transport.c @@ -1,6 +1,6 @@ -/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009-2010 by Daniel Stenberg - * Author: Daniel Stenberg +/* Copyright (C) The Written Word, Inc. + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -35,25 +35,22 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* * This file handles reading and writing to the SECSH transport layer. RFC4253. */ #include "libssh2_priv.h" -#include -#include -#include -#ifdef LIBSSH2DEBUG -#include -#endif +#include +#include #include #include "transport.h" #include "mac.h" -#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */ -#define MAX_MACSIZE 64 /* MUST fit biggest MAC length we support */ - #ifdef LIBSSH2DEBUG #define UNPRINTABLE_CHAR '.' static void @@ -72,8 +69,8 @@ debugdump(LIBSSH2_SESSION * session, return; } - used = snprintf(buffer, sizeof(buffer), "=> %s (%d bytes)\n", - desc, (int) size); + used = snprintf(buffer, sizeof(buffer), "=> %s (%lu bytes)\n", + desc, (unsigned long) size); if(session->tracehandler) (session->tracehandler)(session, session->tracehandler_context, buffer, used); @@ -118,29 +115,50 @@ debugdump(LIBSSH2_SESSION * session, } } #else -#define debugdump(a,x,y,z) +#define debugdump(a,x,y,z) do {} while(0) #endif -/* decrypt() decrypts 'len' bytes from 'source' to 'dest'. +/* decrypt() decrypts 'len' bytes from 'source' to 'dest' in units of + * blocksize. * * returns 0 on success and negative on failure */ static int decrypt(LIBSSH2_SESSION * session, unsigned char *source, - unsigned char *dest, int len) + unsigned char *dest, ssize_t len, int firstlast) { struct transportpacket *p = &session->packet; int blocksize = session->remote.crypt->blocksize; /* if we get called with a len that isn't an even number of blocksizes - we risk losing those extra bytes */ - assert((len % blocksize) == 0); + we risk losing those extra bytes. AAD is an exception, since those first + few bytes aren't encrypted so it throws off the rest of the count. */ + if(!CRYPT_FLAG_L(session, PKTLEN_AAD)) + assert((len % blocksize) == 0); - while(len >= blocksize) { - if(session->remote.crypt->crypt(session, source, blocksize, - &session->remote.crypt_abstract)) { + while(len > 0) { + /* normally decrypt up to blocksize bytes at a time */ + ssize_t decryptlen = LIBSSH2_MIN(blocksize, len); + /* The first block is special (since it needs to be decoded to get the + length of the remainder of the block) and takes priority. When the + length finally gets to the last blocksize bytes, and there's no + more data to come, it's the end. */ + int lowerfirstlast = IS_FIRST(firstlast) ? FIRST_BLOCK : + ((len <= blocksize) ? firstlast : MIDDLE_BLOCK); + /* If the last block would be less than a whole blocksize, combine it + with the previous block to make it larger. This ensures that the + whole MAC is included in a single decrypt call. */ + if(CRYPT_FLAG_L(session, PKTLEN_AAD) && IS_LAST(firstlast) + && (len < blocksize*2)) { + decryptlen = len; + lowerfirstlast = LAST_BLOCK; + } + + if(session->remote.crypt->crypt(session, 0, source, decryptlen, + &session->remote.crypt_abstract, + lowerfirstlast)) { LIBSSH2_FREE(session, p->payload); return LIBSSH2_ERROR_DECRYPT; } @@ -148,11 +166,11 @@ decrypt(LIBSSH2_SESSION * session, unsigned char *source, /* if the crypt() function would write to a given address it wouldn't have to memcpy() and we could avoid this memcpy() too */ - memcpy(dest, source, blocksize); + memcpy(dest, source, decryptlen); - len -= blocksize; /* less bytes left */ - dest += blocksize; /* advance write pointer */ - source += blocksize; /* advance read pointer */ + len -= decryptlen; /* less bytes left */ + dest += decryptlen; /* advance write pointer */ + source += decryptlen; /* advance read pointer */ } return LIBSSH2_ERROR_NONE; /* all is fine */ } @@ -168,30 +186,101 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) struct transportpacket *p = &session->packet; int rc; int compressed; + const LIBSSH2_MAC_METHOD *remote_mac = NULL; + uint32_t seq = session->remote.seqno; + + if(!encrypted || (!CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) && + !CRYPT_FLAG_R(session, INTEGRATED_MAC))) { + remote_mac = session->remote.mac; + } if(session->fullpacket_state == libssh2_NB_state_idle) { session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED; session->fullpacket_payload_len = p->packet_length - 1; - if(encrypted) { + if(encrypted && remote_mac) { /* Calculate MAC hash */ - session->remote.mac->hash(session, macbuf, /* store hash here */ - session->remote.seqno, - p->init, 5, - p->payload, - session->fullpacket_payload_len, - &session->remote.mac_abstract); + int etm = remote_mac->etm; + size_t mac_len = remote_mac->mac_len; + if(etm) { + /* store hash here */ + remote_mac->hash(session, macbuf, + session->remote.seqno, + p->payload, p->total_num - mac_len, + NULL, 0, + &session->remote.mac_abstract); + } + else { + /* store hash here */ + remote_mac->hash(session, macbuf, + session->remote.seqno, + p->init, 5, + p->payload, + session->fullpacket_payload_len, + &session->remote.mac_abstract); + } /* Compare the calculated hash with the MAC we just read from * the network. The read one is at the very end of the payload * buffer. Note that 'payload_len' here is the packet_length * field which includes the padding but not the MAC. */ - if(memcmp(macbuf, p->payload + session->fullpacket_payload_len, - session->remote.mac->mac_len)) { + if(memcmp(macbuf, p->payload + p->total_num - mac_len, mac_len)) { + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Failed MAC check")); session->fullpacket_macstate = LIBSSH2_MAC_INVALID; + } + else if(etm) { + /* MAC was ok and we start by decrypting the first block that + contains padding length since this allows us to decrypt + all other blocks to the right location in memory + avoiding moving a larger block of memory one byte. */ + unsigned char first_block[MAX_BLOCKSIZE]; + ssize_t decrypt_size; + unsigned char *decrypt_buffer; + int blocksize = session->remote.crypt->blocksize; + + rc = decrypt(session, p->payload + 4, + first_block, blocksize, FIRST_BLOCK); + if(rc) { + return rc; + } + + /* we need buffer for decrypt */ + decrypt_size = p->total_num - mac_len - 4; + decrypt_buffer = LIBSSH2_ALLOC(session, decrypt_size); + if(!decrypt_buffer) { + return LIBSSH2_ERROR_ALLOC; + } + + /* grab padding length and copy anything else + into target buffer */ + p->padding_length = first_block[0]; + if(blocksize > 1) { + memcpy(decrypt_buffer, first_block + 1, blocksize - 1); + } + + /* decrypt all other blocks packet */ + if(blocksize < decrypt_size) { + rc = decrypt(session, p->payload + blocksize + 4, + decrypt_buffer + blocksize - 1, + decrypt_size - blocksize, LAST_BLOCK); + if(rc) { + LIBSSH2_FREE(session, decrypt_buffer); + return rc; + } + } + + /* replace encrypted payload with plain text payload */ + LIBSSH2_FREE(session, p->payload); + p->payload = decrypt_buffer; + } + } + else if(encrypted && CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) { + /* etm trim off padding byte from payload */ + memmove(p->payload, &p->payload[1], p->packet_length - 1); } session->remote.seqno++; @@ -200,11 +289,10 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) session->fullpacket_payload_len -= p->padding_length; /* Check for and deal with decompression */ - compressed = - session->local.comp != NULL && - session->local.comp->compress && - ((session->state & LIBSSH2_STATE_AUTHENTICATED) || - session->local.comp->use_in_auth); + compressed = session->local.comp && + session->local.comp->compress && + ((session->state & LIBSSH2_STATE_AUTHENTICATED) || + session->local.comp->use_in_auth); if(compressed && session->remote.comp_abstract) { /* @@ -240,7 +328,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) if(session->fullpacket_state == libssh2_NB_state_created) { rc = _libssh2_packet_add(session, p->payload, session->fullpacket_payload_len, - session->fullpacket_macstate); + session->fullpacket_macstate, seq); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; if(rc) { @@ -251,6 +339,11 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) session->fullpacket_state = libssh2_NB_state_idle; + if(session->kex_strict && + session->fullpacket_packet_type == SSH_MSG_NEWKEYS) { + session->remote.seqno = 0; + } + return session->fullpacket_packet_type; } @@ -274,13 +367,21 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) { int rc; struct transportpacket *p = &session->packet; - int remainbuf; - int remainpack; - int numbytes; - int numdecrypt; - unsigned char block[MAX_BLOCKSIZE]; - int blocksize; - int encrypted = 1; + ssize_t remainpack; /* how much there is left to add to the current payload + package */ + ssize_t remainbuf; /* how much data there is remaining in the buffer to + deal with before we should read more from the + network */ + ssize_t numbytes; /* how much data to deal with from the buffer on this + iteration through the loop */ + ssize_t numdecrypt; /* number of bytes to decrypt this iteration */ + unsigned char block[MAX_BLOCKSIZE]; /* working block buffer */ + int blocksize; /* minimum number of bytes we need before we can + use them */ + int encrypted = 1; /* whether the packet is encrypted or not */ + int firstlast = FIRST_BLOCK; /* if the first or last block to decrypt */ + unsigned int auth_len = 0; /* length of the authentication tag */ + const LIBSSH2_MAC_METHOD *remote_mac = NULL; /* The remote MAC, if used */ /* default clear the bit */ session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; @@ -303,8 +404,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) /* Whoever wants a packet won't get anything until the key re-exchange * is done! */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" - " key re-exchange from _libssh2_transport_read"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Redirecting into the" + " key re-exchange from _libssh2_transport_read")); rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); if(rc) return rc; @@ -322,6 +423,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) } do { + int etm; if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) { return LIBSSH2_ERROR_SOCKET_DISCONNECT; } @@ -335,6 +437,17 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) make the checks below work fine still */ } + if(encrypted) { + if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) { + auth_len = session->remote.crypt->auth_len; + } + else { + remote_mac = session->remote.mac; + } + } + + etm = encrypted && remote_mac ? remote_mac->etm : 0; + /* read/use a whole big chunk into a temporary area stored in the LIBSSH2_SESSION struct. We will decrypt data from that buffer into the packet buffer so this temp one doesn't have @@ -348,7 +461,9 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) /* if remainbuf turns negative we have a bad internal error */ assert(remainbuf >= 0); - if(remainbuf < blocksize) { + if(remainbuf < blocksize || + (CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET) + && ((ssize_t)p->total_num) > remainbuf)) { /* If we have less than a blocksize left, it is too little data to deal with, read more */ ssize_t nread; @@ -366,10 +481,9 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) } /* now read a big chunk from the network into the temp buffer */ - nread = - LIBSSH2_RECV(session, &p->buf[remainbuf], - PACKETBUFSIZE - remainbuf, - LIBSSH2_SOCKET_RECV_FLAGS(session)); + nread = LIBSSH2_RECV(session, &p->buf[remainbuf], + PACKETBUFSIZE - remainbuf, + LIBSSH2_SOCKET_RECV_FLAGS(session)); if(nread <= 0) { /* check if this is due to EAGAIN and return the special return code if so, error out normally otherwise */ @@ -378,14 +492,16 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) LIBSSH2_SESSION_BLOCK_INBOUND; return LIBSSH2_ERROR_EAGAIN; } - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error recving %d bytes (got %d)", - PACKETBUFSIZE - remainbuf, -nread); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Error recving %ld bytes (got %ld)", + (long)(PACKETBUFSIZE - remainbuf), + (long)-nread)); return LIBSSH2_ERROR_SOCKET_RECV; } - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Recved %d/%d bytes to %p+%d", nread, - PACKETBUFSIZE - remainbuf, p->buf, remainbuf); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Recved %ld/%ld bytes to %p+%ld", (long)nread, + (long)(PACKETBUFSIZE - remainbuf), (void *)p->buf, + (long)remainbuf)); debugdump(session, "libssh2_transport_read() raw", &p->buf[remainbuf], nread); @@ -400,13 +516,19 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) numbytes = remainbuf; if(!p->total_num) { - size_t total_num; + size_t total_num; /* the number of bytes following the initial + (5 bytes) packet length and padding length + fields */ + + /* packet length is not encrypted in encode-then-mac mode + and we donøt need to decrypt first block */ + ssize_t required_size = etm ? 4 : blocksize; /* No payload package area allocated yet. To know the - size of this payload, we need to decrypt the first + size of this payload, we need enough to decrypt the first blocksize data. */ - if(numbytes < blocksize) { + if(numbytes < required_size) { /* we can't act on anything less than blocksize, but this check is only done for the initial block since once we have got the start of a block we can in fact deal with fractions @@ -416,47 +538,122 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) return LIBSSH2_ERROR_EAGAIN; } - if(encrypted) { - rc = decrypt(session, &p->buf[p->readidx], block, blocksize); + if(etm) { + /* etm size field is not encrypted */ + memcpy(block, &p->buf[p->readidx], 4); + memcpy(p->init, &p->buf[p->readidx], 4); + } + else if(encrypted && session->remote.crypt->get_len) { + unsigned int len = 0; + unsigned char *ptr = NULL; + + rc = session->remote.crypt->get_len(session, + session->remote.seqno, + &p->buf[p->readidx], + numbytes, + &len, + &session->remote.crypt_abstract); + if(rc != LIBSSH2_ERROR_NONE) { + p->total_num = 0; /* no packet buffer available */ + if(p->payload) + LIBSSH2_FREE(session, p->payload); + p->payload = NULL; return rc; } - /* save the first 5 bytes of the decrypted package, to be - used in the hash calculation later down. */ - memcpy(p->init, block, 5); + + /* store size in buffers for use below */ + ptr = &block[0]; + _libssh2_store_u32(&ptr, len); + + ptr = &p->init[0]; + _libssh2_store_u32(&ptr, len); } else { - /* the data is plain, just copy it verbatim to - the working block buffer */ - memcpy(block, &p->buf[p->readidx], blocksize); + if(encrypted) { + /* first decrypted block */ + rc = decrypt(session, &p->buf[p->readidx], + block, blocksize, FIRST_BLOCK); + if(rc != LIBSSH2_ERROR_NONE) { + return rc; + } + /* Save the first 5 bytes of the decrypted package, to be + used in the hash calculation later down. + This is ignored in the INTEGRATED_MAC case. */ + memcpy(p->init, block, 5); + } + else { + /* the data is plain, just copy it verbatim to + the working block buffer */ + memcpy(block, &p->buf[p->readidx], blocksize); + } + + /* advance the read pointer */ + p->readidx += blocksize; + + /* we now have the initial blocksize bytes decrypted, + * and we can extract packet and padding length from it + */ + p->packet_length = _libssh2_ntohu32(block); } - /* advance the read pointer */ - p->readidx += blocksize; + if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) { + if(p->packet_length < 1) { + return LIBSSH2_ERROR_DECRYPT; + } + else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) { + return LIBSSH2_ERROR_OUT_OF_BOUNDARY; + } - /* we now have the initial blocksize bytes decrypted, - * and we can extract packet and padding length from it - */ - p->packet_length = _libssh2_ntohu32(block); - if(p->packet_length < 1) { - return LIBSSH2_ERROR_DECRYPT; + if(etm) { + /* we collect entire undecrypted packet including the + packet length field that we run MAC over */ + p->packet_length = _libssh2_ntohu32(block); + total_num = 4 + p->packet_length + + remote_mac->mac_len; + } + else { + /* padding_length has not been authenticated yet, but it + won't actually be used (except for the sanity check + immediately following) until after the entire packet is + authenticated, so this is safe. */ + p->padding_length = block[4]; + if(p->padding_length > p->packet_length - 1) { + return LIBSSH2_ERROR_DECRYPT; + } + + /* total_num is the number of bytes following the initial + (5 bytes) packet length and padding length fields */ + total_num = p->packet_length - 1 + + (encrypted ? remote_mac->mac_len : 0); + } } - else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) { - return LIBSSH2_ERROR_OUT_OF_BOUNDARY; + else { + /* advance the read pointer past size field if the packet + length is not required for decryption */ + + /* add size field to be included in total packet size + * calculation so it doesn't get dropped off on subsequent + * partial reads + */ + total_num = 4; + + p->packet_length = _libssh2_ntohu32(block); + if(p->packet_length < 1) + return LIBSSH2_ERROR_DECRYPT; + + /* total_num may include size field, however due to existing + * logic it needs to be removed after the entire packet is read + */ + + total_num += p->packet_length + + (remote_mac ? remote_mac->mac_len : 0) + auth_len; + + /* don't know what padding is until we decrypt the full + packet */ + p->padding_length = 0; } - p->padding_length = block[4]; - if(p->padding_length > p->packet_length - 1) { - return LIBSSH2_ERROR_DECRYPT; - } - - - /* total_num is the number of bytes following the initial - (5 bytes) packet length and padding length fields */ - total_num = - p->packet_length - 1 + - (encrypted ? session->remote.mac->mac_len : 0); - /* RFC4253 section 6.1 Maximum Packet Length says: * * "All implementations MUST be able to process @@ -479,27 +676,42 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) /* init write pointer to start of payload buffer */ p->wptr = p->payload; - if(blocksize > 5) { - /* copy the data from index 5 to the end of - the blocksize from the temporary buffer to - the start of the decrypted buffer */ - if(blocksize - 5 <= (int) total_num) { - memcpy(p->wptr, &block[5], blocksize - 5); - p->wptr += blocksize - 5; /* advance write pointer */ - } - else { - if(p->payload) - LIBSSH2_FREE(session, p->payload); - return LIBSSH2_ERROR_OUT_OF_BOUNDARY; + if(!encrypted || !CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) { + if(!etm && blocksize > 5) { + /* copy the data from index 5 to the end of + the blocksize from the temporary buffer to + the start of the decrypted buffer */ + if(blocksize - 5 <= (int) total_num) { + memcpy(p->wptr, &block[5], blocksize - 5); + p->wptr += blocksize - 5; /* advance write pointer */ + if(etm) { + /* advance past unencrypted packet length */ + p->wptr += 4; + } + } + else { + if(p->payload) + LIBSSH2_FREE(session, p->payload); + return LIBSSH2_ERROR_OUT_OF_BOUNDARY; + } } + + /* init the data_num field to the number of bytes of + the package read so far */ + p->data_num = p->wptr - p->payload; + + /* we already dealt with a blocksize worth of data */ + if(!etm) + numbytes -= blocksize; } + else { + /* haven't started reading payload yet */ + p->data_num = 0; - /* init the data_num field to the number of bytes of - the package read so far */ - p->data_num = p->wptr - p->payload; - - /* we already dealt with a blocksize worth of data */ - numbytes -= blocksize; + /* we already dealt with packet size worth of data */ + if(!encrypted) + numbytes -= 4; + } } /* how much there is left to add to the current payload @@ -512,45 +724,110 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) numbytes = remainpack; } - if(encrypted) { + if(encrypted && CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) { + if(numbytes < remainpack) { + /* need a full packet before checking MAC */ + session->socket_block_directions |= + LIBSSH2_SESSION_BLOCK_INBOUND; + return LIBSSH2_ERROR_EAGAIN; + } + + /* we have a full packet, now remove the size field from numbytes + and total_num to process only the packet data */ + numbytes -= 4; + p->total_num -= 4; + } + + if(encrypted && !etm) { /* At the end of the incoming stream, there is a MAC, and we don't want to decrypt that since we need it "raw". We MUST however decrypt the padding data since it is used for the hash later on. */ - int skip = session->remote.mac->mac_len; + int skip = (remote_mac ? remote_mac->mac_len : 0) + auth_len; + + if(CRYPT_FLAG_R(session, INTEGRATED_MAC)) + /* This crypto method DOES need the MAC to go through + decryption so it can be authenticated. */ + skip = 0; /* if what we have plus numbytes is bigger than the total minus the skip margin, we should lower the amount to decrypt even more */ - if((p->data_num + numbytes) > (p->total_num - skip)) { - numdecrypt = (p->total_num - skip) - p->data_num; + if((p->data_num + numbytes) >= (p->total_num - skip)) { + /* decrypt the entire rest of the package */ + numdecrypt = LIBSSH2_MAX(0, + (int)(p->total_num - skip) - (int)p->data_num); + firstlast = LAST_BLOCK; } else { - int frac; + ssize_t frac; numdecrypt = numbytes; frac = numdecrypt % blocksize; if(frac) { - /* not an aligned amount of blocks, - align it */ + /* not an aligned amount of blocks, align it by reducing + the number of bytes processed this loop */ numdecrypt -= frac; /* and make it no unencrypted data after it */ numbytes = 0; } + if(CRYPT_FLAG_R(session, INTEGRATED_MAC)) { + /* Make sure that we save enough bytes to make the last + * block large enough to hold the entire integrated MAC */ + numdecrypt = LIBSSH2_MIN(numdecrypt, + (int)(p->total_num - skip - blocksize - p->data_num)); + numbytes = 0; + } + firstlast = MIDDLE_BLOCK; } } else { /* unencrypted data should not be decrypted at all */ numdecrypt = 0; } + assert(numdecrypt >= 0); /* if there are bytes to decrypt, do that */ if(numdecrypt > 0) { /* now decrypt the lot */ - rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt); - if(rc != LIBSSH2_ERROR_NONE) { - p->total_num = 0; /* no packet buffer available */ - return rc; + if(CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) { + rc = session->remote.crypt->crypt(session, + session->remote.seqno, + &p->buf[p->readidx], + numdecrypt, + &session->remote.crypt_abstract, + 0); + + if(rc != LIBSSH2_ERROR_NONE) { + p->total_num = 0; /* no packet buffer available */ + return rc; + } + + memcpy(p->wptr, &p->buf[p->readidx], numbytes); + + /* advance read index past size field now that we've decrypted + full packet */ + p->readidx += 4; + + /* include auth tag in bytes decrypted */ + numdecrypt += auth_len; + + /* set padding now that the packet has been verified and + decrypted */ + p->padding_length = p->wptr[0]; + + if(p->padding_length > p->packet_length - 1) { + return LIBSSH2_ERROR_DECRYPT; + } + } + else { + rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt, + firstlast); + + if(rc != LIBSSH2_ERROR_NONE) { + p->total_num = 0; /* no packet buffer available */ + return rc; + } } /* advance the read pointer */ @@ -564,11 +841,11 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) numbytes -= numdecrypt; } - /* if there are bytes to copy that aren't decrypted, simply + /* if there are bytes to copy that aren't decrypted, copy them as-is to the target buffer */ if(numbytes > 0) { - if(numbytes <= (int)(p->total_num - (p->wptr - p->payload))) { + if((size_t)numbytes <= (p->total_num - (p->wptr - p->payload))) { memcpy(p->wptr, &p->buf[p->readidx], numbytes); } else { @@ -591,13 +868,13 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) if(!remainpack) { /* we have a full packet */ - libssh2_transport_read_point1: +libssh2_transport_read_point1: rc = fullpacket(session, encrypted); if(rc == LIBSSH2_ERROR_EAGAIN) { if(session->packAdd_state != libssh2_NB_state_idle) { /* fullpacket only returns LIBSSH2_ERROR_EAGAIN if - * libssh2_packet_add returns LIBSSH2_ERROR_EAGAIN. If + * libssh2_packet_add() returns LIBSSH2_ERROR_EAGAIN. If * that returns LIBSSH2_ERROR_EAGAIN but the packAdd_state * is idle, then the packet has been added to the brigade, * but some immediate action that was taken based on the @@ -641,7 +918,9 @@ send_existing(LIBSSH2_SESSION *session, const unsigned char *data, we don't add this one up until the previous one has been sent. To make the caller really notice his/hers flaw, we return error for this case */ - return LIBSSH2_ERROR_BAD_USE; + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Address is different, returning EAGAIN")); + return LIBSSH2_ERROR_EAGAIN; } *ret = 1; /* set to make our parent return */ @@ -650,14 +929,15 @@ send_existing(LIBSSH2_SESSION *session, const unsigned char *data, length = p->ototal_num - p->osent; rc = LIBSSH2_SEND(session, &p->outbuf[p->osent], length, - LIBSSH2_SOCKET_SEND_FLAGS(session)); + LIBSSH2_SOCKET_SEND_FLAGS(session)); if(rc < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", length, -rc); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Error sending %ld bytes: %ld", + (long)length, (long)-rc)); else { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Sent %d/%d bytes at %p+%d", rc, length, p->outbuf, - p->osent); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Sent %ld/%ld bytes at %p+%lu", (long)rc, (long)length, + (void *)p->outbuf, (unsigned long)p->osent)); debugdump(session, "libssh2_transport_write send()", &p->outbuf[p->osent], rc); } @@ -712,20 +992,24 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, int blocksize = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8; - int padding_length; + ssize_t padding_length; size_t packet_length; - int total_length; -#ifdef RANDOM_PADDING + ssize_t total_length; +#ifdef LIBSSH2_RANDOM_PADDING int rand_max; int seed = data[0]; /* FIXME: make this random */ #endif struct transportpacket *p = &session->packet; int encrypted; int compressed; + int etm; ssize_t ret; int rc; const unsigned char *orgdata = data; + const LIBSSH2_MAC_METHOD *local_mac = NULL; + unsigned int auth_len = 0; size_t orgdata_len = data_len; + size_t crypt_offset, etm_crypt_offset; /* * If the last read operation was interrupted in the middle of a key @@ -738,8 +1022,8 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) { /* Don't write any new packets if we're still in the middle of a key * exchange. */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" - " key re-exchange from _libssh2_transport_send"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Redirecting into the" + " key re-exchange from _libssh2_transport_send")); rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); if(rc) return rc; @@ -750,7 +1034,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, debugdump(session, "libssh2_transport_write plain2", data2, data2_len); /* FIRST, check if we have a pending write to complete. send_existing - only sanity-check data and data_len and not data2 and data2_len!! */ + only sanity-check data and data_len and not data2 and data2_len! */ rc = send_existing(session, data, data_len, &ret); if(rc) return rc; @@ -763,11 +1047,20 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0; - compressed = - session->local.comp != NULL && - session->local.comp->compress && - ((session->state & LIBSSH2_STATE_AUTHENTICATED) || - session->local.comp->use_in_auth); + if(encrypted && session->local.crypt && + CRYPT_FLAG_R(session, REQUIRES_FULL_PACKET)) { + auth_len = session->local.crypt->auth_len; + } + else { + local_mac = session->local.mac; + } + + etm = encrypted && local_mac ? local_mac->etm : 0; + + compressed = session->local.comp && + session->local.comp->compress && + ((session->state & LIBSSH2_STATE_AUTHENTICATED) || + session->local.comp->use_in_auth); if(encrypted && compressed && session->local.comp_abstract) { /* the idea here is that these function must fail if the output gets @@ -825,12 +1118,18 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, packet_length = data_len + 1 + 4; /* 1 is for padding_length field 4 for the packet_length field */ + /* subtract 4 bytes of the packet_length field when padding AES-GCM + or with ETM */ + crypt_offset = (etm || auth_len || + (encrypted && CRYPT_FLAG_R(session, PKTLEN_AAD))) + ? 4 : 0; + etm_crypt_offset = etm ? 4 : 0; /* at this point we have it all except the padding */ /* first figure out our minimum padding amount to make it an even block size */ - padding_length = blocksize - (packet_length % blocksize); + padding_length = blocksize - ((packet_length - crypt_offset) % blocksize); /* if the padding becomes too small we add another blocksize worth of it (taken from the original libssh2 where it didn't have any @@ -838,7 +1137,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, if(padding_length < 4) { padding_length += blocksize; } -#ifdef RANDOM_PADDING +#ifdef LIBSSH2_RANDOM_PADDING /* FIXME: we can add padding here, but that also makes the packets bigger etc */ @@ -853,11 +1152,13 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, /* append the MAC length to the total_length size */ total_length = - packet_length + (encrypted ? session->local.mac->mac_len : 0); + packet_length + (encrypted && local_mac ? local_mac->mac_len : 0); + + total_length += auth_len; /* store packet_length, which is the size of the whole packet except the MAC and the packet_length field itself */ - _libssh2_htonu32(p->outbuf, packet_length - 4); + _libssh2_htonu32(p->outbuf, (uint32_t)(packet_length - 4)); /* store padding_length */ p->outbuf[4] = (unsigned char)padding_length; @@ -873,33 +1174,114 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, /* Calculate MAC hash. Put the output at index packet_length, since that size includes the whole packet. The MAC is calculated on the entire unencrypted packet, including all - fields except the MAC field itself. */ - session->local.mac->hash(session, p->outbuf + packet_length, - session->local.seqno, p->outbuf, - packet_length, NULL, 0, - &session->local.mac_abstract); + fields except the MAC field itself. This is skipped in the + INTEGRATED_MAC case, where the crypto algorithm also does its + own hash. */ + if(!etm && local_mac && !CRYPT_FLAG_L(session, INTEGRATED_MAC)) { + if(local_mac->hash(session, p->outbuf + packet_length, + session->local.seqno, p->outbuf, + packet_length, NULL, 0, + &session->local.mac_abstract)) + return _libssh2_error(session, LIBSSH2_ERROR_MAC_FAILURE, + "Failed to calculate MAC"); + } - /* Encrypt the whole packet data, one block size at a time. - The MAC field is not encrypted. */ - for(i = 0; i < packet_length; i += session->local.crypt->blocksize) { - unsigned char *ptr = &p->outbuf[i]; - if(session->local.crypt->crypt(session, ptr, - session->local.crypt->blocksize, - &session->local.crypt_abstract)) - return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */ + if(CRYPT_FLAG_L(session, REQUIRES_FULL_PACKET)) { + if(session->local.crypt->crypt(session, + session->local.seqno, + p->outbuf, + packet_length, + &session->local.crypt_abstract, + 0)) { + return LIBSSH2_ERROR_ENCRYPT; + } + } + else { + /* Encrypt the whole packet data, one block size at a time. + The MAC field is not encrypted unless INTEGRATED_MAC. */ + /* Some crypto back-ends could handle a single crypt() call for + encryption, but (presumably) others cannot, so break it up + into blocksize-sized chunks to satisfy them all. */ + for(i = etm_crypt_offset; i < packet_length; + i += session->local.crypt->blocksize) { + unsigned char *ptr = &p->outbuf[i]; + size_t bsize = LIBSSH2_MIN(session->local.crypt->blocksize, + (int)(packet_length-i)); + /* The INTEGRATED_MAC case always has an extra call below, so + it will never be LAST_BLOCK up here. */ + int firstlast = i == 0 ? FIRST_BLOCK : + (!CRYPT_FLAG_L(session, INTEGRATED_MAC) + && (i == packet_length - session->local.crypt->blocksize) + ? LAST_BLOCK : MIDDLE_BLOCK); + /* In the AAD case, the last block would be only 4 bytes + because everything is offset by 4 since the initial + packet_length isn't encrypted. In this case, combine that last + short packet with the previous one since AES-GCM crypt() + assumes that the entire MAC is available in that packet so it + can set that to the authentication tag. */ + if(!CRYPT_FLAG_L(session, INTEGRATED_MAC)) + if(i > packet_length - 2*bsize) { + /* increase the final block size */ + bsize = packet_length - i; + /* advance the loop counter by the extra amount */ + i += bsize - session->local.crypt->blocksize; + } + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "crypting bytes %lu-%lu", (unsigned long)i, + (unsigned long)(i + bsize - 1))); + if(session->local.crypt->crypt(session, 0, ptr, + bsize, + &session->local.crypt_abstract, + firstlast)) + return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */ + } + + /* Call crypt one last time so it can be filled in with the MAC */ + if(CRYPT_FLAG_L(session, INTEGRATED_MAC)) { + int authlen = local_mac->mac_len; + assert((size_t)total_length <= + packet_length + session->local.crypt->blocksize); + if(session->local.crypt->crypt(session, + 0, + &p->outbuf[packet_length], + authlen, + &session->local.crypt_abstract, + LAST_BLOCK)) + return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */ + } + } + + if(etm) { + /* Calculate MAC hash. Put the output at index packet_length, + since that size includes the whole packet. The MAC is + calculated on the entire packet (length plain the rest + encrypted), including all fields except the MAC field + itself. */ + if(local_mac->hash(session, p->outbuf + packet_length, + session->local.seqno, p->outbuf, + packet_length, NULL, 0, + &session->local.mac_abstract)) + return _libssh2_error(session, LIBSSH2_ERROR_MAC_FAILURE, + "Failed to calculate MAC"); } } session->local.seqno++; + if(session->kex_strict && data[0] == SSH_MSG_NEWKEYS) { + session->local.seqno = 0; + } + ret = LIBSSH2_SEND(session, p->outbuf, total_length, - LIBSSH2_SOCKET_SEND_FLAGS(session)); + LIBSSH2_SOCKET_SEND_FLAGS(session)); if(ret < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", total_length, -ret); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Error sending %ld bytes: %ld", + (long)total_length, (long)-ret)); else { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p", - ret, total_length, p->outbuf); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Sent %ld/%ld bytes at %p", + (long)ret, (long)total_length, (void *)p->outbuf)); debugdump(session, "libssh2_transport_write send()", p->outbuf, ret); } diff --git a/uppsrc/Core/SSH/libssh2/transport.h b/uppsrc/Core/SSH/libssh2/transport.h index 7d395d0e7..4b824e209 100644 --- a/uppsrc/Core/SSH/libssh2/transport.h +++ b/uppsrc/Core/SSH/libssh2/transport.h @@ -1,8 +1,8 @@ -#ifndef __LIBSSH2_TRANSPORT_H -#define __LIBSSH2_TRANSPORT_H -/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009-2010 by Daniel Stenberg - * Author: Daniel Stenberg +#ifndef LIBSSH2_TRANSPORT_H +#define LIBSSH2_TRANSPORT_H +/* Copyright (C) The Written Word, Inc. + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -38,12 +38,13 @@ * OF SUCH DAMAGE. * * This file handles reading and writing to the SECSH transport layer. RFC4253. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #include "packet.h" - /* * libssh2_transport_send * @@ -83,4 +84,4 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, */ int _libssh2_transport_read(LIBSSH2_SESSION * session); -#endif /* __LIBSSH2_TRANSPORT_H */ +#endif /* LIBSSH2_TRANSPORT_H */ diff --git a/uppsrc/Core/SSH/libssh2/userauth.c b/uppsrc/Core/SSH/libssh2/userauth.c index 40ef9153a..0040c3fa3 100644 --- a/uppsrc/Core/SSH/libssh2/userauth.c +++ b/uppsrc/Core/SSH/libssh2/userauth.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2005 Mikhail Gusarov - * Copyright (c) 2009-2014 by Daniel Stenberg +/* Copyright (C) Sara Golemon + * Copyright (C) Mikhail Gusarov + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,14 +35,13 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #include -#include - -#include /* Needed for struct iovec on some platforms */ #ifdef HAVE_SYS_UIO_H @@ -52,8 +51,11 @@ #include "transport.h" #include "session.h" #include "userauth.h" +#include "userauth_kbd_packet.h" -/* libssh2_userauth_list +#include /* strtol() */ + +/* userauth_list * * List authentication methods * Will yield successful login if "none" happens to be allowable for this user @@ -63,11 +65,13 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len) { - static const unsigned char reply_codes[3] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; + unsigned char reply_codes[4] = + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, + SSH_MSG_USERAUTH_BANNER, 0 }; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" + method_len(4) = 27 */ unsigned long methods_len; + unsigned int banner_len; unsigned char *s; int rc; @@ -134,6 +138,57 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, return NULL; } + if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_BANNER) { + if(session->userauth_list_data_len < 5) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unexpected packet size"); + return NULL; + } + banner_len = _libssh2_ntohu32(session->userauth_list_data + 1); + if(banner_len > session->userauth_list_data_len - 5) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Unexpected userauth banner size"); + return NULL; + } + session->userauth_banner = LIBSSH2_ALLOC(session, banner_len + 1); + if(!session->userauth_banner) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for userauth_banner"); + return NULL; + } + memcpy(session->userauth_banner, session->userauth_list_data + 5, + banner_len); + session->userauth_banner[banner_len] = '\0'; + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Banner: %s", + session->userauth_banner)); + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + /* SSH_MSG_USERAUTH_BANNER has been handled */ + reply_codes[2] = 0; + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_list_data, + &session->userauth_list_data_len, 0, + NULL, 0, + &session->userauth_list_packet_requirev_state); + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting userauth list"); + return NULL; + } + else if(rc || (session->userauth_list_data_len < 1)) { + _libssh2_error(session, rc, "Failed getting response"); + session->userauth_list_state = libssh2_NB_state_idle; + return NULL; + } + } + if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) { /* Wow, who'dve thought... */ _libssh2_error(session, LIBSSH2_ERROR_NONE, "No error"); @@ -163,13 +218,13 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, memmove(session->userauth_list_data, session->userauth_list_data + 5, methods_len); session->userauth_list_data[methods_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Permitted auth methods: %s", - session->userauth_list_data); + session->userauth_list_data)); } session->userauth_list_state = libssh2_NB_state_idle; - return (char *) session->userauth_list_data; + return (char *)session->userauth_list_data; } /* libssh2_userauth_list @@ -189,6 +244,30 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, return ptr; } +/* libssh2_userauth_banner + * + * Retrieve banner message from server, if available. + * When no such message is sent by server or if no authentication attempt has + * been made, this function returns LIBSSH2_ERROR_MISSING_AUTH_BANNER. + */ +LIBSSH2_API int +libssh2_userauth_banner(LIBSSH2_SESSION *session, char **banner) +{ + if(!session) + return LIBSSH2_ERROR_MISSING_USERAUTH_BANNER; + + if(!session->userauth_banner) { + return _libssh2_error(session, + LIBSSH2_ERROR_MISSING_USERAUTH_BANNER, + "Missing userauth banner"); + } + + if(banner) + *banner = session->userauth_banner; + + return LIBSSH2_ERROR_NONE; +} + /* * libssh2_userauth_authenticated * @@ -198,7 +277,7 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION * session) { - return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0; + return (session->state & LIBSSH2_STATE_AUTHENTICATED) ? 1 : 0; } @@ -251,8 +330,8 @@ userauth_password(LIBSSH2_SESSION *session, _libssh2_store_u32(&s, password_len); /* 'password' is sent separately */ - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting to login using password authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting to login using password authentication")); session->userauth_pswd_state = libssh2_NB_state_created; } @@ -279,7 +358,7 @@ userauth_password(LIBSSH2_SESSION *session, session->userauth_pswd_state = libssh2_NB_state_sent; } - password_response: +password_response: if((session->userauth_pswd_state == libssh2_NB_state_sent) || (session->userauth_pswd_state == libssh2_NB_state_sent1) @@ -306,8 +385,8 @@ userauth_password(LIBSSH2_SESSION *session, } if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password authentication successful")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; session->state |= LIBSSH2_STATE_AUTHENTICATED; @@ -316,8 +395,8 @@ userauth_password(LIBSSH2_SESSION *session, } else if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication failed"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password authentication failed")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; session->userauth_pswd_state = libssh2_NB_state_idle; @@ -348,8 +427,8 @@ userauth_password(LIBSSH2_SESSION *session, if((session->userauth_pswd_state == libssh2_NB_state_sent1) || (session->userauth_pswd_state == libssh2_NB_state_sent2)) { if(session->userauth_pswd_state == libssh2_NB_state_sent1) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password change required"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password change required")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; } @@ -490,7 +569,7 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, { unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; size_t pubkey_len = pubkeyfiledata_len; - unsigned int tmp_len; + size_t tmp_len; if(pubkeyfiledata_len <= 1) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, @@ -518,7 +597,7 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, } sp1 = memchr(pubkey, ' ', pubkey_len); - if(sp1 == NULL) { + if(!sp1) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data"); @@ -527,16 +606,17 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, sp1++; sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey)); - if(sp2 == NULL) { + if(!sp2) { /* Assume that the id string is missing, but that it's okay */ sp2 = pubkey + pubkey_len; } - if(libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { + if(_libssh2_base64_decode(session, (char **)&tmp, &tmp_len, + (const char *)sp1, + sp2 - sp1)) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid key data, not base64 encoded"); + "Invalid key data, not base64 encoded"); } /* Wasting some bytes here (okay, more than some), but since it's likely @@ -573,10 +653,10 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, char c; unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; size_t pubkey_len = 0, sp_len; - unsigned int tmp_len; + size_t tmp_len; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", - pubkeyfile); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", + pubkeyfile)); /* Read Public Key */ fd = fopen(pubkeyfile, FOPEN_READTEXT); if(!fd) { @@ -621,7 +701,7 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, } sp1 = memchr(pubkey, ' ', pubkey_len); - if(sp1 == NULL) { + if(!sp1) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data"); @@ -631,13 +711,14 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, sp_len = sp1 > pubkey ? (sp1 - pubkey) : 0; sp2 = memchr(sp1, ' ', pubkey_len - sp_len); - if(sp2 == NULL) { + if(!sp2) { /* Assume that the id string is missing, but that it's okay */ sp2 = pubkey + pubkey_len; } - if(libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { + if(_libssh2_base64_decode(session, (char **)&tmp, &tmp_len, + (const char *)sp1, + sp2 - sp1)) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid key data, not base64 encoded"); @@ -659,7 +740,7 @@ static int memory_read_privatekey(LIBSSH2_SESSION * session, const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, void **hostkey_abstract, - const unsigned char *method, int method_len, + const unsigned char *method, size_t method_len, const char *privkeyfiledata, size_t privkeyfiledata_len, const char *passphrase) { @@ -687,7 +768,7 @@ memory_read_privatekey(LIBSSH2_SESSION * session, (unsigned char *) passphrase, hostkey_abstract)) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to initialize private key from file"); + "Unable to initialize private key from memory"); } return 0; @@ -700,14 +781,14 @@ static int file_read_privatekey(LIBSSH2_SESSION * session, const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, void **hostkey_abstract, - const unsigned char *method, int method_len, + const unsigned char *method, size_t method_len, const char *privkeyfile, const char *passphrase) { const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods(); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading private key file: %s", - privkeyfile); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Loading private key file: %s", privkeyfile)); *hostkey_method = NULL; *hostkey_abstract = NULL; while(*hostkey_methods_avail && (*hostkey_methods_avail)->name) { @@ -739,11 +820,17 @@ struct privkey_file { const char *passphrase; }; +struct privkey_mem { + const char *passphrase; + const char *data; + size_t data_len; +}; + static int sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, const unsigned char *data, size_t data_len, void **abstract) { - struct privkey_file *pk_file = (struct privkey_file *) (*abstract); + struct privkey_mem *pk_mem = (struct privkey_mem *) (*abstract); const LIBSSH2_HOSTKEY_METHOD *privkeyobj; void *hostkey_abstract; struct iovec datavec; @@ -752,9 +839,9 @@ sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, rc = memory_read_privatekey(session, &privkeyobj, &hostkey_abstract, session->userauth_pblc_method, session->userauth_pblc_method_len, - pk_file->filename, - strlen(pk_file->filename), - pk_file->passphrase); + pk_mem->data, + pk_mem->data_len, + pk_mem->passphrase); if(rc) return rc; @@ -763,7 +850,7 @@ sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, datavec.iov_len = data_len; if(privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { + &hostkey_abstract)) { if(privkeyobj->dtor) { privkeyobj->dtor(session, &hostkey_abstract); } @@ -799,7 +886,7 @@ sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, datavec.iov_len = data_len; if(privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { + &hostkey_abstract)) { if(privkeyobj->dtor) { privkeyobj->dtor(session, &hostkey_abstract); } @@ -812,7 +899,106 @@ sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, return 0; } +int +libssh2_sign_sk(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, + const unsigned char *data, size_t data_len, void **abstract) +{ + int rc = LIBSSH2_ERROR_DECRYPT; + LIBSSH2_PRIVKEY_SK *sk_info = (LIBSSH2_PRIVKEY_SK *) (*abstract); + LIBSSH2_SK_SIG_INFO sig_info = { 0 }; + if(sk_info->handle_len <= 0) { + return LIBSSH2_ERROR_DECRYPT; + } + + rc = sk_info->sign_callback(session, + &sig_info, + data, + data_len, + sk_info->algorithm, + sk_info->flags, + sk_info->application, + sk_info->key_handle, + sk_info->handle_len, + sk_info->orig_abstract); + + if(rc == 0 && sig_info.sig_r_len > 0 && sig_info.sig_r) { + unsigned char *p = NULL; + + if(sig_info.sig_s_len > 0 && sig_info.sig_s) { + /* sig length, sig_r, sig_s, flags, counter, plus 4 bytes for each + component's length, and up to 1 extra byte for each component */ + *sig_len = 4 + 5 + sig_info.sig_r_len + 5 + sig_info.sig_s_len + 5; + *sig = LIBSSH2_ALLOC(session, *sig_len); + + if(*sig) { + unsigned char *x = *sig; + p = *sig; + + _libssh2_store_u32(&p, 0); + + _libssh2_store_bignum2_bytes(&p, + sig_info.sig_r, + sig_info.sig_r_len); + + _libssh2_store_bignum2_bytes(&p, + sig_info.sig_s, + sig_info.sig_s_len); + + *sig_len = p - *sig; + + _libssh2_store_u32(&x, (uint32_t)(*sig_len - 4)); + } + else { + _libssh2_debug((session, + LIBSSH2_ERROR_ALLOC, + "Unable to allocate ecdsa-sk signature.")); + rc = LIBSSH2_ERROR_ALLOC; + } + } + else { + /* sig, flags, counter, plus 4 bytes for sig length. */ + *sig_len = 4 + sig_info.sig_r_len + 1 + 4; + *sig = LIBSSH2_ALLOC(session, *sig_len); + + if(*sig) { + p = *sig; + + _libssh2_store_str(&p, + (const char *)sig_info.sig_r, + sig_info.sig_r_len); + } + else { + _libssh2_debug((session, + LIBSSH2_ERROR_ALLOC, + "Unable to allocate ed25519-sk signature.")); + rc = LIBSSH2_ERROR_ALLOC; + } + } + + if(p) { + *p = sig_info.flags; + ++p; + _libssh2_store_u32(&p, sig_info.counter); + + *sig_len = p - *sig; + } + + LIBSSH2_FREE(session, sig_info.sig_r); + + if(sig_info.sig_s) { + LIBSSH2_FREE(session, sig_info.sig_s); + } + } + else { + _libssh2_debug((session, + LIBSSH2_ERROR_DECRYPT, + "sign_callback failed or returned invalid signature.")); + *sig_len = 0; + } + + return rc; +} /* userauth_hostbased_fromfile * Authenticate using a keypair found in the named files @@ -858,7 +1044,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, &pubkeydata, &pubkeydata_len, privatekey, passphrase); if(rc) - /* libssh2_pub_priv_keyfile calls _libssh2_error() */ + /* libssh2_pub_priv_keyfile() calls _libssh2_error() */ return rc; } @@ -927,8 +1113,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, datavec[2].iov_len = session->userauth_host_packet_len; if(privkeyobj && privkeyobj->signv && - privkeyobj->signv(session, &sig, &sig_len, 3, - datavec, &abstract)) { + privkeyobj->signv(session, &sig, &sig_len, 3, + datavec, &abstract)) { LIBSSH2_FREE(session, session->userauth_host_method); session->userauth_host_method = NULL; LIBSSH2_FREE(session, session->userauth_host_packet); @@ -967,8 +1153,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, session->userauth_host_packet + session->userauth_host_packet_len; _libssh2_store_u32(&session->userauth_host_s, - 4 + session->userauth_host_method_len + - 4 + sig_len); + (uint32_t)(4 + session->userauth_host_method_len + + 4 + sig_len)); _libssh2_store_str(&session->userauth_host_s, (const char *)session->userauth_host_method, session->userauth_host_method_len); @@ -979,8 +1165,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, sig_len); LIBSSH2_FREE(session, sig); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting hostbased authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting hostbased authentication")); session->userauth_host_state = libssh2_NB_state_created; } @@ -1028,8 +1214,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, } if(session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Hostbased authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Hostbased authentication successful")); /* We are us and we've proved it. */ LIBSSH2_FREE(session, session->userauth_host_data); session->userauth_host_data = NULL; @@ -1070,8 +1256,23 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, return rc; } -static int plain_method_len(const char *method, size_t method_len) +size_t plain_method(char *method, size_t method_len) { + if(!strncmp("ssh-rsa-cert-v01@openssh.com", + method, + method_len)) { + return 7; + } + + if(!strncmp("rsa-sha2-256-cert-v01@openssh.com", + method, + method_len) || + !strncmp("rsa-sha2-512-cert-v01@openssh.com", + method, + method_len)) { + return 12; + } + if(!strncmp("ecdsa-sha2-nistp256-cert-v01@openssh.com", method, method_len) || @@ -1083,15 +1284,240 @@ static int plain_method_len(const char *method, size_t method_len) method_len)) { return 19; } + + if(!strncmp("ssh-ed25519-cert-v01@openssh.com", + method, + method_len)) { + return 11; + } + + if(!strncmp("sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", + method, + method_len)) { + const char *new_method = "sk-ecdsa-sha2-nistp256@openssh.com"; + memcpy(method, new_method, strlen(new_method)); + return strlen(new_method); + } + + if(!strncmp("sk-ssh-ed25519-cert-v01@openssh.com", + method, + method_len)) { + const char *new_method = "sk-ssh-ed25519@openssh.com"; + memcpy(method, new_method, strlen(new_method)); + return strlen(new_method); + } + return method_len; } +/* Function to check if the given version is less than pattern (OpenSSH 7.8) + * This function expects the input version in x.y* format + * (x being openssh major and y being openssh minor version) + * Returns 1 if the version is less than OpenSSH_7.8, 0 otherwise + */ +static int is_version_less_than_78(const char *version) +{ + char *endptr = NULL; + long major = 0; + int minor = 0; + + if(!version) + return 0; + + major = strtol(version, &endptr, 10); + if(!endptr || *endptr != '.') + return 0; /* Not a valid number */ + minor = (endptr + 1)[0] - '0'; + if((major >= 1 && major <= 6) || + (major == 7 && minor >= 0 && minor <= 7)) { + return 1; /* Version is in the specified range */ + } + return 0; +} + +/** + * @function _libssh2_key_sign_algorithm + * @abstract Upgrades the algorithm used for public key signing RFC 8332 + * @discussion Based on the incoming key_method value, this function + * will upgrade the key method input based on user preferences, + * server support algos and crypto backend support + * @related _libssh2_supported_key_sign_algorithms() + * @param key_method current key method, usually the default key sig method + * @param key_method_len length of the key method buffer + * @result error code or zero on success + */ + +static int +_libssh2_key_sign_algorithm(LIBSSH2_SESSION *session, + unsigned char **key_method, + size_t *key_method_len) +{ + const char *s = NULL; + const char *a = NULL; + const char *match = NULL; + const char *p = NULL; + const char *f = NULL; + char *i = NULL; + size_t p_len = 0; + size_t f_len = 0; + int rc = 0; + size_t match_len = 0; + const size_t suffix_len = 21; + char *filtered_algs = NULL; + const char * const certSuffix = "-cert-v01@openssh.com"; + const char *remote_banner = NULL; + const char * const remote_ver_pre = "OpenSSH_"; + const char *remote_ver_start = NULL; + const char *remote_ver = NULL; + int SSH_BUG_SIGTYPE = 0; + + const char *supported_algs = + _libssh2_supported_key_sign_algorithms(session, + *key_method, + *key_method_len); + + if(!supported_algs || !session->server_sign_algorithms) { + /* no upgrading key algorithm supported, do nothing */ + return LIBSSH2_ERROR_NONE; + } + + filtered_algs = LIBSSH2_ALLOC(session, strlen(supported_algs) + 1); + if(!filtered_algs) { + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate filtered algs"); + return rc; + } + + /* Set "SSH_BUG_SIGTYPE" flag when the remote server version is OpenSSH 7.7 + or lower and when the RSA key in question is a certificate to ignore + "server-sig-algs" and only offer ssh-rsa signature algorithm for + RSA certs */ + remote_banner = libssh2_session_banner_get(session); + /* Extract version information from the banner */ + if(remote_banner) { + remote_ver_start = strstr(remote_banner, remote_ver_pre); + if(remote_ver_start) { + remote_ver = remote_ver_start + strlen(remote_ver_pre); + SSH_BUG_SIGTYPE = is_version_less_than_78(remote_ver); + if(SSH_BUG_SIGTYPE && *key_method_len == 28 && + memcmp(key_method, "ssh-rsa-cert-v01@openssh.com", + *key_method_len)) { + return LIBSSH2_ERROR_NONE; + } + } + } + + s = session->server_sign_algorithms; + i = filtered_algs; + + /* this walks the server algo list and the supported algo list and creates + a filtered list that includes matches */ + + while(s && *s) { + p = strchr(s, ','); + p_len = (p ? (size_t)(p - s) : strlen(s)); + a = supported_algs; + + while(a && *a) { + f = strchr(a, ','); + f_len = (f ? (size_t)(f - a) : strlen(a)); + + if(f_len == p_len && memcmp(a, s, p_len) == 0) { + + if(i != filtered_algs) { + memcpy(i, ",", 1); + i += 1; + } + + memcpy(i, s, p_len); + i += p_len; + } + + a = f ? (f + 1) : NULL; + } + + s = p ? (p + 1) : NULL; + } + + filtered_algs[i - filtered_algs] = '\0'; + + if(session->sign_algo_prefs) { + s = session->sign_algo_prefs; + } + else { + s = supported_algs; + } + + /* now that we have the possible supported algos, match based on the prefs + or what is supported by the crypto backend, look for a match */ + + while(s && *s && !match) { + p = strchr(s, ','); + p_len = (p ? (size_t)(p - s) : strlen(s)); + a = filtered_algs; + + while(a && *a && !match) { + f = strchr(a, ','); + f_len = (f ? (size_t)(f - a) : strlen(a)); + + if(f_len == p_len && memcmp(a, s, p_len) == 0) { + /* found a match, upgrade key method */ + match = s; + match_len = p_len; + } + else { + a = f ? (f + 1) : NULL; + } + } + + s = p ? (p + 1) : NULL; + } + + if(match) { + if(*key_method_len == 28 && + memcmp(key_method, "ssh-rsa-cert-v01@openssh.com", *key_method_len)) { + if(*key_method) + LIBSSH2_FREE(session, *key_method); + *key_method = LIBSSH2_ALLOC(session, match_len + suffix_len); + if(*key_method) { + memcpy(*key_method, match, match_len); + memcpy(*key_method + match_len, certSuffix, suffix_len); + *key_method_len = match_len + suffix_len; + } + } + else { + if(*key_method) + LIBSSH2_FREE(session, *key_method); + *key_method = LIBSSH2_ALLOC(session, match_len); + if(*key_method) { + memcpy(*key_method, match, match_len); + *key_method_len = match_len; + } + } + if(!key_method) { + *key_method_len = 0; + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate key method upgrade"); + } + } + else { + /* no match was found */ + rc = _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, + "No signing signature matched"); + } + + if(filtered_algs) + LIBSSH2_FREE(session, filtered_algs); + + return rc; +} + int _libssh2_userauth_publickey(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len, + size_t username_len, const unsigned char *pubkeydata, - unsigned long pubkeydata_len, + size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC ((*sign_callback)), void *abstract) @@ -1102,6 +1528,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, }; int rc; unsigned char *s; + int auth_attempts = 0; + +retry_auth: + auth_attempts++; if(session->userauth_pblc_state == libssh2_NB_state_idle) { @@ -1127,9 +1557,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata); if(session->userauth_pblc_method_len > pubkeydata_len - 4) - /* the method length simply cannot be longer than the entire - passed in data, so we use this to detect crazy input - data */ + /* the method length cannot be longer than the entire passed + in data, so we use this to detect crazy input data */ return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid public key"); @@ -1144,15 +1573,27 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, memcpy(session->userauth_pblc_method, pubkeydata + 4, session->userauth_pblc_method_len); } - /* - * The length of the method name read from plaintext prefix in the - * file must match length embedded in the key. - * TODO: The data should match too but we don't check that. Should we? - */ - else if(session->userauth_pblc_method_len != - _libssh2_ntohu32(pubkeydata)) - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key"); + + /* upgrade key signing algo if it is supported and + * it is our first auth attempt, otherwise fallback to + * the key default algo */ + if(auth_attempts == 1) { + rc = _libssh2_key_sign_algorithm(session, + &session->userauth_pblc_method, + &session->userauth_pblc_method_len); + + if(rc) + return rc; + } + + if(session->userauth_pblc_method_len && + session->userauth_pblc_method) { + _libssh2_debug((session, + LIBSSH2_TRACE_KEX, + "Signing using %.*s", + (int)session->userauth_pblc_method_len, + session->userauth_pblc_method)); + } /* * 45 = packet_type(1) + username_len(4) + servicename_len(4) + @@ -1198,8 +1639,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, session->userauth_pblc_method_len); _libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting publickey authentication")); session->userauth_pblc_state = libssh2_NB_state_created; } @@ -1246,8 +1687,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, } if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Pubkey authentication prematurely successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Pubkey authentication prematurely successful")); /* * God help any SSH server that allows an UNVERIFIED * public key to validate the user @@ -1310,6 +1751,17 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); } + else if(rc == LIBSSH2_ERROR_ALGO_UNSUPPORTED && auth_attempts == 1) { + /* try again with the default key algo */ + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + + rc = LIBSSH2_ERROR_NONE; + goto retry_auth; + } else if(rc) { LIBSSH2_FREE(session, session->userauth_pblc_method); session->userauth_pblc_method = NULL; @@ -1350,23 +1802,39 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, session->userauth_pblc_b = NULL; session->userauth_pblc_method_len = - plain_method_len((const char *)session->userauth_pblc_method, - session->userauth_pblc_method_len); + plain_method((char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); - _libssh2_store_u32(&s, - 4 + session->userauth_pblc_method_len + 4 + - sig_len); - _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, - session->userauth_pblc_method_len); + if(strncmp((const char *)session->userauth_pblc_method, + "sk-ecdsa-sha2-nistp256@openssh.com", + session->userauth_pblc_method_len) == 0 || + strncmp((const char *)session->userauth_pblc_method, + "sk-ssh-ed25519@openssh.com", + session->userauth_pblc_method_len) == 0) { + _libssh2_store_u32(&s, + (uint32_t)(4 + session->userauth_pblc_method_len + + sig_len)); + _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + memcpy(s, sig, sig_len); + s += sig_len; + } + else { + _libssh2_store_u32(&s, + (uint32_t)(4 + session->userauth_pblc_method_len + + 4 + sig_len)); + _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + _libssh2_store_str(&s, (const char *)sig, sig_len); + } LIBSSH2_FREE(session, session->userauth_pblc_method); session->userauth_pblc_method = NULL; - _libssh2_store_str(&s, (const char *)sig, sig_len); LIBSSH2_FREE(session, sig); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication -- phase 2"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting publickey authentication -- phase 2")); session->userauth_pblc_s = s; session->userauth_pblc_state = libssh2_NB_state_sent2; @@ -1412,8 +1880,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, } if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Publickey authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Publickey authentication successful")); /* We are us and we've proved it. */ LIBSSH2_FREE(session, session->userauth_pblc_data); session->userauth_pblc_data = NULL; @@ -1431,10 +1899,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, "username/public key combination"); } - /* - * userauth_publickey_frommemory - * Authenticate using a keypair from memory - */ +/* + * userauth_publickey_frommemory + * Authenticate using a keypair from memory + */ static int userauth_publickey_frommemory(LIBSSH2_SESSION *session, const char *username, @@ -1447,12 +1915,13 @@ userauth_publickey_frommemory(LIBSSH2_SESSION *session, { unsigned char *pubkeydata = NULL; size_t pubkeydata_len = 0; - struct privkey_file privkey_file; - void *abstract = &privkey_file; + struct privkey_mem privkey_mem; + void *abstract = &privkey_mem; int rc; - privkey_file.filename = privatekeydata; - privkey_file.passphrase = passphrase; + privkey_mem.data = privatekeydata; + privkey_mem.data_len = privatekeydata_len; + privkey_mem.passphrase = passphrase; if(session->userauth_pblc_state == libssh2_NB_state_idle) { if(publickeydata_len && publickeydata) { @@ -1556,7 +2025,7 @@ libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, { int rc; - if(NULL == passphrase) + if(!passphrase) /* if given a NULL pointer, make it point to a zero-length string to save us from having to check this all over */ passphrase = ""; @@ -1584,7 +2053,7 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, { int rc; - if(NULL == passphrase) + if(!passphrase) /* if given a NULL pointer, make it point to a zero-length string to save us from having to check this all over */ passphrase = ""; @@ -1605,7 +2074,7 @@ libssh2_userauth_publickey(LIBSSH2_SESSION *session, const unsigned char *pubkeydata, size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), + ((*sign_callback)), void **abstract) { int rc; @@ -1632,16 +2101,16 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, const char *username, unsigned int username_len, LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC - ((*response_callback))) + ((*response_callback))) { unsigned char *s; + int rc; static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 }; - unsigned int language_tag_len; unsigned int i; if(session->userauth_kybd_state == libssh2_NB_state_idle) { @@ -1692,8 +2161,8 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, /* submethods */ _libssh2_store_u32(&s, 0); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting keyboard-interactive authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting keyboard-interactive authentication")); session->userauth_kybd_state = libssh2_NB_state_created; } @@ -1741,9 +2210,9 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Keyboard-interactive " - "authentication successful"); + "authentication successful")); LIBSSH2_FREE(session, session->userauth_kybd_data); session->userauth_kybd_data = NULL; session->state |= LIBSSH2_STATE_AUTHENTICATED; @@ -1752,8 +2221,8 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive authentication failed"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Keyboard-interactive authentication failed")); LIBSSH2_FREE(session, session->userauth_kybd_data); session->userauth_kybd_data = NULL; session->userauth_kybd_state = libssh2_NB_state_idle; @@ -1764,232 +2233,36 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } /* server requested PAM-like conversation */ - s = session->userauth_kybd_data + 1; - - if(session->userauth_kybd_data_len >= 5) { - /* string name (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "to get length"); + if(userauth_keyboard_interactive_decode_info_request(session) + < 0) { goto cleanup; } - if(session->userauth_kybd_auth_name_len) { - session->userauth_kybd_auth_name = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_name_len); - if(!session->userauth_kybd_auth_name) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'name' " - "request field"); - goto cleanup; - } - if(s + session->userauth_list_data_len <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_auth_name, s, - session->userauth_kybd_auth_name_len); - s += session->userauth_kybd_auth_name_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth name"); - goto cleanup; - } - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string instruction (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_instruction_len = - _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth instruction length"); - goto cleanup; - } - - if(session->userauth_kybd_auth_instruction_len) { - session->userauth_kybd_auth_instruction = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_instruction_len); - if(!session->userauth_kybd_auth_instruction) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'instruction' " - "request field"); - goto cleanup; - } - if(s + session->userauth_kybd_auth_instruction_len <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_auth_instruction, s, - session->userauth_kybd_auth_instruction_len); - s += session->userauth_kybd_auth_instruction_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth instruction"); - goto cleanup; - } - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string language tag (as defined in [RFC-3066]) */ - language_tag_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth language tag length"); - goto cleanup; - } - - if(s + language_tag_len <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* ignoring this field as deprecated */ - s += language_tag_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth language tag"); - goto cleanup; - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* int num-prompts */ - session->userauth_kybd_num_prompts = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth num keyboard prompts"); - goto cleanup; - } - - if(session->userauth_kybd_num_prompts > 100) { - _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, - "Too many replies for " - "keyboard-interactive prompts"); - goto cleanup; - } - - if(session->userauth_kybd_num_prompts) { - session->userauth_kybd_prompts = - LIBSSH2_CALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * - session->userauth_kybd_num_prompts); - if(!session->userauth_kybd_prompts) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompts array"); - goto cleanup; - } - - session->userauth_kybd_responses = - LIBSSH2_CALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * - session->userauth_kybd_num_prompts); - if(!session->userauth_kybd_responses) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive responses array"); - goto cleanup; - } - - for(i = 0; i < session->userauth_kybd_num_prompts; i++) { - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string prompt[1] (ISO-10646 UTF-8) */ - session->userauth_kybd_prompts[i].length = - _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard " - "prompt length"); - goto cleanup; - } - - session->userauth_kybd_prompts[i].text = - LIBSSH2_CALLOC(session, - session->userauth_kybd_prompts[i]. - length); - if(!session->userauth_kybd_prompts[i].text) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompt message"); - goto cleanup; - } - - if(s + session->userauth_kybd_prompts[i].length <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_prompts[i].text, s, - session->userauth_kybd_prompts[i].length); - s += session->userauth_kybd_prompts[i].length; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard prompt"); - goto cleanup; - } - if(s < session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* boolean echo[1] */ - session->userauth_kybd_prompts[i].echo = *s++; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard prompt echo"); - goto cleanup; - } - } - } - - response_callback(session->userauth_kybd_auth_name, - session->userauth_kybd_auth_name_len, + response_callback((const char *)session->userauth_kybd_auth_name, + (int)session->userauth_kybd_auth_name_len, + (const char *) session->userauth_kybd_auth_instruction, - session->userauth_kybd_auth_instruction_len, + (int)session->userauth_kybd_auth_instruction_len, session->userauth_kybd_num_prompts, session->userauth_kybd_prompts, session->userauth_kybd_responses, &session->abstract); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Keyboard-interactive response callback function" - " invoked"); + " invoked")); session->userauth_kybd_packet_len = - 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ - + 4 /* int num-responses */ + 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ + + 4 /* int num-responses */ ; for(i = 0; i < session->userauth_kybd_num_prompts; i++) { /* string response[1] (ISO-10646 UTF-8) */ if(session->userauth_kybd_responses[i].length <= - (SIZE_MAX - 4 - session->userauth_kybd_packet_len) ) { + (SIZE_MAX - 4 - session->userauth_kybd_packet_len)) { session->userauth_kybd_packet_len += - 4 + session->userauth_kybd_responses[i].length; + 4 + (size_t)session->userauth_kybd_responses[i].length; } else { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -2042,7 +2315,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, session->userauth_kybd_auth_failure = 0; } - cleanup: +cleanup: /* * It's safe to clean all the data here, because unallocated pointers * are filled by zeroes @@ -2102,7 +2375,7 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *user, unsigned int user_len, LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC - ((*response_callback))) + ((*response_callback))) { int rc; BLOCK_ADJUST(rc, session, @@ -2110,3 +2383,124 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, response_callback)); return rc; } + +/* + * libssh2_userauth_publickey_sk + * + * Authenticate using an external callback function + */ +LIBSSH2_API int +libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session, + const char *username, + size_t username_len, + const unsigned char *publickeydata, + size_t publickeydata_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase, + LIBSSH2_USERAUTH_SK_SIGN_FUNC + ((*sign_callback)), + void **abstract) +{ + int rc = LIBSSH2_ERROR_NONE; + + unsigned char *tmp_method = NULL; + size_t tmp_method_len = 0; + + unsigned char *tmp_publickeydata = NULL; + size_t tmp_publickeydata_len = 0; + + unsigned char *pubkeydata = NULL; + size_t pubkeydata_len = 0; + + LIBSSH2_PRIVKEY_SK sk_info = { 0 }; + void *sign_abstract = &sk_info; + + sk_info.sign_callback = sign_callback; + sk_info.orig_abstract = abstract; + + if(privatekeydata_len && privatekeydata) { + + if(_libssh2_sk_pub_keyfilememory(session, + &tmp_method, + &tmp_method_len, + &tmp_publickeydata, + &tmp_publickeydata_len, + &(sk_info.algorithm), + &(sk_info.flags), + &(sk_info.application), + &(sk_info.key_handle), + &(sk_info.handle_len), + privatekeydata, privatekeydata_len, + passphrase)) { + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public key " + "from private key."); + } + else if(publickeydata_len == 0 || !publickeydata) { + session->userauth_pblc_method = tmp_method; + session->userauth_pblc_method_len = tmp_method_len; + + pubkeydata_len = tmp_publickeydata_len; + pubkeydata = tmp_publickeydata; + } + else { + const char *ecdsa = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"; + const char *ed25519 = "sk-ssh-ed25519-cert-v01@openssh.com"; + + if(tmp_method) { + LIBSSH2_FREE(session, tmp_method); + } + + if(!strncmp((char *)publickeydata, ecdsa, strlen(ecdsa))) { + session->userauth_pblc_method_len = strlen(ecdsa); + session->userauth_pblc_method = + LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); + + memcpy(session->userauth_pblc_method, ecdsa, + session->userauth_pblc_method_len); + } + else if(!strncmp((char *)publickeydata, ed25519, + strlen(ed25519))) { + session->userauth_pblc_method_len = strlen(ed25519); + session->userauth_pblc_method = + LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); + + memcpy(session->userauth_pblc_method, ed25519, + session->userauth_pblc_method_len); + } + + rc = memory_read_publickey(session, + &session->userauth_pblc_method, + &session->userauth_pblc_method_len, + &pubkeydata, &pubkeydata_len, + (char *)publickeydata, + publickeydata_len); + } + } + else { + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Invalid data in public and private key."); + } + + if(rc == LIBSSH2_ERROR_NONE) { + rc = _libssh2_userauth_publickey(session, username, username_len, + pubkeydata, pubkeydata_len, + libssh2_sign_sk, &sign_abstract); + + while(rc == LIBSSH2_ERROR_EAGAIN) { + rc = _libssh2_userauth_publickey(session, username, username_len, + pubkeydata, pubkeydata_len, + libssh2_sign_sk, &sign_abstract); + } + } + + if(tmp_publickeydata) + LIBSSH2_FREE(session, tmp_publickeydata); + + if(sk_info.application) { + LIBSSH2_FREE(session, (void *)sk_info.application); + } + + return rc; +} diff --git a/uppsrc/Core/SSH/libssh2/userauth.h b/uppsrc/Core/SSH/libssh2/userauth.h index 6b402ddbf..2f53ac5be 100644 --- a/uppsrc/Core/SSH/libssh2/userauth.h +++ b/uppsrc/Core/SSH/libssh2/userauth.h @@ -1,7 +1,7 @@ -#ifndef __LIBSSH2_USERAUTH_H -#define __LIBSSH2_USERAUTH_H -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2009-2010 by Daniel Stenberg +#ifndef LIBSSH2_USERAUTH_H +#define LIBSSH2_USERAUTH_H +/* Copyright (C) Sara Golemon + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,16 +36,18 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ int _libssh2_userauth_publickey(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len, + size_t username_len, const unsigned char *pubkeydata, - unsigned long pubkeydata_len, + size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), + ((*sign_callback)), void *abstract); -#endif /* __LIBSSH2_USERAUTH_H */ +#endif /* LIBSSH2_USERAUTH_H */ diff --git a/uppsrc/Core/SSH/libssh2/userauth_kbd_packet.c b/uppsrc/Core/SSH/libssh2/userauth_kbd_packet.c new file mode 100644 index 000000000..216048e2e --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/userauth_kbd_packet.c @@ -0,0 +1,166 @@ +/* Copyright (C) Xaver Loppenstedt + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "libssh2_priv.h" +#include "userauth_kbd_packet.h" + +int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *session) +{ + unsigned char *language_tag; + size_t language_tag_len; + unsigned int i; + unsigned char packet_type; + uint32_t tmp_u32; + + struct string_buf decoded; + + decoded.data = session->userauth_kybd_data; + decoded.dataptr = session->userauth_kybd_data; + decoded.len = session->userauth_kybd_data_len; + + if(session->userauth_kybd_data_len < 17) { + _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "userauth keyboard data buffer too small " + "to get length"); + return -1; + } + + /* byte SSH_MSG_USERAUTH_INFO_REQUEST */ + _libssh2_get_byte(&decoded, &packet_type); + + /* string name (ISO-10646 UTF-8) */ + if(_libssh2_copy_string(session, &decoded, + &session->userauth_kybd_auth_name, + &session->userauth_kybd_auth_name_len) == -1) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to decode " + "keyboard-interactive 'name' " + "request field"); + return -1; + } + + /* string instruction (ISO-10646 UTF-8) */ + if(_libssh2_copy_string(session, &decoded, + &session->userauth_kybd_auth_instruction, + &session->userauth_kybd_auth_instruction_len) + == -1) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to decode " + "keyboard-interactive 'instruction' " + "request field"); + return -1; + } + + /* string language tag (as defined in [RFC-3066]) */ + if(_libssh2_get_string(&decoded, &language_tag, + &language_tag_len) == -1) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to decode " + "keyboard-interactive 'language tag' " + "request field"); + return -1; + } + + /* int num-prompts */ + if(_libssh2_get_u32(&decoded, &tmp_u32) == -1 || + (session->userauth_kybd_num_prompts = tmp_u32) != tmp_u32) { + _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Unable to decode " + "keyboard-interactive number of keyboard prompts"); + return -1; + } + + if(session->userauth_kybd_num_prompts > 100) { + _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Too many replies for " + "keyboard-interactive prompts"); + return -1; + } + + if(session->userauth_kybd_num_prompts == 0) { + return 0; + } + + session->userauth_kybd_prompts = + LIBSSH2_CALLOC(session, + sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * + session->userauth_kybd_num_prompts); + if(!session->userauth_kybd_prompts) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive prompts array"); + return -1; + } + + session->userauth_kybd_responses = + LIBSSH2_CALLOC(session, + sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * + session->userauth_kybd_num_prompts); + if(!session->userauth_kybd_responses) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive responses array"); + return -1; + } + + for(i = 0; i < session->userauth_kybd_num_prompts; i++) { + /* string prompt[1] (ISO-10646 UTF-8) */ + if(_libssh2_copy_string(session, &decoded, + &session->userauth_kybd_prompts[i].text, + &session->userauth_kybd_prompts[i].length) + == -1) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to decode " + "keyboard-interactive prompt message"); + return -1; + } + + /* boolean echo[1] */ + if(_libssh2_get_boolean(&decoded, + &session->userauth_kybd_prompts[i].echo) + == -1) { + _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Unable to decode " + "user auth keyboard prompt echo"); + return -1; + } + } + + return 0; +} diff --git a/uppsrc/Core/SSH/libssh2/userauth_kbd_packet.h b/uppsrc/Core/SSH/libssh2/userauth_kbd_packet.h new file mode 100644 index 000000000..56e88b3f3 --- /dev/null +++ b/uppsrc/Core/SSH/libssh2/userauth_kbd_packet.h @@ -0,0 +1,45 @@ +/* Copyright (C) Xaver Loppenstedt + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef LIBSSH2_USERAUTH_KBD_PACKET_H +#define LIBSSH2_USERAUTH_KBD_PACKET_H + +int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *); + +#endif /* LIBSSH2_USERAUTH_KBD_PACKET_H */ diff --git a/uppsrc/Core/SSH/libssh2/version.c b/uppsrc/Core/SSH/libssh2/version.c index 408f83a39..d32ae64ae 100644 --- a/uppsrc/Core/SSH/libssh2/version.c +++ b/uppsrc/Core/SSH/libssh2/version.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2009 Daniel Stenberg. All rights reserved. +/* Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -33,18 +34,11 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -/* - libssh2_version() can be used like this: - - if (!libssh2_version(LIBSSH2_VERSION_NUM)) { - fprintf (stderr, "Runtime libssh2 version too old!\n"); - exit(1); - } -*/ LIBSSH2_API const char *libssh2_version(int req_version_num) { @@ -52,3 +46,9 @@ const char *libssh2_version(int req_version_num) return LIBSSH2_VERSION; return NULL; /* this is not a suitable library! */ } + +LIBSSH2_API +libssh2_crypto_engine_t libssh2_crypto_engine(void) +{ + return LIBSSH2_CRYPTO_ENGINE; +} diff --git a/uppsrc/Core/SSH/libssh2/wincng.c b/uppsrc/Core/SSH/libssh2/wincng.c index cbb2b61cb..5d4b36b70 100644 --- a/uppsrc/Core/SSH/libssh2/wincng.c +++ b/uppsrc/Core/SSH/libssh2/wincng.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2020 Marc Hoersken + * Copyright (C) Marc Hoersken * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,11 +34,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include "libssh2_priv.h" - -#ifdef LIBSSH2_WINCNG /* compile only if we build with wincng */ +#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */ /* required for cross-compilation against the w64 mingw-runtime package */ #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) @@ -48,6 +48,10 @@ #define _WIN32_WINNT 0x0600 #endif +#if !defined(LIBSSH2_WINCNG_DISABLE_WINCRYPT) && !defined(HAVE_LIBCRYPT32) +#define HAVE_LIBCRYPT32 +#endif + /* specify the required libraries for dependencies using MSVC */ #ifdef _MSC_VER #pragma comment(lib, "bcrypt.lib") @@ -58,22 +62,32 @@ #include #include -#include #include -#include "misc.h" -#ifdef HAVE_STDLIB_H #include -#endif + #ifdef HAVE_LIBCRYPT32 -#include +#include /* for CryptDecodeObjectEx() */ #endif #define PEM_RSA_HEADER "-----BEGIN RSA PRIVATE KEY-----" #define PEM_RSA_FOOTER "-----END RSA PRIVATE KEY-----" #define PEM_DSA_HEADER "-----BEGIN DSA PRIVATE KEY-----" #define PEM_DSA_FOOTER "-----END DSA PRIVATE KEY-----" +#define PEM_ECDSA_HEADER "-----BEGIN OPENSSH PRIVATE KEY-----" +#define PEM_ECDSA_FOOTER "-----END OPENSSH PRIVATE KEY-----" +#define OPENSSL_PRIVATEKEY_AUTH_MAGIC "openssh-key-v1" + +/* Define these manually to avoid including and thus + clashing with symbols. */ +#ifndef STATUS_NOT_SUPPORTED +#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BB) +#endif + +#ifndef STATUS_INVALID_SIGNATURE +#define STATUS_INVALID_SIGNATURE ((NTSTATUS)0xC000A000) +#endif /*******************************************************************/ /* @@ -87,9 +101,11 @@ #define BCRYPT_RNG_ALGORITHM L"RNG" #endif +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM #ifndef BCRYPT_MD5_ALGORITHM #define BCRYPT_MD5_ALGORITHM L"MD5" #endif +#endif #ifndef BCRYPT_SHA1_ALGORITHM #define BCRYPT_SHA1_ALGORITHM L"SHA1" @@ -216,6 +232,103 @@ #define PKCS_RSA_PRIVATE_KEY (LPCSTR)43 #endif +#if defined(_MSC_VER) && _MSC_VER < 1700 +/* Workaround for warning C4306: + 'type cast' : conversion from 'int' to 'LPCSTR' of greater size */ +#undef X509_SEQUENCE_OF_ANY +#undef X509_MULTI_BYTE_UINT +#undef PKCS_RSA_PRIVATE_KEY +#define X509_SEQUENCE_OF_ANY ((LPCSTR)(size_t)34) +#define X509_MULTI_BYTE_UINT ((LPCSTR)(size_t)38) +#define PKCS_RSA_PRIVATE_KEY ((LPCSTR)(size_t)43) +#endif + +static int +_libssh2_wincng_bignum_resize(_libssh2_bn* bn, ULONG length); + +/*******************************************************************/ +/* + * Windows CNG backend: ECDSA-specific declarations. + */ +#if LIBSSH2_ECDSA + +typedef enum { + WINCNG_ECC_KEYTYPE_ECDSA = 0, + WINCNG_ECC_KEYTYPE_ECDH = 1, +} _libssh2_wincng_ecc_keytype; + +typedef struct __libssh2_wincng_ecdsa_algorithm { + /* Algorithm name */ + const char *name; + + /* Key length, in bits */ + ULONG key_length; + + /* Length of each point, in bytes */ + ULONG point_length; + + /* Name of CNG algorithm provider, */ + /* indexed by _libssh2_wincng_ecc_keytype */ + LPCWSTR provider[2]; + + /* Magic for public key import, indexed by _libssh2_wincng_ecc_keytype */ + ULONG public_import_magic[2]; + + /* Magic for private key import, indexed by _libssh2_wincng_ecc_keytype */ + ULONG private_import_magic[2]; +} _libssh2_wincng_ecdsa_algorithm; + +/* Supported algorithms, indexed by libssh2_curve_type */ +static _libssh2_wincng_ecdsa_algorithm _wincng_ecdsa_algorithms[] = { + { + "ecdsa-sha2-nistp256", + 256, + 256 / 8, + { BCRYPT_ECDSA_P256_ALGORITHM, BCRYPT_ECDH_P256_ALGORITHM }, + { BCRYPT_ECDSA_PUBLIC_P256_MAGIC, BCRYPT_ECDH_PUBLIC_P256_MAGIC }, + { BCRYPT_ECDSA_PRIVATE_P256_MAGIC, BCRYPT_ECDH_PRIVATE_P256_MAGIC } + }, + { + "ecdsa-sha2-nistp384", + 384, + 384 / 8, + { BCRYPT_ECDSA_P384_ALGORITHM, BCRYPT_ECDH_P384_ALGORITHM }, + { BCRYPT_ECDSA_PUBLIC_P384_MAGIC, BCRYPT_ECDH_PUBLIC_P384_MAGIC }, + { BCRYPT_ECDSA_PRIVATE_P384_MAGIC, BCRYPT_ECDH_PRIVATE_P384_MAGIC } + }, + { + "ecdsa-sha2-nistp521", + 521, + ((521 + 7) & ~7) / 8, + { BCRYPT_ECDSA_P521_ALGORITHM, BCRYPT_ECDH_P521_ALGORITHM }, + { BCRYPT_ECDSA_PUBLIC_P521_MAGIC, BCRYPT_ECDH_PUBLIC_P521_MAGIC }, + { BCRYPT_ECDSA_PRIVATE_P521_MAGIC, BCRYPT_ECDH_PRIVATE_P521_MAGIC } + }, +}; + +/* An encoded point */ +typedef struct __libssh2_ecdsa_point { + libssh2_curve_type curve; + + const unsigned char *x; + ULONG x_len; + + const unsigned char *y; + ULONG y_len; +} _libssh2_ecdsa_point; + +/* Lookup libssh2_curve_type by name */ +static int +_libssh2_wincng_ecdsa_curve_type_from_name(IN const char *name, + OUT libssh2_curve_type *out_curve); + +/* Parse an OpenSSL-formatted ECDSA private key */ +static int +_libssh2_wincng_parse_ecdsa_privatekey(OUT _libssh2_wincng_ecdsa_key **key, + IN unsigned char *privatekey, + IN size_t privatekey_len); + +#endif /*******************************************************************/ /* @@ -229,6 +342,10 @@ _libssh2_wincng_init(void) { int ret; +#if LIBSSH2_ECDSA + unsigned int curve; +#endif + memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG, @@ -237,11 +354,13 @@ _libssh2_wincng_init(void) _libssh2_wincng.hAlgRNG = NULL; } +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5, BCRYPT_MD5_ALGORITHM, NULL, 0); if(!BCRYPT_SUCCESS(ret)) { _libssh2_wincng.hAlgHashMD5 = NULL; } +#endif ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1, BCRYPT_SHA1_ALGORITHM, NULL, 0); if(!BCRYPT_SUCCESS(ret)) { @@ -263,12 +382,14 @@ _libssh2_wincng_init(void) _libssh2_wincng.hAlgHashSHA512 = NULL; } +#if LIBSSH2_MD5 ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5, BCRYPT_MD5_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); if(!BCRYPT_SUCCESS(ret)) { _libssh2_wincng.hAlgHmacMD5 = NULL; } +#endif ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); @@ -371,15 +492,46 @@ _libssh2_wincng_init(void) if(!BCRYPT_SUCCESS(ret)) { _libssh2_wincng.hAlgDH = NULL; } + +#if LIBSSH2_ECDSA + for(curve = 0; curve < ARRAY_SIZE(_wincng_ecdsa_algorithms); curve++) { + BCRYPT_ALG_HANDLE alg_handle_ecdsa; + BCRYPT_ALG_HANDLE alg_handle_ecdh; + + ret = BCryptOpenAlgorithmProvider( + &alg_handle_ecdsa, + _wincng_ecdsa_algorithms[curve].provider[WINCNG_ECC_KEYTYPE_ECDSA], + NULL, + 0); + if(BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgECDSA[curve] = alg_handle_ecdsa; + } + + ret = BCryptOpenAlgorithmProvider( + &alg_handle_ecdh, + _wincng_ecdsa_algorithms[curve].provider[WINCNG_ECC_KEYTYPE_ECDH], + NULL, + 0); + if(BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgECDH[curve] = alg_handle_ecdh; + } + } +#endif } void _libssh2_wincng_free(void) { +#if LIBSSH2_ECDSA + unsigned int curve; +#endif + if(_libssh2_wincng.hAlgRNG) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0); +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM if(_libssh2_wincng.hAlgHashMD5) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0); +#endif if(_libssh2_wincng.hAlgHashSHA1) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0); if(_libssh2_wincng.hAlgHashSHA256) @@ -388,8 +540,10 @@ _libssh2_wincng_free(void) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA384, 0); if(_libssh2_wincng.hAlgHashSHA512) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0); +#if LIBSSH2_MD5 if(_libssh2_wincng.hAlgHmacMD5) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0); +#endif if(_libssh2_wincng.hAlgHmacSHA1) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0); if(_libssh2_wincng.hAlgHmacSHA256) @@ -411,33 +565,40 @@ _libssh2_wincng_free(void) if(_libssh2_wincng.hAlgDH) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDH, 0); +#if LIBSSH2_ECDSA + for(curve = 0; curve < ARRAY_SIZE(_wincng_ecdsa_algorithms); curve++) { + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgECDSA[curve], + 0); + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgECDH[curve], + 0); + } +#endif + memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); } int -_libssh2_wincng_random(void *buf, int len) +_libssh2_wincng_random(void *buf, size_t len) { int ret; - ret = BCryptGenRandom(_libssh2_wincng.hAlgRNG, buf, len, 0); + if(len > ULONG_MAX) { + return -1; + } + + ret = BCryptGenRandom(_libssh2_wincng.hAlgRNG, buf, (ULONG)len, 0); return BCRYPT_SUCCESS(ret) ? 0 : -1; } static void -_libssh2_wincng_safe_free(void *buf, int len) +_libssh2_wincng_safe_free(void *buf, size_t len) { -#ifndef LIBSSH2_CLEAR_MEMORY - (void)len; -#endif - if(!buf) return; -#ifdef LIBSSH2_CLEAR_MEMORY if(len > 0) - SecureZeroMemory(buf, len); -#endif + _libssh2_explicit_zero(buf, len); free(buf); } @@ -446,8 +607,8 @@ _libssh2_wincng_safe_free(void *buf, int len) * 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) +memcpy_with_be_padding(unsigned char *dest, ULONG dest_len, + unsigned char *src, ULONG src_len) { if(dest_len > src_len) { memset(dest, 0, dest_len - src_len); @@ -455,12 +616,6 @@ memcpy_with_be_padding(unsigned char *dest, unsigned long dest_len, memcpy((dest + dest_len) - src_len, src, src_len); } -static int -round_down(int number, int multiple) -{ - return (number / multiple) * multiple; -} - /*******************************************************************/ /* * Windows CNG backend: Hash functions @@ -468,12 +623,12 @@ round_down(int number, int multiple) int _libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, - BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen, - unsigned char *key, unsigned long keylen) + BCRYPT_ALG_HANDLE hAlg, ULONG hashlen, + unsigned char *key, ULONG keylen) { BCRYPT_HASH_HANDLE hHash; unsigned char *pbHashObject; - unsigned long dwHashObject, dwHash, cbData; + ULONG dwHashObject, dwHash, cbData; int ret; ret = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, @@ -517,11 +672,11 @@ _libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, int _libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx, - const unsigned char *data, unsigned long datalen) + const void *data, ULONG datalen) { int ret; - ret = BCryptHashData(ctx->hHash, (unsigned char *)data, datalen, 0); + ret = BCryptHashData(ctx->hHash, (PUCHAR)data, datalen, 0); return BCRYPT_SUCCESS(ret) ? 0 : -1; } @@ -545,9 +700,9 @@ _libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx, } int -_libssh2_wincng_hash(unsigned char *data, unsigned long datalen, +_libssh2_wincng_hash(const unsigned char *data, ULONG datalen, BCRYPT_ALG_HANDLE hAlg, - unsigned char *hash, unsigned long hashlen) + unsigned char *hash, ULONG hashlen) { _libssh2_wincng_hash_ctx ctx; int ret; @@ -567,19 +722,70 @@ _libssh2_wincng_hash(unsigned char *data, unsigned long datalen, * Windows CNG backend: HMAC functions */ -int -_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash) +int _libssh2_hmac_ctx_init(libssh2_hmac_ctx *ctx) { - int ret; - - ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; + memset(ctx, 0, sizeof(*ctx)); + return 1; } -void -_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx) +#if LIBSSH2_MD5 +int _libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + int ret = _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacMD5, + MD5_DIGEST_LENGTH, + key, (ULONG) keylen); + + return ret == 0 ? 1 : 0; +} +#endif + +int _libssh2_hmac_sha1_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + int ret = _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA1, + SHA_DIGEST_LENGTH, + key, (ULONG) keylen); + + return ret == 0 ? 1 : 0; +} + +int _libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + int ret = _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA256, + SHA256_DIGEST_LENGTH, + key, (ULONG) keylen); + + return ret == 0 ? 1 : 0; +} + +int _libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx, + void *key, size_t keylen) +{ + int ret = _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA512, + SHA512_DIGEST_LENGTH, + key, (ULONG) keylen); + + return ret == 0 ? 1 : 0; +} + +int _libssh2_hmac_update(libssh2_hmac_ctx *ctx, + const void *data, size_t datalen) +{ + int ret = _libssh2_wincng_hash_update(ctx, data, (ULONG) datalen); + + return ret == 0 ? 1 : 0; +} + +int _libssh2_hmac_final(libssh2_hmac_ctx *ctx, void *data) +{ + int ret = BCryptFinishHash(ctx->hHash, data, ctx->cbHash, 0); + + return BCRYPT_SUCCESS(ret) ? 1 : 0; +} + +void _libssh2_hmac_cleanup(libssh2_hmac_ctx *ctx) { BCryptDestroyHash(ctx->hHash); ctx->hHash = NULL; @@ -595,39 +801,58 @@ _libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx) * Windows CNG backend: Key functions */ -int -_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len, - unsigned long flags) +static int +_libssh2_wincng_key_sha_verify(_libssh2_wincng_key_ctx *ctx, + ULONG hashlen, + const unsigned char *sig, + ULONG sig_len, + const unsigned char *m, + ULONG m_len, + ULONG flags) { BCRYPT_PKCS1_PADDING_INFO paddingInfoPKCS1; + BCRYPT_ALG_HANDLE hAlgHash; void *pPaddingInfo; unsigned char *data, *hash; - unsigned long datalen, hashlen; + ULONG datalen; int ret; + if(hashlen == SHA_DIGEST_LENGTH) { + hAlgHash = _libssh2_wincng.hAlgHashSHA1; + paddingInfoPKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM; + } + else if(hashlen == SHA256_DIGEST_LENGTH) { + hAlgHash = _libssh2_wincng.hAlgHashSHA256; + paddingInfoPKCS1.pszAlgId = BCRYPT_SHA256_ALGORITHM; + } + else if(hashlen == SHA384_DIGEST_LENGTH) { + hAlgHash = _libssh2_wincng.hAlgHashSHA384; + paddingInfoPKCS1.pszAlgId = BCRYPT_SHA384_ALGORITHM; + } + else if(hashlen == SHA512_DIGEST_LENGTH) { + hAlgHash = _libssh2_wincng.hAlgHashSHA512; + paddingInfoPKCS1.pszAlgId = BCRYPT_SHA512_ALGORITHM; + } + else { + return -1; + } + datalen = m_len; data = malloc(datalen); if(!data) { return -1; } - hashlen = SHA_DIGEST_LENGTH; hash = malloc(hashlen); if(!hash) { free(data); return -1; } - memcpy(data, m, datalen); ret = _libssh2_wincng_hash(data, datalen, - _libssh2_wincng.hAlgHashSHA1, + hAlgHash, hash, hashlen); - _libssh2_wincng_safe_free(data, datalen); if(ret) { @@ -643,7 +868,6 @@ _libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, } if(flags & BCRYPT_PAD_PKCS1) { - paddingInfoPKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM; pPaddingInfo = &paddingInfoPKCS1; } else @@ -664,11 +888,11 @@ _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, - unsigned int *datalen) + size_t *datalen) { FILE *fp; int ret; @@ -690,13 +914,13 @@ _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, + size_t *pcbEncoded, int tryLoadRSA, int tryLoadDSA) { unsigned char *data = NULL; - unsigned int datalen = 0; + size_t datalen = 0; int ret = -1; if(ret && tryLoadRSA) { @@ -723,13 +947,13 @@ 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, + size_t *pcbEncoded, int tryLoadRSA, int tryLoadDSA) { unsigned char *data = NULL; - unsigned int datalen = 0; + size_t datalen = 0; int ret = -1; (void)passphrase; @@ -758,13 +982,13 @@ _libssh2_wincng_load_private_memory(LIBSSH2_SESSION *session, static int _libssh2_wincng_asn_decode(unsigned char *pbEncoded, - unsigned long cbEncoded, + DWORD cbEncoded, LPCSTR lpszStructType, unsigned char **ppbDecoded, - unsigned long *pcbDecoded) + DWORD *pcbDecoded) { unsigned char *pbDecoded = NULL; - unsigned long cbDecoded = 0; + DWORD cbDecoded = 0; int ret; ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, @@ -798,12 +1022,12 @@ _libssh2_wincng_asn_decode(unsigned char *pbEncoded, static int _libssh2_wincng_bn_ltob(unsigned char *pbInput, - unsigned long cbInput, + DWORD cbInput, unsigned char **ppbOutput, - unsigned long *pcbOutput) + DWORD *pcbOutput) { unsigned char *pbOutput; - unsigned long cbOutput, index, offset, length; + DWORD cbOutput, index, offset, length; if(cbInput < 1) { return 0; @@ -837,20 +1061,21 @@ _libssh2_wincng_bn_ltob(unsigned char *pbInput, static int _libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded, - unsigned long cbEncoded, + DWORD cbEncoded, unsigned char **ppbDecoded, - unsigned long *pcbDecoded) + DWORD *pcbDecoded) { - unsigned char *pbDecoded = NULL, *pbInteger; - unsigned long cbDecoded = 0, cbInteger; + unsigned char *pbDecoded = NULL; + PCRYPT_DATA_BLOB pbInteger; + DWORD cbDecoded = 0, cbInteger; int ret; ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, X509_MULTI_BYTE_UINT, - &pbInteger, &cbInteger); + (void *)&pbInteger, &cbInteger); if(!ret) { - ret = _libssh2_wincng_bn_ltob(((PCRYPT_DATA_BLOB)pbInteger)->pbData, - ((PCRYPT_DATA_BLOB)pbInteger)->cbData, + ret = _libssh2_wincng_bn_ltob(pbInteger->pbData, + pbInteger->cbData, &pbDecoded, &cbDecoded); if(!ret) { *ppbDecoded = pbDecoded; @@ -864,29 +1089,29 @@ _libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded, static int _libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded, - unsigned long cbEncoded, + DWORD cbEncoded, unsigned char ***prpbDecoded, - unsigned long **prcbDecoded, - unsigned long *pcbCount) + DWORD **prcbDecoded, + DWORD *pcbCount) { PCRYPT_DER_BLOB pBlob; - unsigned char *pbDecoded, **rpbDecoded; - unsigned long cbDecoded, *rcbDecoded, index, length; + unsigned char **rpbDecoded; + PCRYPT_SEQUENCE_OF_ANY pbDecoded; + DWORD cbDecoded, *rcbDecoded, index, length; int ret; ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, X509_SEQUENCE_OF_ANY, - &pbDecoded, &cbDecoded); + (void *)&pbDecoded, &cbDecoded); if(!ret) { - length = ((PCRYPT_DATA_BLOB)pbDecoded)->cbData; + length = pbDecoded->cValue; rpbDecoded = malloc(sizeof(PBYTE) * length); if(rpbDecoded) { rcbDecoded = malloc(sizeof(DWORD) * length); if(rcbDecoded) { for(index = 0; index < length; index++) { - pBlob = &((PCRYPT_DER_BLOB) - ((PCRYPT_DATA_BLOB)pbDecoded)->pbData)[index]; + pBlob = &pbDecoded->rgValue[index]; ret = _libssh2_wincng_asn_decode_bn(pBlob->pbData, pBlob->cbData, &rpbDecoded[index], @@ -927,11 +1152,11 @@ _libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded, } #endif /* HAVE_LIBCRYPT32 */ -static unsigned long -_libssh2_wincng_bn_size(const unsigned char *bignum, - unsigned long length) +#if LIBSSH2_RSA || LIBSSH2_DSA +static ULONG +_libssh2_wincng_bn_size(const unsigned char *bignum, ULONG length) { - unsigned long offset; + ULONG offset; if(!bignum) return 0; @@ -946,8 +1171,10 @@ _libssh2_wincng_bn_size(const unsigned char *bignum, return length - offset; } +#endif +#if LIBSSH2_RSA /*******************************************************************/ /* * Windows CNG backend: RSA functions @@ -975,8 +1202,7 @@ _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, BCRYPT_KEY_HANDLE hKey; BCRYPT_RSAKEY_BLOB *rsakey; LPCWSTR lpszBlobType; - unsigned char *key; - unsigned long keylen, offset, mlen, p1len = 0, p2len = 0; + ULONG keylen, offset, mlen, p1len = 0, p2len = 0; int ret; mlen = max(_libssh2_wincng_bn_size(ndata, nlen), @@ -991,65 +1217,76 @@ _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, keylen += p1len * 3 + p2len * 2 + mlen; } - key = malloc(keylen); - if(!key) { + rsakey = (BCRYPT_RSAKEY_BLOB *)malloc(keylen); + if(!rsakey) { return -1; } - memset(key, 0, keylen); + memset(rsakey, 0, keylen); /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ - rsakey = (BCRYPT_RSAKEY_BLOB *)key; rsakey->BitLength = mlen * 8; rsakey->cbPublicExp = elen; rsakey->cbModulus = mlen; - memcpy(key + offset, edata, elen); + memcpy((unsigned char *)rsakey + offset, edata, elen); offset += elen; if(nlen < mlen) - memcpy(key + offset + mlen - nlen, ndata, nlen); + memcpy((unsigned char *)rsakey + offset + mlen - nlen, ndata, nlen); else - memcpy(key + offset, ndata + nlen - mlen, mlen); + memcpy((unsigned char *)rsakey + offset, ndata + nlen - mlen, mlen); if(ddata && dlen > 0) { offset += mlen; if(plen < p1len) - memcpy(key + offset + p1len - plen, pdata, plen); + memcpy((unsigned char *)rsakey + offset + p1len - plen, + pdata, plen); else - memcpy(key + offset, pdata + plen - p1len, p1len); + memcpy((unsigned char *)rsakey + offset, + pdata + plen - p1len, p1len); offset += p1len; if(qlen < p2len) - memcpy(key + offset + p2len - qlen, qdata, qlen); + memcpy((unsigned char *)rsakey + offset + p2len - qlen, + qdata, qlen); else - memcpy(key + offset, qdata + qlen - p2len, p2len); + memcpy((unsigned char *)rsakey + offset, + qdata + qlen - p2len, p2len); offset += p2len; if(e1len < p1len) - memcpy(key + offset + p1len - e1len, e1data, e1len); + memcpy((unsigned char *)rsakey + offset + p1len - e1len, + e1data, e1len); else - memcpy(key + offset, e1data + e1len - p1len, p1len); + memcpy((unsigned char *)rsakey + offset, + e1data + e1len - p1len, p1len); offset += p1len; if(e2len < p2len) - memcpy(key + offset + p2len - e2len, e2data, e2len); + memcpy((unsigned char *)rsakey + offset + p2len - e2len, + e2data, e2len); else - memcpy(key + offset, e2data + e2len - p2len, p2len); + memcpy((unsigned char *)rsakey + offset, + e2data + e2len - p2len, p2len); offset += p2len; if(coefflen < p1len) - memcpy(key + offset + p1len - coefflen, coeffdata, coefflen); + memcpy((unsigned char *)rsakey + offset + p1len - coefflen, + coeffdata, coefflen); else - memcpy(key + offset, coeffdata + coefflen - p1len, p1len); + memcpy((unsigned char *)rsakey + offset, + coeffdata + coefflen - p1len, p1len); offset += p1len; if(dlen < mlen) - memcpy(key + offset + mlen - dlen, ddata, dlen); + memcpy((unsigned char *)rsakey + offset + mlen - dlen, + ddata, dlen); else - memcpy(key + offset, ddata + dlen - mlen, mlen); + memcpy((unsigned char *)rsakey + offset, + ddata + dlen - mlen, mlen); lpszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB; rsakey->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC; @@ -1065,9 +1302,9 @@ _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType, - &hKey, key, keylen, 0); + &hKey, (PUCHAR)rsakey, keylen, 0); if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(key, keylen); + _libssh2_wincng_safe_free(rsakey, keylen); return -1; } @@ -1075,12 +1312,12 @@ _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, *rsa = malloc(sizeof(libssh2_rsa_ctx)); if(!(*rsa)) { BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(key, keylen); + _libssh2_wincng_safe_free(rsakey, keylen); return -1; } (*rsa)->hKey = hKey; - (*rsa)->pbKeyObject = key; + (*rsa)->pbKeyObject = rsakey; (*rsa)->cbKeyObject = keylen; return 0; @@ -1091,16 +1328,16 @@ static int _libssh2_wincng_rsa_new_private_parse(libssh2_rsa_ctx **rsa, LIBSSH2_SESSION *session, unsigned char *pbEncoded, - unsigned long cbEncoded) + size_t cbEncoded) { BCRYPT_KEY_HANDLE hKey; unsigned char *pbStructInfo; - unsigned long cbStructInfo; + DWORD cbStructInfo; int ret; (void)session; - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, + ret = _libssh2_wincng_asn_decode(pbEncoded, (DWORD)cbEncoded, PKCS_RSA_PRIVATE_KEY, &pbStructInfo, &cbStructInfo); @@ -1143,13 +1380,12 @@ _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, { #ifdef HAVE_LIBCRYPT32 unsigned char *pbEncoded; - unsigned long cbEncoded; + size_t cbEncoded; int ret; (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,17 +1409,17 @@ _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; - unsigned long cbEncoded; + size_t cbEncoded; int ret; (void)session; ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, + passphrase, &pbEncoded, &cbEncoded, 1, 0); if(ret) { return -1; @@ -1203,38 +1439,69 @@ _libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, #endif /* HAVE_LIBCRYPT32 */ } +#if LIBSSH2_RSA_SHA1 int _libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa, const unsigned char *sig, - unsigned long sig_len, + size_t sig_len, const unsigned char *m, - unsigned long m_len) + size_t m_len) { - return _libssh2_wincng_key_sha1_verify(rsa, sig, sig_len, m, m_len, - BCRYPT_PAD_PKCS1); + return _libssh2_wincng_key_sha_verify(rsa, SHA_DIGEST_LENGTH, + sig, (ULONG)sig_len, + m, (ULONG)m_len, + BCRYPT_PAD_PKCS1); } +#endif +#if LIBSSH2_RSA_SHA2 int -_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len) +_libssh2_wincng_rsa_sha2_verify(libssh2_rsa_ctx *rsa, + size_t hash_len, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len) +{ + return _libssh2_wincng_key_sha_verify(rsa, (ULONG)hash_len, + sig, (ULONG)sig_len, + m, (ULONG)m_len, + BCRYPT_PAD_PKCS1); +} +#endif + +static int +_libssh2_wincng_rsa_sha_sign(LIBSSH2_SESSION *session, + libssh2_rsa_ctx *rsa, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, + size_t *signature_len) { BCRYPT_PKCS1_PADDING_INFO paddingInfo; unsigned char *data, *sig; - unsigned long cbData, datalen, siglen; - int ret; + ULONG cbData, datalen, siglen; + NTSTATUS ret; - datalen = (unsigned long)hash_len; + if(hash_len == SHA_DIGEST_LENGTH) + paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; + else if(hash_len == SHA256_DIGEST_LENGTH) + paddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM; + else if(hash_len == SHA384_DIGEST_LENGTH) + paddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM; + else if(hash_len == SHA512_DIGEST_LENGTH) + paddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM; + else { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unsupported hash digest length"); + return -1; + } + + datalen = (ULONG)hash_len; data = malloc(datalen); if(!data) { return -1; } - - paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; - memcpy(data, hash, datalen); ret = BCryptSignHash(rsa->hKey, &paddingInfo, @@ -1256,7 +1523,7 @@ _libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, } } else - ret = STATUS_NO_MEMORY; + ret = (NTSTATUS)STATUS_NO_MEMORY; } _libssh2_wincng_safe_free(data, datalen); @@ -1264,6 +1531,32 @@ _libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, return BCRYPT_SUCCESS(ret) ? 0 : -1; } +int +_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, + libssh2_rsa_ctx *rsa, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, + size_t *signature_len) +{ + return _libssh2_wincng_rsa_sha_sign(session, rsa, + hash, hash_len, + signature, signature_len); +} + +int +_libssh2_wincng_rsa_sha2_sign(LIBSSH2_SESSION *session, + libssh2_rsa_ctx *rsa, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, + size_t *signature_len) +{ + return _libssh2_wincng_rsa_sha_sign(session, rsa, + hash, hash_len, + signature, signature_len); +} + void _libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa) { @@ -1276,7 +1569,7 @@ _libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa) _libssh2_wincng_safe_free(rsa->pbKeyObject, rsa->cbKeyObject); _libssh2_wincng_safe_free(rsa, sizeof(libssh2_rsa_ctx)); } - +#endif /*******************************************************************/ /* @@ -1300,8 +1593,7 @@ _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, BCRYPT_KEY_HANDLE hKey; BCRYPT_DSA_KEY_BLOB *dsakey; LPCWSTR lpszBlobType; - unsigned char *key; - unsigned long keylen, offset, length; + ULONG keylen, offset, length; int ret; length = max(max(_libssh2_wincng_bn_size(pdata, plen), @@ -1312,16 +1604,15 @@ _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, if(xdata && xlen > 0) keylen += 20; - key = malloc(keylen); - if(!key) { + dsakey = (BCRYPT_DSA_KEY_BLOB *)malloc(keylen); + if(!dsakey) { return -1; } - memset(key, 0, keylen); + memset(dsakey, 0, keylen); /* https://msdn.microsoft.com/library/windows/desktop/aa833126.aspx */ - dsakey = (BCRYPT_DSA_KEY_BLOB *)key; dsakey->cbKey = length; memset(dsakey->Count, -1, sizeof(dsakey->Count)); @@ -1333,29 +1624,35 @@ _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, memcpy(dsakey->q, qdata + qlen - 20, 20); if(plen < length) - memcpy(key + offset + length - plen, pdata, plen); + memcpy((unsigned char *)dsakey + offset + length - plen, + pdata, plen); else - memcpy(key + offset, pdata + plen - length, length); + memcpy((unsigned char *)dsakey + offset, + pdata + plen - length, length); offset += length; if(glen < length) - memcpy(key + offset + length - glen, gdata, glen); + memcpy((unsigned char *)dsakey + offset + length - glen, + gdata, glen); else - memcpy(key + offset, gdata + glen - length, length); + memcpy((unsigned char *)dsakey + offset, + gdata + glen - length, length); offset += length; if(ylen < length) - memcpy(key + offset + length - ylen, ydata, ylen); + memcpy((unsigned char *)dsakey + offset + length - ylen, + ydata, ylen); else - memcpy(key + offset, ydata + ylen - length, length); + memcpy((unsigned char *)dsakey + offset, + ydata + ylen - length, length); if(xdata && xlen > 0) { offset += length; if(xlen < 20) - memcpy(key + offset + 20 - xlen, xdata, xlen); + memcpy((unsigned char *)dsakey + offset + 20 - xlen, xdata, xlen); else - memcpy(key + offset, xdata + xlen - 20, 20); + memcpy((unsigned char *)dsakey + offset, xdata + xlen - 20, 20); lpszBlobType = BCRYPT_DSA_PRIVATE_BLOB; dsakey->dwMagic = BCRYPT_DSA_PRIVATE_MAGIC; @@ -1367,9 +1664,9 @@ _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType, - &hKey, key, keylen, 0); + &hKey, (PUCHAR)dsakey, keylen, 0); if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(key, keylen); + _libssh2_wincng_safe_free(dsakey, keylen); return -1; } @@ -1377,12 +1674,12 @@ _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, *dsa = malloc(sizeof(libssh2_dsa_ctx)); if(!(*dsa)) { BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(key, keylen); + _libssh2_wincng_safe_free(dsakey, keylen); return -1; } (*dsa)->hKey = hKey; - (*dsa)->pbKeyObject = key; + (*dsa)->pbKeyObject = dsakey; (*dsa)->cbKeyObject = keylen; return 0; @@ -1393,15 +1690,15 @@ static int _libssh2_wincng_dsa_new_private_parse(libssh2_dsa_ctx **dsa, LIBSSH2_SESSION *session, unsigned char *pbEncoded, - unsigned long cbEncoded) + size_t cbEncoded) { unsigned char **rpbDecoded; - unsigned long *rcbDecoded, index, length; + DWORD *rcbDecoded, index, length; int ret; (void)session; - ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, + ret = _libssh2_wincng_asn_decode_bns(pbEncoded, (DWORD)cbEncoded, &rpbDecoded, &rcbDecoded, &length); _libssh2_wincng_safe_free(pbEncoded, cbEncoded); @@ -1444,11 +1741,10 @@ _libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, { #ifdef HAVE_LIBCRYPT32 unsigned char *pbEncoded; - unsigned long cbEncoded; + size_t 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,15 +1768,15 @@ _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; - unsigned long cbEncoded; + size_t cbEncoded; int ret; ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, + passphrase, &pbEncoded, &cbEncoded, 0, 1); if(ret) { return -1; @@ -1504,22 +1800,23 @@ int _libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa, const unsigned char *sig_fixed, const unsigned char *m, - unsigned long m_len) + size_t m_len) { - return _libssh2_wincng_key_sha1_verify(dsa, sig_fixed, 40, m, m_len, 0); + return _libssh2_wincng_key_sha_verify(dsa, SHA_DIGEST_LENGTH, sig_fixed, + 40, m, (ULONG)m_len, 0); } int _libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, const unsigned char *hash, - unsigned long hash_len, + size_t hash_len, unsigned char *sig_fixed) { unsigned char *data, *sig; - unsigned long cbData, datalen, siglen; - int ret; + ULONG cbData, datalen, siglen; + NTSTATUS ret; - datalen = hash_len; + datalen = (ULONG)hash_len; data = malloc(datalen); if(!data) { return -1; @@ -1543,10 +1840,10 @@ _libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, _libssh2_wincng_safe_free(sig, siglen); } else - ret = STATUS_NO_MEMORY; + ret = (NTSTATUS)STATUS_NO_MEMORY; } else - ret = STATUS_NO_MEMORY; + ret = (NTSTATUS)STATUS_NO_MEMORY; } _libssh2_wincng_safe_free(data, datalen); @@ -1569,17 +1866,1227 @@ _libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa) #endif +/*******************************************************************/ +/* + * Windows CNG backend: ECDSA helper functions + */ + +#if LIBSSH2_ECDSA + +/* + * Decode an uncompressed point. + */ +static int +_libssh2_wincng_ecdsa_decode_uncompressed_point( + IN const unsigned char *encoded_point, + IN size_t encoded_point_len, + OUT _libssh2_ecdsa_point *point) +{ + unsigned int curve; + + if(!point) { + return LIBSSH2_ERROR_INVAL; + } + + /* Verify that the point uses uncompressed format */ + if(encoded_point_len == 0 || encoded_point[0] != 4) { + return LIBSSH2_ERROR_INVAL; + } + + for(curve = 0; curve < ARRAY_SIZE(_wincng_ecdsa_algorithms); curve++) { + if(_wincng_ecdsa_algorithms[curve].point_length == + (encoded_point_len - 1) / 2) { + + point->curve = curve; + + point->x = encoded_point + 1; + point->x_len = _wincng_ecdsa_algorithms[curve].point_length; + + point->y = point->x + point->x_len; + point->y_len = _wincng_ecdsa_algorithms[curve].point_length; + + return LIBSSH2_ERROR_NONE; + } + } + + return LIBSSH2_ERROR_INVAL; +} + +/* + * Create a IEEE P-1363 signature from a point. + * + * The IEEE P-1363 format is defined as r || s, + * where r and s are of the same length. + */ +static int +_libssh2_wincng_p1363signature_from_point(IN const unsigned char *r, + IN size_t r_len, + IN const unsigned char *s, + IN size_t s_len, + IN libssh2_curve_type curve, + OUT PUCHAR *signature, + OUT size_t *signature_length) +{ + const unsigned char *r_trimmed; + const unsigned char *s_trimmed; + size_t r_trimmed_len; + size_t s_trimmed_len; + + /* Validate parameters */ + if(curve >= ARRAY_SIZE(_wincng_ecdsa_algorithms)) { + return LIBSSH2_ERROR_INVAL; + } + + *signature = NULL; + *signature_length = (size_t) + _wincng_ecdsa_algorithms[curve].point_length * 2; + + /* Trim leading zero, if any */ + r_trimmed = r; + r_trimmed_len = r_len; + if(r_len > 0 && r[0] == '\0') { + r_trimmed++; + r_trimmed_len--; + } + + s_trimmed = s; + s_trimmed_len = s_len; + if(s_len > 0 && s[0] == '\0') { + s_trimmed++; + s_trimmed_len--; + } + + /* Concatenate into zero-filled buffer and zero-pad if necessary */ + *signature = calloc(1, *signature_length); + if(!*signature) { + return LIBSSH2_ERROR_ALLOC; + } + + memcpy( + *signature + (*signature_length / 2) - r_trimmed_len, + r_trimmed, + r_trimmed_len); + memcpy( + *signature + (*signature_length) - s_trimmed_len, + s_trimmed, + s_trimmed_len); + + return LIBSSH2_ERROR_NONE; +} + +/* + * Create a CNG public key from an ECC point. + */ +static int +_libssh2_wincng_publickey_from_point(IN _libssh2_wincng_ecc_keytype keytype, + IN _libssh2_ecdsa_point *point, + OUT BCRYPT_KEY_HANDLE *key) +{ + + int result = LIBSSH2_ERROR_NONE; + NTSTATUS status; + + PBCRYPT_ECCKEY_BLOB ecc_blob; + size_t ecc_blob_len; + + /* Validate parameters */ + if(!key) { + return LIBSSH2_ERROR_INVAL; + } + + if(point->x_len != point->y_len) { + return LIBSSH2_ERROR_INVAL; + } + + *key = NULL; + + /* Initialize a blob to import */ + ecc_blob_len = sizeof(BCRYPT_ECCKEY_BLOB) + point->x_len + point->y_len; + ecc_blob = malloc(ecc_blob_len); + if(!ecc_blob) { + return LIBSSH2_ERROR_ALLOC; + } + + ecc_blob->cbKey = point->x_len; + ecc_blob->dwMagic = + _wincng_ecdsa_algorithms[point->curve].public_import_magic[keytype]; + + /** Copy x, y */ + memcpy( + (PUCHAR)ecc_blob + sizeof(BCRYPT_ECCKEY_BLOB), + point->x, + point->x_len); + memcpy( + (PUCHAR)ecc_blob + sizeof(BCRYPT_ECCKEY_BLOB) + point->x_len, + point->y, + point->y_len); + + status = BCryptImportKeyPair( + keytype == WINCNG_ECC_KEYTYPE_ECDSA + ? _libssh2_wincng.hAlgECDSA[point->curve] + : _libssh2_wincng.hAlgECDH[point->curve], + NULL, + BCRYPT_ECCPUBLIC_BLOB, + key, + (PUCHAR)ecc_blob, + (ULONG)ecc_blob_len, + 0); + if(!BCRYPT_SUCCESS(status)) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + + result = LIBSSH2_ERROR_NONE; + +cleanup: + free(ecc_blob); + return result; +} + +/* + * Create a CNG private key from an ECC point. + */ +static int +_libssh2_wincng_privatekey_from_point(IN _libssh2_wincng_ecc_keytype keytype, + IN _libssh2_ecdsa_point *q, + IN unsigned char *d, + IN size_t d_len, + OUT BCRYPT_KEY_HANDLE *key) +{ + int result = LIBSSH2_ERROR_NONE; + NTSTATUS status; + + PBCRYPT_ECCKEY_BLOB ecc_blob; + size_t ecc_blob_len; + + /* Validate parameters */ + if(!key) { + return LIBSSH2_ERROR_INVAL; + } + + if(q->x_len != q->y_len) { + return LIBSSH2_ERROR_INVAL; + } + + *key = NULL; + + /* Initialize a blob to import */ + ecc_blob_len = + sizeof(BCRYPT_ECCPRIVATE_BLOB) + q->x_len + q->y_len + d_len; + ecc_blob = malloc(ecc_blob_len); + if(!ecc_blob) { + return LIBSSH2_ERROR_ALLOC; + } + + ecc_blob->cbKey = q->x_len; + ecc_blob->dwMagic = + _wincng_ecdsa_algorithms[q->curve].private_import_magic[keytype]; + + /* Copy x, y, d */ + memcpy( + (PUCHAR)ecc_blob + sizeof(BCRYPT_ECCKEY_BLOB), + q->x, + q->x_len); + memcpy( + (PUCHAR)ecc_blob + sizeof(BCRYPT_ECCKEY_BLOB) + q->x_len, + q->y, + q->y_len); + memcpy( + (PUCHAR)ecc_blob + sizeof(BCRYPT_ECCKEY_BLOB) + q->x_len + q->y_len, + d, + d_len); + + status = BCryptImportKeyPair( + keytype == WINCNG_ECC_KEYTYPE_ECDSA + ? _libssh2_wincng.hAlgECDSA[q->curve] + : _libssh2_wincng.hAlgECDH[q->curve], + NULL, + BCRYPT_ECCPRIVATE_BLOB, + key, + (PUCHAR)ecc_blob, + (ULONG)ecc_blob_len, + 0); + if(!BCRYPT_SUCCESS(status)) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + + result = LIBSSH2_ERROR_NONE; + +cleanup: + free(ecc_blob); + return result; +} + +/* + * Get the uncompressed point encoding for a CNG key. + */ +static int +_libssh2_wincng_uncompressed_point_from_publickey( + IN LIBSSH2_SESSION *session, + IN libssh2_curve_type curve, + IN BCRYPT_KEY_HANDLE key, + OUT PUCHAR *encoded_point, + OUT size_t *encoded_point_len) +{ + int result = LIBSSH2_ERROR_NONE; + NTSTATUS status; + + PBCRYPT_ECCKEY_BLOB ecc_blob = NULL; + ULONG ecc_blob_len; + PUCHAR point_x; + PUCHAR point_y; + + /* Validate parameters */ + if(curve >= ARRAY_SIZE(_wincng_ecdsa_algorithms)) { + return LIBSSH2_ERROR_INVAL; + } + + if(!encoded_point || !encoded_point_len) { + return LIBSSH2_ERROR_INVAL; + } + + *encoded_point = NULL; + *encoded_point_len = 0; + + /* + * Export point as BCRYPT_ECCKEY_BLOB, a dynamically-sized structure. + */ + status = BCryptExportKey(key, + NULL, + BCRYPT_ECCPUBLIC_BLOB, + NULL, + 0, + &ecc_blob_len, + 0); + if(BCRYPT_SUCCESS(status) && ecc_blob_len > 0) { + ecc_blob = LIBSSH2_ALLOC(session, ecc_blob_len); + if(!ecc_blob) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + status = BCryptExportKey(key, + NULL, + BCRYPT_ECCPUBLIC_BLOB, + (PUCHAR)ecc_blob, + ecc_blob_len, + &ecc_blob_len, + 0); + } + + if(!BCRYPT_SUCCESS(status)) { + result = _libssh2_error(session, + LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Decoding the ECC public key failed"); + goto cleanup; + } + + point_x = (PUCHAR)ecc_blob + sizeof(BCRYPT_ECCKEY_BLOB); + point_y = (PUCHAR)ecc_blob + ecc_blob->cbKey + sizeof(BCRYPT_ECCKEY_BLOB); + + /* + * Create uncompressed point, which needs to look like the following: + * + * struct uncompressed_point { + * UCHAR tag = 4; // uncompressed + * PUCHAR[size] x; + * PUCHAR[size] y; + * } + */ + + *encoded_point_len = (size_t)ecc_blob->cbKey * 2 + 1; + *encoded_point = LIBSSH2_ALLOC(session, *encoded_point_len); + if(!*encoded_point) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + **encoded_point = 4; /* Uncompressed tag */ + memcpy((*encoded_point) + 1, point_x, ecc_blob->cbKey); + memcpy((*encoded_point) + 1 + ecc_blob->cbKey, point_y, ecc_blob->cbKey); + +cleanup: + if(ecc_blob) { + LIBSSH2_FREE(session, ecc_blob); + } + + return result; +} + +static void +_libssh_wincng_reverse_bytes(IN PUCHAR buffer, + IN size_t buffer_len) +{ + PUCHAR start = buffer; + PUCHAR end = buffer + buffer_len - 1; + while(start < end) { + unsigned char tmp = *end; + *end = *start; + *start = tmp; + start++; + end--; + } +} + +/*******************************************************************/ +/* + * Windows CNG backend: ECDSA functions + */ + +void +_libssh2_wincng_ecdsa_free(IN _libssh2_wincng_ecdsa_key *key) +{ + if(!key) { + return; + } + + (void)BCryptDestroyKey(key->handle); + free(key); +} + + +/* + * _libssh2_ecdsa_create_key + * + * Creates a local private ECDH key based on input curve + * and returns the public key in uncompressed point encoding. + */ + +int +_libssh2_wincng_ecdh_create_key(IN LIBSSH2_SESSION *session, + OUT _libssh2_wincng_ecdsa_key **privatekey, + OUT unsigned char **encoded_publickey, + OUT size_t *encoded_publickey_len, + IN libssh2_curve_type curve) +{ + int result = LIBSSH2_ERROR_NONE; + NTSTATUS status; + + BCRYPT_KEY_HANDLE key_handle = NULL; + + /* Validate parameters */ + if(curve >= ARRAY_SIZE(_wincng_ecdsa_algorithms)) { + return LIBSSH2_ERROR_INVAL; + } + + if(!_libssh2_wincng.hAlgECDH[curve]) { + return LIBSSH2_ERROR_INVAL; + } + + if(!privatekey || !encoded_publickey || !encoded_publickey_len) { + return LIBSSH2_ERROR_INVAL; + } + + *privatekey = NULL; + *encoded_publickey = NULL; + *encoded_publickey_len = 0; + + /* Create an ECDH key pair using the requested curve */ + status = BCryptGenerateKeyPair( + _libssh2_wincng.hAlgECDH[curve], + &key_handle, + _wincng_ecdsa_algorithms[curve].key_length, + 0); + if(!BCRYPT_SUCCESS(status)) { + result = _libssh2_error( + session, + LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Creating ECC key pair failed"); + goto cleanup; + } + + status = BCryptFinalizeKeyPair(key_handle, 0); + if(!BCRYPT_SUCCESS(status)) { + result = _libssh2_error( + session, + LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Creating ECDH key pair failed"); + goto cleanup; + } + + result = _libssh2_wincng_uncompressed_point_from_publickey( + session, + curve, + key_handle, + encoded_publickey, + encoded_publickey_len); + if(result != LIBSSH2_ERROR_NONE) { + result = _libssh2_error( + session, + LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Exporting ECDH key pair failed"); + } + + *privatekey = malloc(sizeof(_libssh2_wincng_ecdsa_key)); + if(!*privatekey) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + (*privatekey)->curve = curve; + (*privatekey)->handle = key_handle; + +cleanup: + if(result != LIBSSH2_ERROR_NONE && key_handle) { + (void)BCryptDestroyKey(key_handle); + } + + if(result != LIBSSH2_ERROR_NONE && *privatekey) { + free(*privatekey); + } + + return result; +} + +/* + * _libssh2_ecdsa_curve_name_with_octal_new + * + * Creates an ECDSA public key from an uncompressed point. + */ + +int +_libssh2_wincng_ecdsa_curve_name_with_octal_new( + OUT _libssh2_wincng_ecdsa_key **key, + IN const unsigned char *publickey_encoded, + IN size_t publickey_encoded_len, + IN libssh2_curve_type curve) +{ + int result = LIBSSH2_ERROR_NONE; + + BCRYPT_KEY_HANDLE publickey_handle; + _libssh2_ecdsa_point publickey; + + /* Validate parameters */ + if(curve >= ARRAY_SIZE(_wincng_ecdsa_algorithms)) { + return LIBSSH2_ERROR_INVAL; + } + + if(!key) { + return LIBSSH2_ERROR_INVAL; + } + + *key = NULL; + + result = _libssh2_wincng_ecdsa_decode_uncompressed_point( + publickey_encoded, + publickey_encoded_len, + &publickey); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + result = _libssh2_wincng_publickey_from_point( + WINCNG_ECC_KEYTYPE_ECDSA, + &publickey, + &publickey_handle); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + *key = malloc(sizeof(_libssh2_wincng_ecdsa_key)); + if(!*key) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + (*key)->handle = publickey_handle; + (*key)->curve = curve; + +cleanup: + + return result; +} + +/* + * _libssh2_ecdh_gen_k + * + * Computes the shared secret K given a local private key, + * remote public key and length + */ + +int +_libssh2_wincng_ecdh_gen_k(OUT _libssh2_bn **secret, + IN _libssh2_wincng_ecdsa_key *privatekey, + IN const unsigned char *server_publickey_encoded, + IN size_t server_publickey_encoded_len) +{ + int result = LIBSSH2_ERROR_NONE; + NTSTATUS status; + + BCRYPT_KEY_HANDLE publickey_handle; + BCRYPT_SECRET_HANDLE agreed_secret_handle = NULL; + ULONG secret_len; + _libssh2_ecdsa_point server_publickey; + + /* Validate parameters */ + if(!secret) { + return LIBSSH2_ERROR_INVAL; + } + + *secret = NULL; + + /* Decode the public key */ + result = _libssh2_wincng_ecdsa_decode_uncompressed_point( + server_publickey_encoded, + server_publickey_encoded_len, + &server_publickey); + if(result != LIBSSH2_ERROR_NONE) { + return result; + } + + result = _libssh2_wincng_publickey_from_point( + WINCNG_ECC_KEYTYPE_ECDH, + &server_publickey, + &publickey_handle); + if(result != LIBSSH2_ERROR_NONE) { + return result; + } + + /* Establish the shared secret between ourselves and the peer */ + status = BCryptSecretAgreement( + privatekey->handle, + publickey_handle, + &agreed_secret_handle, + 0); + if(!BCRYPT_SUCCESS(status)) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + + /* Compute the size of the buffer that is needed to hold the derived + * shared secret. + * + * NB. The use of BCRYPT_KDF_RAW_SECRET requires Windows 10 or newer. + * On older versions, the BCryptDeriveKey returns STATUS_NOT_SUPPORTED. + */ + status = BCryptDeriveKey( + agreed_secret_handle, + BCRYPT_KDF_RAW_SECRET, + NULL, + NULL, + 0, + &secret_len, + 0); + if(!BCRYPT_SUCCESS(status)) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + + /* Allocate a secret bignum to be ready to receive the derived secret */ + *secret = _libssh2_wincng_bignum_init(); + if(!*secret) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + if(_libssh2_wincng_bignum_resize(*secret, secret_len)) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + /* And populate the secret bignum */ + status = BCryptDeriveKey( + agreed_secret_handle, + BCRYPT_KDF_RAW_SECRET, + NULL, + (*secret)->bignum, + secret_len, + &secret_len, + 0); + if(!BCRYPT_SUCCESS(status)) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + + /* BCRYPT_KDF_RAW_SECRET returns the little-endian representation of the + * raw secret, so we need to swap it to big endian order. + */ + + _libssh_wincng_reverse_bytes((*secret)->bignum, secret_len); + + result = LIBSSH2_ERROR_NONE; + +cleanup: + if(result != LIBSSH2_ERROR_NONE && agreed_secret_handle) { + _libssh2_wincng_bignum_free(*secret); + } + + if(result != LIBSSH2_ERROR_NONE && agreed_secret_handle) { + BCryptDestroySecret(agreed_secret_handle); + } + + return result; +} + +/* + * _libssh2_ecdsa_curve_type_from_name + * + */ +int +_libssh2_wincng_ecdsa_curve_type_from_name(IN const char *name, + OUT libssh2_curve_type *out_curve) +{ + unsigned int curve; + + /* Validate parameters */ + if(!out_curve) { + return LIBSSH2_ERROR_INVAL; + } + + for(curve = 0; curve < ARRAY_SIZE(_wincng_ecdsa_algorithms); curve++) { + if(strcmp(name, _wincng_ecdsa_algorithms[curve].name) == 0) { + *out_curve = curve; + return LIBSSH2_ERROR_NONE; + } + } + + return LIBSSH2_ERROR_INVAL; +} + +/* + * _libssh2_ecdsa_verify + * + * Verifies the ECDSA signature of a hashed message + * + */ + +int +_libssh2_wincng_ecdsa_verify(IN _libssh2_wincng_ecdsa_key *key, + IN const unsigned char *r, + IN size_t r_len, + IN const unsigned char *s, + IN size_t s_len, + IN const unsigned char *m, + IN size_t m_len) +{ + int result = LIBSSH2_ERROR_NONE; + NTSTATUS status; + + PUCHAR signature_p1363 = NULL; + size_t signature_p1363_len; + ULONG hash_len; + PUCHAR hash = NULL; + BCRYPT_ALG_HANDLE hash_alg; + + /* CNG expects signatures in IEEE P-1363 format. */ + result = _libssh2_wincng_p1363signature_from_point( + r, + r_len, + s, + s_len, + _libssh2_wincng_ecdsa_get_curve_type(key), + &signature_p1363, + &signature_p1363_len); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + /* Create hash over m */ + switch(_libssh2_wincng_ecdsa_get_curve_type(key)) { + case LIBSSH2_EC_CURVE_NISTP256: + hash_len = 256/8; + hash_alg = _libssh2_wincng.hAlgHashSHA256; + break; + + case LIBSSH2_EC_CURVE_NISTP384: + hash_len = 384/8; + hash_alg = _libssh2_wincng.hAlgHashSHA384; + break; + + case LIBSSH2_EC_CURVE_NISTP521: + hash_len = 512/8; + hash_alg = _libssh2_wincng.hAlgHashSHA512; + break; + + default: + return LIBSSH2_ERROR_INVAL; + } + + hash = malloc(hash_len); + result = _libssh2_wincng_hash( + m, + (ULONG)m_len, + hash_alg, + hash, + hash_len); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + /* Verify signature over hash */ + status = BCryptVerifySignature( + key->handle, + NULL, + hash, + hash_len, + signature_p1363, + (ULONG)signature_p1363_len, + 0); + + if(status == STATUS_INVALID_SIGNATURE) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + else if(!BCRYPT_SUCCESS(status)) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + + result = LIBSSH2_ERROR_NONE; + +cleanup: + if(hash) { + free(hash); + } + + if(signature_p1363) { + free(signature_p1363); + } + + return result; +} + +/* + *_libssh2_ecdsa_new_private + * + * Creates a new private key given a file path and password + * + */ + +int +_libssh2_wincng_ecdsa_new_private(OUT _libssh2_wincng_ecdsa_key **key, + IN LIBSSH2_SESSION *session, + IN const char *filename, + IN const unsigned char *passphrase) +{ + int result; + + FILE *file_handle = NULL; + unsigned char *data = NULL; + size_t datalen = 0; + + /* Validate parameters */ + if(!key || !session || !filename) { + return LIBSSH2_ERROR_INVAL; + } + + *key = NULL; + + if(passphrase && strlen((const char *)passphrase) > 0) { + return _libssh2_error( + session, + LIBSSH2_ERROR_INVAL, + "Passphrase-protected ECDSA private key files are unsupported"); + } + + file_handle = fopen(filename, FOPEN_READTEXT); + if(!file_handle) { + result = _libssh2_error( + session, + LIBSSH2_ERROR_INVAL, + "Opening the private key file failed"); + goto cleanup; + } + + result = _libssh2_pem_parse(session, + PEM_ECDSA_HEADER, + PEM_ECDSA_FOOTER, + passphrase, + file_handle, + &data, + &datalen); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + result = _libssh2_wincng_ecdsa_new_private_frommemory( + key, + session, + (const char *)data, + datalen, + passphrase); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + +cleanup: + if(file_handle) { + fclose(file_handle); + } + + if(data) { + LIBSSH2_FREE(session, data); + } + + return result; +} + +int +_libssh2_wincng_parse_ecdsa_privatekey(OUT _libssh2_wincng_ecdsa_key **key, + IN unsigned char *privatekey, + IN size_t privatekey_len) +{ + char *keytype = NULL; + size_t keytype_len; + + unsigned char *ignore; + size_t ignore_len; + + unsigned char *publickey; + size_t publickey_len; + + libssh2_curve_type curve_type; + int result; + uint32_t check1, check2; + struct string_buf data_buffer; + + _libssh2_ecdsa_point q; + unsigned char *d; + size_t d_len; + + BCRYPT_KEY_HANDLE key_handle = NULL; + + *key = NULL; + + data_buffer.data = privatekey; + data_buffer.dataptr = privatekey; + data_buffer.len = privatekey_len; + + /* Read the 2 checkints and check that they match */ + result = _libssh2_get_u32(&data_buffer, &check1); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + result = _libssh2_get_u32(&data_buffer, &check2); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + if(check1 != check2) { + result = LIBSSH2_ERROR_FILE; + goto cleanup; + } + + /* What follows is a key as defined in */ + /* draft-miller-ssh-agent, section-3.2.2 */ + + /* Read the key type */ + result = _libssh2_get_string(&data_buffer, + (unsigned char **)&keytype, + &keytype_len); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + result = _libssh2_wincng_ecdsa_curve_type_from_name(keytype, &curve_type); + if(result < 0) { + goto cleanup; + } + + /* Read the curve */ + result = _libssh2_get_string(&data_buffer, &ignore, &ignore_len); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + /* Read Q */ + result = _libssh2_get_string(&data_buffer, &publickey, &publickey_len); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + result = _libssh2_wincng_ecdsa_decode_uncompressed_point( + publickey, + publickey_len, + &q); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + /* Read d */ + result = _libssh2_get_bignum_bytes(&data_buffer, &d, &d_len); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + /* Ignore the rest (comment, etc) */ + + /* Use Q and d to create a key handle */ + result = _libssh2_wincng_privatekey_from_point( + WINCNG_ECC_KEYTYPE_ECDSA, + &q, + d, + d_len, + &key_handle); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + *key = malloc(sizeof(_libssh2_wincng_ecdsa_key)); + if(!*key) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + (*key)->curve = q.curve; + (*key)->handle = key_handle; + + result = LIBSSH2_ERROR_NONE; + +cleanup: + if(result != LIBSSH2_ERROR_NONE && key_handle) { + (void)BCryptDestroyKey(key_handle); + } + + return result; +} + +/* + * _libssh2_ecdsa_new_private + * + * Creates a new private key given a file data and password. + * ECDSA private key files use the decoding defined in PROTOCOL.key + * in the OpenSSL source tree. + */ +int +_libssh2_wincng_ecdsa_new_private_frommemory( + OUT _libssh2_wincng_ecdsa_key **key, + IN LIBSSH2_SESSION *session, + IN const char *data, + IN size_t data_len, + IN const unsigned char *passphrase) +{ + int result; + + struct string_buf data_buffer; + uint32_t index; + uint32_t key_count; + unsigned char *privatekey; + size_t privatekey_len; + + /* Validate parameters */ + if(!key || !session || !data) { + return LIBSSH2_ERROR_INVAL; + } + + *key = NULL; + + if(passphrase && strlen((const char *)passphrase) > 0) { + return _libssh2_error( + session, + LIBSSH2_ERROR_INVAL, + "Passphrase-protected ECDSA private key files are unsupported"); + } + + /* Read OPENSSL_PRIVATEKEY_AUTH_MAGIC */ + if(strncmp(data, OPENSSL_PRIVATEKEY_AUTH_MAGIC, data_len) != 0) { + result = -1; + goto cleanup; + } + + data_buffer.len = data_len; + data_buffer.data = (unsigned char *)data; + data_buffer.dataptr = + (unsigned char *)data + strlen(OPENSSL_PRIVATEKEY_AUTH_MAGIC) + 1; + + /* Read ciphername, should be 'none' as we don't support passphrases */ + result = _libssh2_match_string(&data_buffer, "none"); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + /* Read kdfname, should be 'none' as we don't support passphrases */ + result = _libssh2_match_string(&data_buffer, "none"); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + /* Read kdfoptions, should be empty */ + result = _libssh2_match_string(&data_buffer, ""); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + /* Read number of keys N */ + result = _libssh2_get_u32(&data_buffer, &key_count); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + if(key_count == 0) { + result = LIBSSH2_ERROR_FILE; + goto cleanup; + } + + /* Skip all public keys */ + for(index = 0; index < key_count; index++) { + unsigned char *publickey; + size_t publickey_len; + + result = _libssh2_get_string(&data_buffer, &publickey, &publickey_len); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + } + + /* Read first private key */ + result = _libssh2_get_string(&data_buffer, &privatekey, &privatekey_len); + if(result != LIBSSH2_ERROR_NONE) { + goto cleanup; + } + + result = _libssh2_wincng_parse_ecdsa_privatekey( + key, + privatekey, + privatekey_len); + +cleanup: + if(result != LIBSSH2_ERROR_NONE) { + return _libssh2_error( + session, + result, + "The key is malformed"); + } + + return result; +} + +/* + * _libssh2_ecdsa_sign + * + * Computes the ECDSA signature of a previously-hashed message + * + */ + +int +_libssh2_wincng_ecdsa_sign(IN LIBSSH2_SESSION *session, + IN _libssh2_wincng_ecdsa_key *key, + IN const unsigned char *hash, + IN size_t hash_len, + OUT unsigned char **signature, + OUT size_t *signature_len) +{ + NTSTATUS status; + int result = LIBSSH2_ERROR_NONE; + + unsigned char *hash_buffer; + + unsigned char *cng_signature = NULL; + ULONG cng_signature_len; + + ULONG signature_maxlen; + unsigned char *signature_ptr; + + *signature = NULL; + *signature_len = 0; + + /* CNG expects a mutable buffer */ + hash_buffer = malloc(hash_len); + if(!hash_buffer) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + memcpy(hash_buffer, hash, hash_len); + + status = BCryptSignHash( + key->handle, + NULL, + hash_buffer, + (ULONG)hash_len, + NULL, + 0, + &cng_signature_len, + 0); + if(!BCRYPT_SUCCESS(status)) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + + cng_signature = malloc(cng_signature_len); + if(!cng_signature) { + result = LIBSSH2_ERROR_ALLOC; + goto cleanup; + } + + status = BCryptSignHash( + key->handle, + NULL, + hash_buffer, + (ULONG)hash_len, + cng_signature, + cng_signature_len, + &cng_signature_len, + 0); + if(!BCRYPT_SUCCESS(status)) { + result = LIBSSH2_ERROR_PUBLICKEY_PROTOCOL; + goto cleanup; + } + + /* + cng_signature is in IEEE P-1163 format: r || s. + Convert to ecdsa_signature_blob: mpint(r) || mpint(s) + */ + + signature_maxlen = + cng_signature_len / 2 + 5 + /* mpint(r) */ + cng_signature_len / 2 + 5; /* mpint(s) */ + + *signature = LIBSSH2_ALLOC(session, signature_maxlen); + signature_ptr = *signature; + + _libssh2_store_bignum2_bytes( + &signature_ptr, + cng_signature, + cng_signature_len / 2); + + _libssh2_store_bignum2_bytes( + &signature_ptr, + cng_signature + (cng_signature_len / 2), + cng_signature_len / 2); + + *signature_len = signature_ptr - *signature; + +cleanup: + if(cng_signature) { + free(cng_signature); + } + + if(hash_buffer) { + free(hash_buffer); + } + + return result; +} + +/* + * _libssh2_ecdsa_get_curve_type + * + * returns key curve type that maps to libssh2_curve_type + * + */ + +libssh2_curve_type +_libssh2_wincng_ecdsa_get_curve_type(IN _libssh2_wincng_ecdsa_key *key) +{ + return key->curve; +} + +#endif + /*******************************************************************/ /* * Windows CNG backend: Key functions */ #ifdef HAVE_LIBCRYPT32 -static unsigned long +static DWORD _libssh2_wincng_pub_priv_write(unsigned char *key, - unsigned long offset, + DWORD offset, const unsigned char *bignum, - const unsigned long length) + const DWORD length) { _libssh2_htonu32(key + offset, length); offset += 4; @@ -1597,16 +3104,16 @@ _libssh2_wincng_pub_priv_keyfile_parse(LIBSSH2_SESSION *session, unsigned char **pubkeydata, size_t *pubkeydata_len, unsigned char *pbEncoded, - unsigned long cbEncoded) + size_t cbEncoded) { - unsigned char **rpbDecoded; - unsigned long *rcbDecoded; + unsigned char **rpbDecoded = NULL; + DWORD *rcbDecoded = NULL; unsigned char *key = NULL, *mth = NULL; - unsigned long keylen = 0, mthlen = 0; - unsigned long index, offset, length; + DWORD keylen = 0, mthlen = 0; + DWORD index, offset, length = 0; int ret; - ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, + ret = _libssh2_wincng_asn_decode_bns(pbEncoded, (DWORD)cbEncoded, &rpbDecoded, &rcbDecoded, &length); _libssh2_wincng_safe_free(pbEncoded, cbEncoded); @@ -1725,10 +3232,11 @@ _libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, { #ifdef HAVE_LIBCRYPT32 unsigned char *pbEncoded; - unsigned long cbEncoded; + size_t 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; @@ -1763,11 +3271,13 @@ _libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session, { #ifdef HAVE_LIBCRYPT32 unsigned char *pbEncoded; - unsigned long cbEncoded; + size_t cbEncoded; 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; @@ -1786,11 +3296,44 @@ _libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session, (void)passphrase; return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract public key from private key in memory: " - "Method unsupported in Windows CNG backend"); + "Unable to extract public key from private key in memory: " + "Method unsupported in Windows CNG backend"); #endif /* HAVE_LIBCRYPT32 */ } +int +_libssh2_wincng_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) +{ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)algorithm; + (void)flags; + (void)application; + (void)key_handle; + (void)handle_len; + (void)privatekeydata; + (void)privatekeydata_len; + (void)passphrase; + + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public SK key from private key file: " + "Method unimplemented in Windows CNG backend"); +} + /*******************************************************************/ /* * Windows CNG backend: Cipher functions @@ -1805,9 +3348,8 @@ _libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, { BCRYPT_KEY_HANDLE hKey; BCRYPT_KEY_DATA_BLOB_HEADER *header; - unsigned char *pbKeyObject, *pbIV, *key, *pbCtr, *pbIVCopy; - unsigned long dwKeyObject, dwIV, dwCtrLength, dwBlockLength, - cbData, keylen; + unsigned char *pbKeyObject, *pbIV, *pbCtr, *pbIVCopy; + ULONG dwKeyObject, dwIV, dwCtrLength, dwBlockLength, cbData, keylen; int ret; (void)encrypt; @@ -1834,26 +3376,27 @@ _libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, } - keylen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + type.dwKeyLength; - key = malloc(keylen); - if(!key) { + keylen = (ULONG)sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + + type.dwKeyLength; + header = (BCRYPT_KEY_DATA_BLOB_HEADER *)malloc(keylen); + if(!header) { free(pbKeyObject); return -1; } - header = (BCRYPT_KEY_DATA_BLOB_HEADER *)key; header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; header->cbKeyData = type.dwKeyLength; - memcpy(key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), + memcpy((unsigned char *)header + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), secret, type.dwKeyLength); ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey, - pbKeyObject, dwKeyObject, key, keylen, 0); + pbKeyObject, dwKeyObject, + (PUCHAR)header, keylen, 0); - _libssh2_wincng_safe_free(key, keylen); + _libssh2_wincng_safe_free(header, keylen); if(!BCRYPT_SUCCESS(ret)) { _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject); @@ -1895,20 +3438,22 @@ _libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, return 0; } + int _libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, _libssh2_cipher_type(type), int encrypt, unsigned char *block, - size_t blocklen) + size_t blocklen, int firstlast) { unsigned char *pbOutput, *pbInput; - unsigned long cbOutput, cbInput; - int ret; + ULONG cbOutput, cbInput; + NTSTATUS ret; (void)type; + (void)firstlast; - cbInput = (unsigned long)blocklen; + cbInput = (ULONG)blocklen; if(type.ctrMode) { pbInput = ctx->pbCtr; @@ -1951,7 +3496,7 @@ _libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, _libssh2_wincng_safe_free(pbOutput, cbOutput); } else - ret = STATUS_NO_MEMORY; + ret = (NTSTATUS)STATUS_NO_MEMORY; } return BCRYPT_SUCCESS(ret) ? 0 : -1; @@ -1997,7 +3542,7 @@ _libssh2_wincng_bignum_init(void) } static int -_libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length) +_libssh2_wincng_bignum_resize(_libssh2_bn *bn, ULONG length) { unsigned char *bignum; @@ -2007,11 +3552,9 @@ _libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length) if(length == bn->length) return 0; -#ifdef LIBSSH2_CLEAR_MEMORY if(bn->bignum && bn->length > 0 && length < bn->length) { - SecureZeroMemory(bn->bignum + length, bn->length - length); + _libssh2_explicit_zero(bn->bignum + length, bn->length - length); } -#endif bignum = realloc(bn->bignum, length); if(!bignum) @@ -2027,13 +3570,12 @@ static int _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) { unsigned char *bignum; - unsigned long length; + ULONG length; if(!rnd) return -1; - length = (unsigned long) (ceil(((double)bits) / 8.0) * - sizeof(unsigned char)); + length = (ULONG) (ceil(((double)bits) / 8.0) * sizeof(unsigned char)); if(_libssh2_wincng_bignum_resize(rnd, length)) return -1; @@ -2048,13 +3590,13 @@ _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) bits = 8; /* fill most significant byte with zero padding */ - bignum[0] &= ((1 << bits) - 1); + bignum[0] &= (unsigned char)((1 << bits) - 1); /* set most significant bits in most significant byte */ if(top == 0) - bignum[0] |= (1 << (bits - 1)); + bignum[0] |= (unsigned char)(1 << (bits - 1)); else if(top == 1) - bignum[0] |= (3 << (bits - 2)); + bignum[0] |= (unsigned char)(3 << (bits - 2)); /* make odd by setting first bit in least significant byte */ if(bottom) @@ -2071,9 +3613,9 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, { BCRYPT_KEY_HANDLE hKey; BCRYPT_RSAKEY_BLOB *rsakey; - unsigned char *key, *bignum; - unsigned long keylen, offset, length; - int ret; + unsigned char *bignum; + ULONG keylen, offset, length; + NTSTATUS ret; if(!r || !a || !p || !m) return -1; @@ -2081,13 +3623,12 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, offset = sizeof(BCRYPT_RSAKEY_BLOB); keylen = offset + p->length + m->length; - key = malloc(keylen); - if(!key) + rsakey = (BCRYPT_RSAKEY_BLOB *)malloc(keylen); + if(!rsakey) return -1; /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ - rsakey = (BCRYPT_RSAKEY_BLOB *)key; rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; rsakey->BitLength = m->length * 8; rsakey->cbPublicExp = p->length; @@ -2095,14 +3636,15 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, rsakey->cbPrime1 = 0; rsakey->cbPrime2 = 0; - memcpy(key + offset, p->bignum, p->length); + memcpy((unsigned char *)rsakey + offset, p->bignum, p->length); offset += p->length; - memcpy(key + offset, m->bignum, m->length); + memcpy((unsigned char *)rsakey + offset, m->bignum, m->length); offset = 0; ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, - BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, 0); + BCRYPT_RSAPUBLIC_BLOB, &hKey, + (PUCHAR)rsakey, keylen, 0); if(BCRYPT_SUCCESS(ret)) { ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0, NULL, 0, &length, BCRYPT_PAD_NONE); @@ -2125,24 +3667,24 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, } } else - ret = STATUS_NO_MEMORY; + ret = (NTSTATUS)STATUS_NO_MEMORY; } else - ret = STATUS_NO_MEMORY; + ret = (NTSTATUS)STATUS_NO_MEMORY; } BCryptDestroyKey(hKey); } - _libssh2_wincng_safe_free(key, keylen); + _libssh2_wincng_safe_free(rsakey, keylen); return BCRYPT_SUCCESS(ret) ? 0 : -1; } int -_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word) +_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, ULONG word) { - unsigned long offset, number, bits, length; + ULONG offset, number, bits, length; if(!bn) return -1; @@ -2153,8 +3695,7 @@ _libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word) bits++; bits++; - length = (unsigned long) (ceil(((double)bits) / 8.0) * - sizeof(unsigned char)); + length = (ULONG) (ceil(((double)bits) / 8.0) * sizeof(unsigned char)); if(_libssh2_wincng_bignum_resize(bn, length)) return -1; @@ -2164,11 +3705,11 @@ _libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word) return 0; } -unsigned long +ULONG _libssh2_wincng_bignum_bits(const _libssh2_bn *bn) { unsigned char number; - unsigned long offset, length, bits; + ULONG offset, length, bits; if(!bn || !bn->bignum || !bn->length) return 0; @@ -2187,47 +3728,52 @@ _libssh2_wincng_bignum_bits(const _libssh2_bn *bn) return bits; } -void -_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, +int +_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, ULONG len, const unsigned char *bin) { unsigned char *bignum; - unsigned long offset, length, bits; + ULONG offset, length, bits; if(!bn || !bin || !len) - return; + return -1; if(_libssh2_wincng_bignum_resize(bn, len)) - return; + return -1; memcpy(bn->bignum, bin, len); bits = _libssh2_wincng_bignum_bits(bn); - length = (unsigned long) (ceil(((double)bits) / 8.0) * - sizeof(unsigned char)); + length = (ULONG) (ceil(((double)bits) / 8.0) * sizeof(unsigned char)); offset = bn->length - length; if(offset > 0) { memmove(bn->bignum, bn->bignum + offset, length); -#ifdef LIBSSH2_CLEAR_MEMORY - SecureZeroMemory(bn->bignum + length, offset); -#endif + _libssh2_explicit_zero(bn->bignum + length, offset); bignum = realloc(bn->bignum, length); if(bignum) { bn->bignum = bignum; bn->length = length; } + else { + return -1; + } } + + return 0; } -void +int _libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin) { if(bin && bn && bn->bignum && bn->length > 0) { memcpy(bin, bn->bignum, bn->length); + return 0; } + + return -1; } void @@ -2253,9 +3799,9 @@ void _libssh2_dh_init(_libssh2_dh_ctx *dhctx) { /* Random from client */ - dhctx->bn = NULL; dhctx->dh_handle = NULL; dhctx->dh_params = NULL; + dhctx->dh_privbn = NULL; } void @@ -2271,12 +3817,18 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) free(dhctx->dh_params); dhctx->dh_params = NULL; } - if(dhctx->bn) { - _libssh2_wincng_bignum_free(dhctx->bn); - dhctx->bn = NULL; + if(dhctx->dh_privbn) { + _libssh2_wincng_bignum_free(dhctx->dh_privbn); + dhctx->dh_privbn = NULL; } } +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 @@ -2287,16 +3839,19 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, _libssh2_bn *g, _libssh2_bn *p, int group_order) { const int hasAlgDHwithKDF = _libssh2_wincng.hasAlgDHwithKDF; + + if(group_order < 0) + return -1; + while(_libssh2_wincng.hAlgDH && hasAlgDHwithKDF != -1) { - BCRYPT_DH_PARAMETER_HEADER *dh_params = NULL; - unsigned long dh_params_len; - unsigned char *blob = NULL; + BCRYPT_DH_PARAMETER_HEADER *dh_params; + ULONG dh_params_len; int status; /* 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), + ULONG key_length_bytes = max((ULONG)round_down(group_order, 8), max(g->length, p->length)); BCRYPT_DH_KEY_BLOB *dh_key_blob; LPCWSTR key_type; @@ -2310,38 +3865,39 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, return -1; } - dh_params_len = sizeof(*dh_params) + 2 * key_length_bytes; - blob = malloc(dh_params_len); - if(!blob) { + dh_params_len = (ULONG)sizeof(*dh_params) + + 2 * key_length_bytes; + dh_params = (BCRYPT_DH_PARAMETER_HEADER *)malloc(dh_params_len); + if(!dh_params) { 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, + memcpy_with_be_padding((unsigned char *)dh_params + + sizeof(*dh_params), + key_length_bytes, p->bignum, p->length); + memcpy_with_be_padding((unsigned char *)dh_params + + 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); + (PUCHAR)dh_params, dh_params_len, 0); if(hasAlgDHwithKDF == -1) { /* We know that the raw KDF is not supported, so discard this. */ - free(blob); + free(dh_params); } 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. */ + * _libssh2_dh_secret() is called later. */ dhctx->dh_params = dh_params; } dh_params = NULL; - blob = NULL; if(!BCRYPT_SUCCESS(status)) { return -1; @@ -2371,21 +3927,21 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, return -1; } - blob = malloc(key_length_bytes); - if(!blob) { + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)malloc(key_length_bytes); + if(!dh_key_blob) { return -1; } status = BCryptExportKey(dhctx->dh_handle, NULL, key_type, - blob, key_length_bytes, + (PUCHAR)dh_key_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); + free(dh_key_blob); } else { /* we may have potentially private data, use secure free */ - _libssh2_wincng_safe_free(blob, key_length_bytes); + _libssh2_wincng_safe_free(dh_key_blob, key_length_bytes); } return -1; } @@ -2399,45 +3955,47 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, /* 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*)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); + free(dh_key_blob); } else { /* we may have potentially private data, use secure free */ - _libssh2_wincng_safe_free(blob, key_length_bytes); + _libssh2_wincng_safe_free(dh_key_blob, key_length_bytes); } return -1; } /* Copy the public key data into the public bignum data buffer */ - memcpy(public->bignum, - blob + sizeof(*dh_key_blob) + 2 * dh_key_blob->cbKey, + memcpy(public->bignum, (unsigned char *)dh_key_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); + dhctx->dh_privbn = _libssh2_wincng_bignum_init(); + if(!dhctx->dh_privbn) { + _libssh2_wincng_safe_free(dh_key_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); + if(_libssh2_wincng_bignum_resize(dhctx->dh_privbn, + dh_key_blob->cbKey)) { + _libssh2_wincng_safe_free(dh_key_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, + memcpy(dhctx->dh_privbn->bignum, (unsigned char *)dh_key_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); + if(!(dhctx->dh_privbn->bignum[dhctx->dh_privbn->length-1] % 2)) { + _libssh2_wincng_safe_free(dh_key_blob, key_length_bytes); /* discard everything first, then try again */ _libssh2_dh_dtor(dhctx); _libssh2_dh_init(dhctx); @@ -2445,16 +4003,18 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, } } + _libssh2_wincng_safe_free(dh_key_blob, key_length_bytes); + return 0; } /* Generate x and e */ - dhctx->bn = _libssh2_wincng_bignum_init(); - if(!dhctx->bn) + dhctx->dh_privbn = _libssh2_wincng_bignum_init(); + if(!dhctx->dh_privbn) return -1; - if(_libssh2_wincng_bignum_rand(dhctx->bn, group_order * 8 - 1, 0, -1)) + if(_libssh2_wincng_bignum_rand(dhctx->dh_privbn, (group_order*8)-1, 0, -1)) return -1; - if(_libssh2_wincng_bignum_mod_exp(public, g, dhctx->bn, p)) + if(_libssh2_wincng_bignum_mod_exp(public, g, dhctx->dh_privbn, p)) return -1; return 0; @@ -2473,12 +4033,12 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, BCRYPT_KEY_HANDLE peer_public = NULL; BCRYPT_SECRET_HANDLE agreement = NULL; ULONG secret_len_bytes = 0; - unsigned char *blob; - int status; + NTSTATUS 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; + BCRYPT_DH_KEY_BLOB *public_blob; + ULONG key_length_bytes = max(f->length, dhctx->dh_params->cbKeyLength); + ULONG public_blob_len = (ULONG)(sizeof(*public_blob) + + 3 * key_length_bytes); { /* Populate a BCRYPT_DH_KEY_BLOB; after the header follows the @@ -2487,11 +4047,10 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, unsigned char *dest; unsigned char *src; - blob = malloc(public_blob_len); - if(!blob) { + public_blob = (BCRYPT_DH_KEY_BLOB *)malloc(public_blob_len); + if(!public_blob) { return -1; } - public_blob = (BCRYPT_DH_KEY_BLOB*)blob; public_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC; public_blob->cbKey = key_length_bytes; @@ -2512,8 +4071,8 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, /* 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, + (PUCHAR)public_blob, public_blob_len, 0); if(!BCRYPT_SUCCESS(status)) { goto out; } @@ -2540,7 +4099,7 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, /* 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; + status = (NTSTATUS)STATUS_NO_MEMORY; goto out; } @@ -2578,6 +4137,9 @@ out: if(agreement) { BCryptDestroySecret(agreement); } + + free(public_blob); + if(status == STATUS_NOT_SUPPORTED && _libssh2_wincng.hasAlgDHwithKDF == -1) { goto fb; /* fallback to RSA-based implementation */ @@ -2587,7 +4149,37 @@ out: fb: /* Compute the shared secret */ - return _libssh2_wincng_bignum_mod_exp(secret, f, dhctx->bn, p); + return _libssh2_wincng_bignum_mod_exp(secret, f, dhctx->dh_privbn, p); } -#endif /* LIBSSH2_WINCNG */ +/* _libssh2_supported_key_sign_algorithms + * + * Return supported key hash algo upgrades, see crypto.h + * + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len) +{ + (void)session; + +#if LIBSSH2_RSA_SHA2 + if(key_method_len == 7 && + memcmp(key_method, "ssh-rsa", key_method_len) == 0) { + return "rsa-sha2-512,rsa-sha2-256" +#if LIBSSH2_RSA_SHA1 + ",ssh-rsa" +#endif + ; + } +#else + (void)key_method; + (void)key_method_len; +#endif + + return NULL; +} + +#endif /* LIBSSH2_CRYPTO_C */ diff --git a/uppsrc/Core/SSH/libssh2/wincng.h b/uppsrc/Core/SSH/libssh2/wincng.h index eaf6f9051..a8d0d8057 100644 --- a/uppsrc/Core/SSH/libssh2/wincng.h +++ b/uppsrc/Core/SSH/libssh2/wincng.h @@ -1,7 +1,7 @@ -#ifndef __LIBSSH2_WINCNG_H -#define __LIBSSH2_WINCNG_H +#ifndef LIBSSH2_WINCNG_H +#define LIBSSH2_WINCNG_H /* - * Copyright (C) 2013-2020 Marc Hoersken + * Copyright (C) Marc Hoersken * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,8 +36,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ +#define LIBSSH2_CRYPTO_ENGINE libssh2_wincng + /* required for cross-compilation against the w64 mingw-runtime package */ #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) #undef _WIN32_WINNT @@ -55,19 +59,43 @@ #define LIBSSH2_HMAC_SHA256 1 #define LIBSSH2_HMAC_SHA512 1 -#define LIBSSH2_AES 1 +#define LIBSSH2_AES_CBC 1 #define LIBSSH2_AES_CTR 1 +#define LIBSSH2_AES_GCM 0 #define LIBSSH2_BLOWFISH 0 #define LIBSSH2_RC4 1 #define LIBSSH2_CAST 0 #define LIBSSH2_3DES 1 #define LIBSSH2_RSA 1 +#define LIBSSH2_RSA_SHA1 1 +#define LIBSSH2_RSA_SHA2 1 #define LIBSSH2_DSA 1 -#define LIBSSH2_ECDSA 0 #define LIBSSH2_ED25519 0 +/* + * Conditionally enable ECDSA support. + * + * ECDSA support requires the use of + * + * BCryptDeriveKey(..., BCRYPT_KDF_RAW_SECRET, ... ) + * + * This functionality is only available as of Windows 10. To maintain + * backward compatibility, ECDSA support is therefore disabled + * by default and needs to be explicitly enabled using a build + * flag. + */ +#ifdef LIBSSH2_ECDSA_WINCNG +#define LIBSSH2_ECDSA 1 +#else +#define LIBSSH2_ECDSA 0 +#endif + +#include "crypto_config.h" + +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM #define MD5_DIGEST_LENGTH 16 +#endif #define SHA_DIGEST_LENGTH 20 #define SHA256_DIGEST_LENGTH 32 #define SHA384_DIGEST_LENGTH 48 @@ -104,6 +132,11 @@ struct _libssh2_wincng_ctx { BCRYPT_ALG_HANDLE hAlgRC4_NA; BCRYPT_ALG_HANDLE hAlg3DES_CBC; BCRYPT_ALG_HANDLE hAlgDH; + BCRYPT_ALG_HANDLE hAlgChacha20; +#if LIBSSH2_ECDSA + BCRYPT_ALG_HANDLE hAlgECDH[3]; /* indexed by libssh2_curve_type */ + BCRYPT_ALG_HANDLE hAlgECDSA[3]; /* indexed by libssh2_curve_type */ +#endif volatile int hasAlgDHwithKDF; /* -1=no, 0=maybe, 1=yes */ }; @@ -115,16 +148,13 @@ extern struct _libssh2_wincng_ctx _libssh2_wincng; * Windows CNG backend: Generic functions */ -void _libssh2_wincng_init(void); -void _libssh2_wincng_free(void); - #define libssh2_crypto_init() \ - _libssh2_wincng_init() + _libssh2_wincng_init() #define libssh2_crypto_exit() \ - _libssh2_wincng_free() + _libssh2_wincng_free() #define _libssh2_random(buf, len) \ - _libssh2_wincng_random(buf, len) + _libssh2_wincng_random(buf, len) #define libssh2_prepare_iovec(vec, len) /* Empty. */ @@ -137,8 +167,8 @@ void _libssh2_wincng_free(void); typedef struct __libssh2_wincng_hash_ctx { BCRYPT_HASH_HANDLE hHash; unsigned char *pbHashObject; - unsigned long dwHashObject; - unsigned long cbHash; + ULONG dwHashObject; + ULONG cbHash; } _libssh2_wincng_hash_ctx; /* @@ -147,88 +177,68 @@ typedef struct __libssh2_wincng_hash_ctx { #define libssh2_sha1_ctx _libssh2_wincng_hash_ctx #define libssh2_sha1_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA1, \ - SHA_DIGEST_LENGTH, NULL, 0) == 0) + (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA1, \ + SHA_DIGEST_LENGTH, NULL, 0) == 0) #define libssh2_sha1_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) + (_libssh2_wincng_hash_update(&ctx, data, (ULONG) datalen) == 0) #define libssh2_sha1_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) + (_libssh2_wincng_hash_final(&ctx, hash) == 0) #define libssh2_sha1(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA1, \ - hash, SHA_DIGEST_LENGTH) + _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA1, \ + hash, SHA_DIGEST_LENGTH) #define libssh2_sha256_ctx _libssh2_wincng_hash_ctx #define libssh2_sha256_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA256, \ - SHA256_DIGEST_LENGTH, NULL, 0) == 0) + (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA256, \ + SHA256_DIGEST_LENGTH, NULL, 0) == 0) #define libssh2_sha256_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) + (_libssh2_wincng_hash_update(&ctx, data, (ULONG) datalen) == 0) #define libssh2_sha256_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) + (_libssh2_wincng_hash_final(&ctx, hash) == 0) #define libssh2_sha256(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA256, \ - hash, SHA256_DIGEST_LENGTH) + _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) + (_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) + (_libssh2_wincng_hash_update(&ctx, data, (ULONG) datalen) == 0) #define libssh2_sha384_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) + (_libssh2_wincng_hash_final(&ctx, hash) == 0) #define libssh2_sha384(data, datalen, hash) \ -_libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA384, \ - hash, SHA384_DIGEST_LENGTH) + _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, \ - SHA512_DIGEST_LENGTH, NULL, 0) == 0) + (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA512, \ + SHA512_DIGEST_LENGTH, NULL, 0) == 0) #define libssh2_sha512_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) + (_libssh2_wincng_hash_update(&ctx, data, (ULONG) datalen) == 0) #define libssh2_sha512_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) + (_libssh2_wincng_hash_final(&ctx, hash) == 0) #define libssh2_sha512(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA512, \ - hash, SHA512_DIGEST_LENGTH) + _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA512, \ + hash, SHA512_DIGEST_LENGTH) +#if LIBSSH2_MD5 || LIBSSH2_MD5_PEM #define libssh2_md5_ctx _libssh2_wincng_hash_ctx #define libssh2_md5_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashMD5, \ - MD5_DIGEST_LENGTH, NULL, 0) == 0) + (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashMD5, \ + MD5_DIGEST_LENGTH, NULL, 0) == 0) #define libssh2_md5_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) + (_libssh2_wincng_hash_update(&ctx, data, (ULONG) datalen) == 0) #define libssh2_md5_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_md5(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashMD5, \ - hash, MD5_DIGEST_LENGTH) + (_libssh2_wincng_hash_final(&ctx, hash) == 0) +#endif /* * Windows CNG backend: HMAC functions */ #define libssh2_hmac_ctx _libssh2_wincng_hash_ctx -#define libssh2_hmac_ctx_init(ctx) -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA1, \ - SHA_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacMD5, \ - MD5_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) - /* not implemented */ -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA256, \ - SHA256_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA512, \ - SHA512_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_hmac_final(ctx, hash) \ - _libssh2_wincng_hmac_final(&ctx, hash) -#define libssh2_hmac_cleanup(ctx) \ - _libssh2_wincng_hmac_cleanup(ctx) /*******************************************************************/ @@ -238,8 +248,8 @@ _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA384, \ typedef struct __libssh2_wincng_key_ctx { BCRYPT_KEY_HANDLE hKey; - unsigned char *pbKeyObject; - unsigned long cbKeyObject; + void *pbKeyObject; + DWORD cbKeyObject; } _libssh2_wincng_key_ctx; @@ -251,21 +261,25 @@ typedef struct __libssh2_wincng_key_ctx { #define _libssh2_rsa_new(rsactx, e, e_len, n, n_len, \ d, d_len, p, p_len, q, q_len, \ e1, e1_len, e2, e2_len, c, c_len) \ - _libssh2_wincng_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) + _libssh2_wincng_rsa_new(rsactx, e, e_len, n, n_len, \ + d, d_len, p, p_len, q, q_len, \ + e1, e1_len, e2, e2_len, c, c_len) #define _libssh2_rsa_new_private(rsactx, s, filename, passphrase) \ - _libssh2_wincng_rsa_new_private(rsactx, s, filename, passphrase) + _libssh2_wincng_rsa_new_private(rsactx, s, filename, passphrase) #define _libssh2_rsa_new_private_frommemory(rsactx, s, filedata, \ filedata_len, passphrase) \ - _libssh2_wincng_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) + _libssh2_wincng_rsa_new_private_frommemory(rsactx, s, filedata, \ + filedata_len, passphrase) #define _libssh2_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) \ - _libssh2_wincng_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) + _libssh2_wincng_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) +#define _libssh2_rsa_sha2_sign(s, rsactx, hash, hash_len, sig, sig_len) \ + _libssh2_wincng_rsa_sha2_sign(s, rsactx, hash, hash_len, sig, sig_len) #define _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) \ - _libssh2_wincng_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) + _libssh2_wincng_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) +#define _libssh2_rsa_sha2_verify(rsactx, hash_len, sig, sig_len, m, m_len) \ + _libssh2_wincng_rsa_sha2_verify(rsactx, hash_len, sig, sig_len, m, m_len) #define _libssh2_rsa_free(rsactx) \ - _libssh2_wincng_rsa_free(rsactx) + _libssh2_wincng_rsa_free(rsactx) /* * Windows CNG backend: DSA functions @@ -274,32 +288,92 @@ typedef struct __libssh2_wincng_key_ctx { #define libssh2_dsa_ctx _libssh2_wincng_key_ctx #define _libssh2_dsa_new(dsactx, p, p_len, q, q_len, \ g, g_len, y, y_len, x, x_len) \ - _libssh2_wincng_dsa_new(dsactx, p, p_len, q, q_len, \ - g, g_len, y, y_len, x, x_len) + _libssh2_wincng_dsa_new(dsactx, p, p_len, q, q_len, \ + g, g_len, y, y_len, x, x_len) #define _libssh2_dsa_new_private(dsactx, s, filename, passphrase) \ - _libssh2_wincng_dsa_new_private(dsactx, s, filename, passphrase) + _libssh2_wincng_dsa_new_private(dsactx, s, filename, passphrase) #define _libssh2_dsa_new_private_frommemory(dsactx, s, filedata, \ filedata_len, passphrase) \ - _libssh2_wincng_dsa_new_private_frommemory(dsactx, s, filedata, \ - filedata_len, passphrase) + _libssh2_wincng_dsa_new_private_frommemory(dsactx, s, filedata, \ + filedata_len, passphrase) #define _libssh2_dsa_sha1_sign(dsactx, hash, hash_len, sig) \ - _libssh2_wincng_dsa_sha1_sign(dsactx, hash, hash_len, sig) + _libssh2_wincng_dsa_sha1_sign(dsactx, hash, hash_len, sig) #define _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len) \ - _libssh2_wincng_dsa_sha1_verify(dsactx, sig, m, m_len) + _libssh2_wincng_dsa_sha1_verify(dsactx, sig, m, m_len) #define _libssh2_dsa_free(dsactx) \ - _libssh2_wincng_dsa_free(dsactx) + _libssh2_wincng_dsa_free(dsactx) + + +/* + * Windows CNG backend: ECDSA functions + */ + +typedef enum { + LIBSSH2_EC_CURVE_NISTP256 = 0, + LIBSSH2_EC_CURVE_NISTP384 = 1, + LIBSSH2_EC_CURVE_NISTP521 = 2, +} libssh2_curve_type; + +typedef struct __libssh2_wincng_ecdsa_ctx { + BCRYPT_KEY_HANDLE handle; + libssh2_curve_type curve; +} _libssh2_wincng_ecdsa_key; + +#define libssh2_ecdsa_ctx _libssh2_wincng_ecdsa_key + +#if LIBSSH2_ECDSA +#define _libssh2_ec_key _libssh2_wincng_ecdsa_key +#endif + +void +_libssh2_wincng_ecdsa_free(libssh2_ecdsa_ctx* ctx); + +#define _libssh2_ecdsa_create_key(session, privkey, pubkey_octal, \ + pubkey_octal_len, curve) \ + _libssh2_wincng_ecdh_create_key(session, privkey, pubkey_octal, \ + pubkey_octal_len, curve) + +#define _libssh2_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve) \ + _libssh2_wincng_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve) + +#define _libssh2_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len) \ + _libssh2_wincng_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_wincng_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len) + +#define _libssh2_ecdsa_new_private(ctx, session, filename, passphrase) \ + _libssh2_wincng_ecdsa_new_private(ctx, session, filename, passphrase) + +#define _libssh2_ecdsa_new_private_frommemory(ctx, session, filedata, \ + filedata_len, passphrase) \ + _libssh2_wincng_ecdsa_new_private_frommemory(ctx, session, filedata, \ + filedata_len, passphrase) + +#define _libssh2_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len) \ + _libssh2_wincng_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len) + +#define _libssh2_ecdsa_get_curve_type(ctx) \ + _libssh2_wincng_ecdsa_get_curve_type(ctx) + +#define _libssh2_ecdsa_free(ecdsactx) \ + _libssh2_wincng_ecdsa_free(ecdsactx) + /* * Windows CNG backend: Key functions */ #define _libssh2_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) \ - _libssh2_wincng_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) + _libssh2_wincng_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) #define _libssh2_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) \ - _libssh2_wincng_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) - + pk, pk_len, pw) \ + _libssh2_wincng_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ + pk, pk_len, pw) +#define _libssh2_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \ + f, kh, kh_len, pk, pk_len, pw) \ + _libssh2_wincng_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \ + f, kh, kh_len, pk, pk_len, pw) /*******************************************************************/ /* @@ -311,10 +385,10 @@ struct _libssh2_wincng_cipher_ctx { unsigned char *pbKeyObject; unsigned char *pbIV; unsigned char *pbCtr; - unsigned long dwKeyObject; - unsigned long dwIV; - unsigned long dwBlockLength; - unsigned long dwCtrLength; + ULONG dwKeyObject; + ULONG dwIV; + ULONG dwBlockLength; + ULONG dwCtrLength; }; #define _libssh2_cipher_ctx struct _libssh2_wincng_cipher_ctx @@ -325,7 +399,7 @@ struct _libssh2_wincng_cipher_ctx { struct _libssh2_wincng_cipher_type { BCRYPT_ALG_HANDLE *phAlg; - unsigned long dwKeyLength; + ULONG dwKeyLength; int useIV; /* TODO: Convert to bool when a C89 compatible bool type is defined */ int ctrMode; @@ -336,22 +410,23 @@ struct _libssh2_wincng_cipher_type { #define _libssh2_cipher_aes256ctr { &_libssh2_wincng.hAlgAES_ECB, 32, 0, 1 } #define _libssh2_cipher_aes192ctr { &_libssh2_wincng.hAlgAES_ECB, 24, 0, 1 } #define _libssh2_cipher_aes128ctr { &_libssh2_wincng.hAlgAES_ECB, 16, 0, 1 } -#define _libssh2_cipher_aes256 { &_libssh2_wincng.hAlgAES_CBC, 32, 1, 0 } -#define _libssh2_cipher_aes192 { &_libssh2_wincng.hAlgAES_CBC, 24, 1, 0 } -#define _libssh2_cipher_aes128 { &_libssh2_wincng.hAlgAES_CBC, 16, 1, 0 } -#define _libssh2_cipher_arcfour { &_libssh2_wincng.hAlgRC4_NA, 16, 0, 0 } -#define _libssh2_cipher_3des { &_libssh2_wincng.hAlg3DES_CBC, 24, 1, 0 } +#define _libssh2_cipher_aes256 { &_libssh2_wincng.hAlgAES_CBC, 32, 1, 0 } +#define _libssh2_cipher_aes192 { &_libssh2_wincng.hAlgAES_CBC, 24, 1, 0 } +#define _libssh2_cipher_aes128 { &_libssh2_wincng.hAlgAES_CBC, 16, 1, 0 } +#define _libssh2_cipher_arcfour { &_libssh2_wincng.hAlgRC4_NA, 16, 0, 0 } +#define _libssh2_cipher_3des { &_libssh2_wincng.hAlg3DES_CBC, 24, 1, 0 } +#define _libssh2_cipher_chacha20 { &_libssh2_wincng.hAlgChacha20, 24, 1, 0 } /* * Windows CNG backend: Cipher functions */ #define _libssh2_cipher_init(ctx, type, iv, secret, encrypt) \ - _libssh2_wincng_cipher_init(ctx, type, iv, secret, encrypt) -#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen) \ - _libssh2_wincng_cipher_crypt(ctx, type, encrypt, block, blocklen) + _libssh2_wincng_cipher_init(ctx, type, iv, secret, encrypt) +#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen, fl) \ + _libssh2_wincng_cipher_crypt(ctx, type, encrypt, block, blocklen, fl) #define _libssh2_cipher_dtor(ctx) \ - _libssh2_wincng_cipher_dtor(ctx) + _libssh2_wincng_cipher_dtor(ctx) /*******************************************************************/ /* @@ -370,7 +445,7 @@ struct _libssh2_wincng_cipher_type { struct _libssh2_wincng_bignum { unsigned char *bignum; - unsigned long length; + ULONG length; }; #define _libssh2_bn struct _libssh2_wincng_bignum @@ -379,28 +454,34 @@ struct _libssh2_wincng_bignum { * Windows CNG backend: BigNumber functions */ -_libssh2_bn *_libssh2_wincng_bignum_init(void); - #define _libssh2_bn_init() \ - _libssh2_wincng_bignum_init() + _libssh2_wincng_bignum_init() #define _libssh2_bn_init_from_bin() \ - _libssh2_bn_init() + _libssh2_bn_init() #define _libssh2_bn_set_word(bn, word) \ - _libssh2_wincng_bignum_set_word(bn, word) + _libssh2_wincng_bignum_set_word(bn, word) #define _libssh2_bn_from_bin(bn, len, bin) \ - _libssh2_wincng_bignum_from_bin(bn, len, bin) + _libssh2_wincng_bignum_from_bin(bn, (ULONG) len, bin) #define _libssh2_bn_to_bin(bn, bin) \ - _libssh2_wincng_bignum_to_bin(bn, bin) + _libssh2_wincng_bignum_to_bin(bn, bin) #define _libssh2_bn_bytes(bn) bn->length #define _libssh2_bn_bits(bn) \ - _libssh2_wincng_bignum_bits(bn) + _libssh2_wincng_bignum_bits(bn) #define _libssh2_bn_free(bn) \ - _libssh2_wincng_bignum_free(bn) + _libssh2_wincng_bignum_free(bn) /* * Windows CNG backend: Diffie-Hellman support */ +/* Default generate and safe prime sizes for + diffie-hellman-group-exchange-sha1 */ +#define LIBSSH2_DH_GEX_MINGROUP 2048 +#define LIBSSH2_DH_GEX_OPTGROUP 4096 +#define LIBSSH2_DH_GEX_MAXGROUP 4096 + +#define LIBSSH2_DH_MAX_MODULUS_BITS 16384 + typedef struct { /* holds our private and public key components */ BCRYPT_KEY_HANDLE dh_handle; @@ -409,14 +490,14 @@ typedef struct { BCRYPT_DH_PARAMETER_HEADER *dh_params; /* records the parsed out private key component for * fallback if the DH API raw KDF is not supported */ - struct _libssh2_wincng_bignum *bn; + struct _libssh2_wincng_bignum *dh_privbn; } _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) + _libssh2_dh_key_pair(dhctx, public, g, p, group_order) #define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) + _libssh2_dh_secret(dhctx, secret, f, p) #define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) /*******************************************************************/ @@ -425,163 +506,44 @@ typedef struct { */ void _libssh2_wincng_init(void); void _libssh2_wincng_free(void); -int _libssh2_wincng_random(void *buf, int len); +int _libssh2_wincng_random(void *buf, size_t len); int _libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, - BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen, - unsigned char *key, unsigned long keylen); + BCRYPT_ALG_HANDLE hAlg, ULONG hashlen, + unsigned char *key, ULONG keylen); int _libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx, - const unsigned char *data, unsigned long datalen); + const void *data, ULONG datalen); int _libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx, unsigned char *hash); int -_libssh2_wincng_hash(unsigned char *data, unsigned long datalen, +_libssh2_wincng_hash(const unsigned char *data, ULONG datalen, BCRYPT_ALG_HANDLE hAlg, - unsigned char *hash, unsigned long hashlen); + unsigned char *hash, ULONG hashlen); -int -_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash); -void -_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx); - -int -_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len, - unsigned long flags); - -int -_libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen); -int -_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); -int -_libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len); void _libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa); #if LIBSSH2_DSA -int -_libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *gdata, - unsigned long glen, - const unsigned char *ydata, - unsigned long ylen, - const unsigned char *xdata, - unsigned long xlen); -int -_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); -int -_libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa, - const unsigned char *sig_fixed, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, - const unsigned char *hash, - unsigned long hash_len, - unsigned char *sig_fixed); void _libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa); #endif -int -_libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); -int -_libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase); - -int -_libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt); -int -_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen); void _libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx); _libssh2_bn * _libssh2_wincng_bignum_init(void); int -_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word); -unsigned long +_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, ULONG word); +ULONG _libssh2_wincng_bignum_bits(const _libssh2_bn *bn); -void -_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, +int +_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, ULONG len, const unsigned char *bin); -void +int _libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin); void _libssh2_wincng_bignum_free(_libssh2_bn *bn); @@ -596,4 +558,4 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); -#endif /* __LIBSSH2_WINCNG_H */ +#endif /* LIBSSH2_WINCNG_H */ diff --git a/uppsrc/Core/SSH/libssh2upp.c b/uppsrc/Core/SSH/libssh2upp.c deleted file mode 100644 index 295d7c1f5..000000000 --- a/uppsrc/Core/SSH/libssh2upp.c +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _UPP_SSH_libssh2upp_h_ -#define _UPP_SSH_libssh2upp_h_ - -#include "libssh2/agent.c" -#include "libssh2/agent_win.c" -#include "libssh2/bcrypt_pbkdf.c" -#include "libssh2/blowfish.c" -#include "libssh2/channel.c" -#include "libssh2/comp.c" -#include "libssh2/crypt.c" -#include "libssh2/global.c" -#include "libssh2/hostkey.c" -#include "libssh2/keepalive.c" -#include "libssh2/kex.c" -#include "libssh2/knownhost.c" -#include "libssh2/libgcrypt.c" -#include "libssh2/mac.c" -#include "libssh2/mbedtls.c" -#include "libssh2/misc.c" -#include "libssh2/openssl.c" -#include "libssh2/packet.c" -#include "libssh2/pem.c" -#include "libssh2/publickey.c" -#include "libssh2/scp.c" -#include "libssh2/session.c" -#include "libssh2/sftp.c" -#include "libssh2/transport.c" -#include "libssh2/userauth.c" -#include "libssh2/version.c" -#include "libssh2/wincng.c" - -#endif diff --git a/uppsrc/Core/SSH/libssh2upp.ext b/uppsrc/Core/SSH/libssh2upp.ext new file mode 100644 index 000000000..878fbe81b --- /dev/null +++ b/uppsrc/Core/SSH/libssh2upp.ext @@ -0,0 +1,7 @@ +// Imports the source files of winpty-agent executable, filters out the test code and other files. + +files + libssh2/*.c +; + +includes ; \ No newline at end of file diff --git a/uppsrc/Core/SSH/src.tpp/Upp_Ssh_Session_en-us.tpp b/uppsrc/Core/SSH/src.tpp/Upp_Ssh_Session_en-us.tpp index 596b61b00..441dddba6 100644 --- a/uppsrc/Core/SSH/src.tpp/Upp_Ssh_Session_en-us.tpp +++ b/uppsrc/Core/SSH/src.tpp/Upp_Ssh_Session_en-us.tpp @@ -54,14 +54,17 @@ shSession][@(0.0.255) `&]_[* Keys]([@(0.0.255) const]_[_^Upp`:`:String^ String][ ]_[*@3 prikey], [@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `&]_[*@3 pubkey], [@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `&]_[*@3 phrase], [@(0.0.255) bool]_[*@3 fromfile]_`=_[@(0.0.255) true])&] -[s2;%% Sets the asymmetric encryption keys to be used to authenticate +[s0;l288;%% Sets the asymmetric encryption keys to be used to authenticate the session. [%-*@3 phrase] can be used to decipher the private key, or it can be empty (not recommended). Returns `*this for method chaining. Note that when the [%-*@3 fromfile] parameter is true, [%-*@3 prikey] and [%-*@3 pubkey] strings will be treated as file paths to the respective key files. This is the default behaviour. Otherwise they will be treated as memory buffers containing -the actual keys.&] +the actual keys. Note that it is possible to compute public key +from public key (aka. private key auth). To enable it, simply +&] +[s2;%% pass an empty or Null [%-*@3 pubkey].&] [s3;%% &] [s4; &] [s5;:Upp`:`:SshSession`:`:Method`(int`,Upp`:`:Value`): [_^Upp`:`:SshSession^ SshSession @@ -161,33 +164,6 @@ The `"[C none]`" method allows logging in without an authentication scheme. It is rarely used by the servers, and handled automatically by the session.&] [s3;^Upp`:`:SFtp^ &] -[s4;^Upp`:`:SFtp^ &] -[s5;:Upp`:`:SshSession`:`:CreateSFtp`(`): [_^Upp`:`:SFtp^ SFtp]_[* CreateSFtp]()&] -[s2;%% Creates an sftp channel instance.&] -[s3; &] -[s4; &] -[s5;:Upp`:`:SshSession`:`:CreateChannel`(`): [_^Upp`:`:SshChannel^ SshChannel]_[* CreateC -hannel]()&] -[s2;%% Creates a generic channel instance.&] -[s3; &] -[s4; &] -[s5;:Upp`:`:SshSession`:`:CreateExec`(`): [_^Upp`:`:SshExec^ SshExec]_[* CreateExec]()&] -[s2;%% Creates an exec channel instance.&] -[s3; &] -[s4; &] -[s5;:Upp`:`:SshSession`:`:CreateScp`(`): [_^Upp`:`:Scp^ Scp]_[* CreateScp]()&] -[s2;%% Creates an scp channel instance.&] -[s3; &] -[s4; &] -[s5;:Upp`:`:SshSession`:`:CreateTunnel`(`): [_^Upp`:`:SshTunnel^ SshTunnel]_[* CreateTunn -el]()&] -[s2;%% Creates a tcp`-ip and port forwarding channel instance.&] -[s3; &] -[s4; &] -[s5;:Upp`:`:SshSession`:`:CreateShell`(`): [_^Upp`:`:SshShell^ SshShell]_[* CreateShell]( -)&] -[s2;%% Creates a remote shell channel instance.&] -[s3; &] [s4; &] [s5;:Upp`:`:SshSession`:`:Connect`(const Upp`:`:String`&`): [@(0.0.255) bool]_[* Connect]( [@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `&]_[*@3 url])&] diff --git a/uppsrc/Core/SSH/src.tpp/Upp_Ssh_Session_en-us.tppi b/uppsrc/Core/SSH/src.tpp/Upp_Ssh_Session_en-us.tppi index c94dbb717..22e759ca1 100644 --- a/uppsrc/Core/SSH/src.tpp/Upp_Ssh_Session_en-us.tppi +++ b/uppsrc/Core/SSH/src.tpp/Upp_Ssh_Session_en-us.tppi @@ -1,21 +1,20 @@ TITLE("Session") COMPRESSED -120,156,237,27,127,119,219,182,241,171,224,53,107,39,231,217,50,73,137,146,44,117,123,118,21,167,206,107,98,231,69,206,214,77,143,54,33,10,146,88,83,164,70,128,118,180,182,249,236,187,3,64,18,148,37,91,178,147,117,127,172,47,181,73,240,112,184,223,184,59,192,195,176,217,236,244,168,227,246,110,126,186,56,234,57,228,79,127,178,247,173,23,141,182,221,232,184,13,187,233,180,224,135,221,176,29,215,105,52,237,142,115,212,236,52,26,29,171,27,68,148,115,111,24,57,157,142,156,228,236,59,47,156,182,235,216,237,102,167,217,177,27,237,142,3,115,29,203,114,172,182,227,218,205,70,199,113,187,99,198,3,111,104,1,120,3,214,56,106,53,142,44,219,178,218,182,109,53,156,182,213,112,155,182,221,112,0,133,211,118,108,203,237,178,120,236,13,207,90,61,156,208,132,9,150,219,178,44,171,5,216,154,77,11,176,227,180,102,195,110,88,78,195,181,143,220,86,119,196,166,97,236,13,239,179,228,62,202,82,219,234,134,130,205,53,71,180,217,123,121,236,246,108,152,218,218, -111,189,104,195,178,77,23,22,59,66,142,26,48,205,113,90,238,145,237,54,129,164,166,229,116,83,246,175,44,76,217,156,197,66,99,8,109,219,177,123,35,187,221,3,18,62,127,254,92,183,155,150,146,84,27,104,177,45,160,219,177,97,12,248,104,219,238,145,117,228,118,236,142,213,104,55,29,183,13,172,47,104,74,231,154,147,81,211,233,105,62,58,251,157,23,45,187,5,18,181,58,64,191,123,4,8,44,96,2,126,131,32,93,248,215,232,116,133,158,140,243,112,210,209,254,209,11,16,82,195,181,218,71,86,187,217,118,155,192,137,99,183,108,16,164,133,252,131,26,186,113,146,206,105,228,13,113,130,133,178,126,228,191,238,43,54,161,89,4,236,254,122,253,59,25,146,95,127,181,113,248,184,6,42,172,55,157,186,181,71,134,220,234,125,251,45,25,190,60,110,247,154,100,192,103,3,198,121,152,196,158,247,251,239,223,121,67,222,232,17,252,101,247,186,31,23,11,191,235,119,75,16,124,147,22,214,37,195,227,154,85,183,234,192,236,94,131,104,171,107,144,107,111,248,178,97, -226,196,177,46,140,154,208,139,108,20,133,65,14,126,220,232,201,25,30,46,106,245,94,72,53,1,125,151,179,144,43,196,132,197,1,93,240,44,162,130,113,66,9,103,65,150,50,194,103,44,138,72,237,150,165,184,18,113,246,0,58,4,77,195,119,185,118,157,188,17,4,112,164,140,47,146,152,135,163,136,145,73,146,18,198,5,5,2,248,44,140,167,251,132,102,98,6,147,194,128,10,245,30,143,201,156,198,20,44,118,10,107,5,233,114,33,146,105,74,23,51,0,137,162,165,94,125,172,151,215,107,17,248,71,99,50,24,156,57,36,72,230,139,40,164,146,144,20,168,171,27,242,208,12,1,85,99,150,134,183,128,102,146,38,115,50,188,18,201,34,12,64,188,135,254,97,63,73,153,127,8,168,252,67,158,6,254,33,106,225,26,80,248,215,63,80,206,252,107,22,251,7,25,247,95,148,218,41,212,114,37,5,73,70,0,167,86,82,252,204,40,39,128,254,6,8,2,214,128,87,94,47,21,157,155,200,235,154,237,116,246,126,148,63,143,237,210,74,200,123,169,46,242,142,137,89, -50,38,111,67,46,86,44,197,221,96,41,151,225,156,37,153,240,107,97,44,252,61,48,153,235,171,123,112,87,21,99,41,173,132,248,223,121,215,176,184,198,225,213,204,111,128,15,63,30,55,200,156,123,123,72,130,131,180,14,152,224,68,168,9,228,150,70,25,3,72,50,15,65,215,44,72,226,49,175,35,8,170,153,128,206,87,32,69,66,206,51,80,232,34,67,36,240,217,80,90,50,250,133,5,2,151,77,200,40,74,130,27,68,49,79,198,172,78,62,48,145,165,49,39,254,75,129,246,138,246,53,87,130,10,102,52,140,1,176,78,206,19,1,248,103,20,12,130,207,8,207,70,124,201,33,166,113,169,27,0,139,99,22,129,77,196,51,48,9,129,107,135,41,152,135,116,227,42,145,92,89,139,130,200,173,92,41,2,216,199,135,230,195,26,233,131,105,166,250,181,54,74,146,232,169,106,49,16,85,85,131,72,181,110,70,222,181,255,151,107,243,163,72,51,102,232,235,52,6,63,4,166,64,102,227,144,171,231,127,74,247,209,168,165,56,199,84,80,152,73,99,62,1,79,223,78, -226,6,121,210,215,20,246,49,25,45,115,193,214,85,124,209,51,233,100,2,10,86,122,191,155,37,16,40,138,24,114,9,90,97,176,8,216,146,32,243,140,11,50,66,179,186,77,110,0,31,11,97,70,10,35,18,128,198,75,160,30,180,25,8,92,152,10,80,242,66,32,123,119,0,7,166,136,232,183,116,245,92,105,107,188,221,208,231,223,33,116,245,147,120,18,78,175,72,249,236,17,118,11,33,173,42,6,30,204,96,31,132,136,10,97,10,56,224,11,22,132,147,16,120,184,13,169,114,7,20,241,34,73,69,46,20,174,124,197,140,21,143,217,215,121,82,177,176,167,90,87,5,141,87,43,45,230,213,90,51,1,183,166,115,16,63,55,25,174,77,104,196,217,222,255,237,101,123,123,217,94,207,63,177,37,247,107,64,59,176,151,3,136,20,68,233,127,231,239,239,54,252,156,40,132,100,84,195,143,92,4,190,149,200,228,66,128,72,254,94,131,4,2,213,34,13,111,216,210,219,39,207,199,148,141,190,20,166,89,10,155,248,10,38,35,184,226,70,48,9,35,246,88,140,85,123, -226,12,189,99,57,7,235,77,97,39,135,116,10,179,26,180,57,160,150,227,214,7,54,154,113,48,80,120,52,18,34,38,103,22,166,61,252,246,192,32,45,143,36,249,188,49,4,148,5,90,55,206,1,145,222,226,124,192,191,143,6,13,190,160,193,209,196,151,164,22,39,2,18,51,112,98,200,205,199,108,188,165,159,150,59,233,29,208,168,252,67,17,85,200,131,200,44,155,9,32,4,176,160,52,246,11,194,149,158,229,182,155,15,41,133,17,46,85,193,193,241,32,5,24,97,48,100,64,254,24,99,10,98,5,164,98,38,5,133,75,98,66,137,62,123,43,249,147,0,92,199,135,80,9,59,223,189,71,108,70,111,195,36,131,28,240,2,61,255,14,50,17,4,88,174,91,104,206,230,73,186,36,163,108,130,27,29,154,141,80,124,43,253,5,34,163,145,84,216,78,91,190,74,219,84,14,182,175,33,254,134,201,196,83,157,78,33,220,148,144,137,229,66,90,109,129,88,174,117,69,228,175,60,105,83,24,214,24,41,4,97,224,29,179,235,123,187,17,218,3,130,232,87,173,63,185, -28,200,190,128,214,227,26,202,43,141,97,78,151,185,72,177,132,0,177,70,57,50,105,161,148,64,154,8,193,119,162,7,33,117,198,40,172,214,76,224,75,73,155,70,142,240,185,137,164,0,128,102,133,208,17,163,21,112,0,128,84,92,108,101,225,187,107,22,226,176,41,233,119,116,241,60,197,98,64,173,42,15,80,106,253,193,83,69,133,247,147,239,245,122,224,160,34,141,93,73,153,207,146,44,26,23,250,0,163,246,15,84,26,190,160,32,203,125,116,239,148,169,232,148,50,220,154,177,174,91,36,92,85,113,90,106,168,124,93,225,232,244,184,132,45,84,140,66,6,87,12,23,209,253,20,167,198,247,54,107,249,143,86,239,123,40,223,238,146,116,124,2,241,248,233,169,148,137,197,204,164,202,125,193,168,127,97,67,200,69,155,96,17,9,123,197,66,207,95,129,219,129,219,173,120,149,37,38,108,231,207,100,214,68,179,27,183,170,39,33,227,249,87,229,244,12,140,12,203,248,103,170,181,130,102,55,78,103,104,230,216,33,248,202,58,5,53,140,18,250,92,251,53,177,236,198, -231,141,158,233,31,192,238,196,82,170,54,236,26,112,18,69,44,158,178,67,221,23,98,123,95,87,14,39,83,64,253,60,33,20,40,76,9,228,213,115,198,101,167,42,198,230,130,127,64,17,84,82,188,137,169,205,217,149,89,225,232,206,41,207,29,3,163,159,145,212,229,73,163,14,183,59,136,227,71,38,206,0,89,196,10,113,188,125,243,3,246,205,160,134,57,29,12,222,92,156,95,145,213,145,170,76,94,74,153,20,120,10,153,20,28,82,216,41,164,206,243,132,45,10,71,32,28,167,104,214,205,228,68,236,217,241,44,8,24,182,201,206,63,190,125,139,3,19,26,70,89,202,118,99,232,7,108,225,164,200,144,204,245,43,74,174,230,250,154,114,53,1,40,191,190,95,40,20,10,46,21,198,116,39,209,255,51,7,207,197,169,36,156,16,122,11,180,162,13,236,70,236,187,87,238,107,32,133,165,160,78,200,9,183,39,186,58,113,51,241,15,172,61,56,59,177,159,182,248,202,204,167,174,238,184,173,39,175,95,157,251,136,242,46,103,224,24,121,250,3,222,132,170,148,154,196, -190,69,134,137,197,56,156,50,149,112,86,21,140,241,25,183,33,211,58,147,180,46,155,147,165,129,26,165,16,44,5,41,74,65,152,164,4,114,23,142,168,83,122,71,70,97,76,177,174,88,10,204,150,176,240,154,177,79,184,124,40,224,157,39,88,156,129,227,227,135,49,184,124,32,162,37,145,152,118,183,173,65,18,220,48,177,26,232,46,131,133,250,112,69,138,199,117,97,174,64,96,134,185,210,169,101,198,5,181,43,203,221,58,119,103,46,39,237,232,5,121,242,188,198,2,214,103,189,164,156,181,89,247,86,47,63,190,40,233,206,235,10,158,45,48,247,92,83,220,240,138,178,49,212,66,56,87,133,178,154,92,198,37,50,40,176,152,89,48,161,41,43,179,95,213,185,242,191,193,64,237,127,163,49,230,209,194,168,111,102,97,48,203,235,242,34,97,86,165,112,181,36,210,229,241,254,250,101,84,242,237,127,99,214,231,176,201,230,73,57,206,129,36,63,74,238,88,26,224,201,68,196,132,192,86,238,46,217,48,8,31,55,64,67,109,21,141,129,213,38,41,232,75,254,246,190, -223,232,205,127,213,138,52,112,105,99,219,78,115,25,248,233,250,148,195,232,76,23,202,187,149,228,84,212,39,157,53,137,64,24,40,228,73,146,109,66,39,197,22,100,80,98,196,232,144,5,9,93,16,248,176,95,228,229,30,234,87,141,200,141,26,187,25,197,16,134,18,153,233,149,67,107,179,34,47,55,18,9,18,39,49,142,40,90,205,145,162,251,137,228,67,213,147,76,229,33,25,232,22,107,40,60,165,0,206,87,184,81,109,231,226,40,14,152,2,102,100,203,8,76,167,12,124,197,65,21,110,204,50,49,77,230,84,232,19,183,2,210,60,240,40,20,252,90,128,163,42,11,186,63,182,241,32,68,182,93,16,238,94,86,38,231,226,79,117,208,81,0,154,65,73,141,74,77,243,137,88,228,135,56,32,10,46,40,68,168,29,98,145,66,213,87,8,214,164,136,250,139,76,17,245,179,65,88,62,178,142,54,2,169,32,195,126,223,179,169,59,253,196,130,53,164,225,176,164,11,31,12,162,228,235,122,105,49,248,244,124,122,6,193,125,181,5,168,181,160,162,180,96,163,206,130, -47,160,178,203,108,131,198,212,7,41,24,245,104,208,164,7,214,170,75,0,87,7,225,66,165,218,184,57,64,146,126,7,174,138,62,246,124,145,225,105,245,186,10,4,199,85,253,129,79,166,248,228,251,90,74,83,54,199,64,175,78,192,159,67,154,58,252,216,116,146,176,215,93,219,253,38,122,218,23,232,252,103,105,100,180,176,52,94,89,219,80,117,150,175,162,147,113,90,166,99,145,110,111,225,124,163,178,74,51,179,168,168,147,178,90,93,66,54,245,41,207,245,62,126,120,139,193,16,59,75,114,39,192,219,20,125,192,230,15,177,132,251,13,172,19,126,64,88,241,127,67,119,241,189,238,225,161,63,196,157,167,155,71,125,255,216,247,48,184,251,195,46,90,138,239,121,16,165,235,222,110,71,193,15,202,126,95,246,139,119,58,202,249,250,234,66,150,87,142,68,202,206,51,10,226,75,156,188,160,160,191,200,9,78,190,67,239,102,96,180,232,157,74,110,43,135,21,200,225,102,115,219,69,251,175,66,30,228,6,176,170,184,219,36,28,75,197,149,64,43,103,176,65,206,71,126, -29,193,228,101,7,255,47,143,32,205,168,116,138,135,145,87,68,254,242,190,151,25,155,113,86,105,84,88,224,67,242,224,18,157,137,205,67,33,148,248,144,30,121,227,76,158,157,104,159,91,164,137,72,130,36,146,41,6,159,209,27,24,154,97,50,138,170,64,39,84,169,29,188,253,43,99,80,45,37,120,193,66,172,61,24,223,229,64,28,9,199,92,115,11,254,100,127,167,154,137,238,198,98,94,14,173,100,96,219,178,185,54,13,173,241,189,221,152,205,251,205,152,152,76,153,201,246,235,44,150,231,220,87,36,127,242,190,87,254,83,187,103,125,123,133,84,170,248,74,237,191,153,232,70,150,198,165,174,84,65,25,204,198,251,88,208,230,231,107,249,201,187,60,47,164,101,59,59,144,248,100,155,11,171,112,121,116,199,179,213,180,180,78,250,250,74,153,58,176,48,234,248,152,221,21,216,114,159,212,141,56,149,252,235,58,10,3,125,196,181,244,217,120,71,219,121,143,202,219,108,60,171,145,176,20,27,206,219,228,43,185,76,192,144,2,150,202,19,24,105,36,178,99,96,92,72, -0,159,41,43,82,217,26,196,75,109,170,241,23,198,19,188,153,136,112,52,170,147,247,249,209,140,174,249,0,81,8,241,161,60,126,131,196,31,216,120,217,39,239,207,78,6,167,254,245,171,243,193,126,254,220,191,56,63,63,237,95,190,185,56,47,134,206,78,206,95,13,206,78,126,58,45,70,78,62,94,158,93,124,120,243,207,147,10,220,224,99,191,127,58,24,120,187,73,245,111,144,22,79,150,166,88,127,132,204,230,138,224,207,7,138,199,251,59,79,33,111,133,113,157,251,78,177,99,106,10,125,34,197,145,71,237,73,22,173,139,77,247,220,245,86,46,32,45,79,54,240,233,148,98,194,101,20,169,55,113,114,23,147,26,236,10,120,110,181,39,193,32,7,65,7,98,170,137,40,104,58,5,103,199,15,177,188,48,147,39,154,113,54,31,33,81,188,170,52,110,218,181,188,78,3,20,70,186,239,126,223,78,118,53,237,52,249,180,81,7,165,33,35,212,125,183,207,165,170,93,126,157,199,167,225,116,38,242,171,54,72,113,24,135,34,164,145,110,23,25,12,228,213,105,97,223, -90,244,34,140,194,127,171,243,247,16,66,6,200,5,220,218,63,240,191,89,68,217,20,11,104,40,137,99,38,32,2,220,160,12,62,45,9,29,211,5,10,14,182,101,255,96,140,151,45,199,95,85,134,63,219,246,230,224,0,224,240,93,53,201,11,121,194,136,148,102,171,71,222,95,12,222,252,12,148,70,75,164,81,183,251,33,185,207,212,174,242,179,185,159,175,70,17,41,108,93,159,72,86,0,175,193,78,113,85,34,175,43,138,234,128,235,246,16,24,255,66,200,89,58,4,203,203,153,91,95,119,210,117,47,95,123,223,73,150,58,93,243,74,172,170,101,118,20,110,126,244,244,216,38,182,49,94,212,30,138,36,79,248,84,238,138,57,105,235,2,14,246,76,70,52,184,81,87,159,165,90,139,93,237,201,103,98,58,29,80,61,33,25,128,164,5,200,61,19,76,72,29,179,163,163,21,168,212,237,86,77,128,172,25,21,102,117,5,155,98,227,49,7,53,47,205,9,147,133,253,123,119,183,147,81,126,39,70,6,198,28,41,236,81,120,191,195,240,254,185,66,70,241,102,118,192, -202,107,208,13,240,209,113,168,182,45,35,210,145,26,124,211,93,78,76,135,229,221,146,80,68,242,46,11,190,160,253,166,153,50,110,79,161,211,119,199,18,216,237,241,10,10,66,171,157,210,0,205,201,50,83,130,34,172,98,144,202,25,40,194,23,195,29,148,138,82,103,40,237,135,18,12,57,17,99,202,106,72,209,247,9,119,185,234,221,79,52,237,120,239,150,129,168,163,45,175,122,27,111,170,158,120,105,30,105,154,213,131,190,25,21,148,43,237,224,150,254,231,123,11,153,165,215,103,239,209,117,199,172,88,150,156,84,186,140,65,148,228,27,101,181,211,72,148,147,233,194,202,170,72,242,193,191,171,48,174,37,229,189,102,45,77,167,167,123,3,228,7,134,91,77,104,118,155,239,93,125,82,29,254,26,118,243,247,212,223,39,232,22,113,77,101,91,123,70,131,26,140,6,226,37,88,118,112,67,167,172,110,44,86,152,64,211,110,52,186,110,167,213,142,14,157,86,10,255,139,67,187,57,130,255,143,237,3,101,12,127,81,214,0,81,134,156,126,82,153,178,231,117,187,0,239, -2,188,11,240,46,192,187,199,142,132,38,234,83,21,85,205,110,119,246,10,100,128,9,128,138,87,121,172,2,165,197,90,156,191,217,38,17,125,98,90,64,247,221,41,100,129,175,252,235,211,159,251,144,34,254,120,234,229,104,17,184,79,198,225,4,138,104,255,0,195,61,108,190,254,193,52,77,178,133,237,31,64,86,101,23,176,100,171,73,205,103,204,114,220,214,142,243,90,114,158,107,59,59,206,235,60,109,158,127,192,180,98,159,194,229,202,236,7,184,101,193,120,166,96,252,131,24,236,123,177,11,108,163,211,220,26,214,117,54,242,16,100,144,198,64,128,176,143,114,106,253,99,117,35,160,158,164,211,237,103,121,235,236,124,197,101,240,94,14,26,251,127,207,91,220,199,157,229,236,98,112,249,211,233,63,86,124,69,94,23,25,115,190,73,0,242,123,202,233,3,42,224,116,7,221,174,0,63,172,220,21,224,7,180,43,201,100,99,169,169,109,52,212,87,151,148,107,186,176,135,112,122,8,155,221,64,166,186,123,255,99,81,174,127,122,222,255,240,143,247,88,241,234,76,239,65, -240,129,1,94,21,18,101,28,205,254,32,16,41,217,36,72,128,177,143,28,9,243,60,16,181,210,40,32,181,52,252,37,30,83,22,201,87,112,186,37,167,184,241,70,97,86,135,20,243,209,85,70,193,67,32,78,231,65,144,6,236,244,207,3,8,40,23,143,173,66,211,0,207,112,31,249,12,88,54,65,200,163,213,45,204,246,221,73,159,156,81,249,55,139,127,188,237,182,183,48,93,32,120,43,155,69,184,170,72,102,115,26,228,222,255,64,72,49,193,30,216,255,10,176,141,17,164,132,240,15,142,30,89,110,62,118,31,5,120,28,75,26,46,216,124,108,183,44,82,91,25,240,143,147,5,139,113,107,10,146,249,70,15,217,214,104,204,63,107,250,239,26,13,24,137,243,184,145,12,250,23,239,222,127,208,119,252,182,48,150,190,9,95,21,201,191,97,71,175,8,111,29,103,27,249,90,65,244,212,185,185,94,86,245,240,22,82,165,12,210,241,63,220,115,183,240,219,183,144,86,127,60,129,204,122,27,231,45,128,171,202,192,70,142,55,236,95,205,132,88,112,213,202,17,73,18, -113,191,30,50,49,241,49,237,242,15,103,98,30,249,135,233,36,104,182,154,173,43,242,225,117,223,63,192,71,60,202,84,127,248,41,11,80,94,207,139,38,137,221,243,254,3,138,221,87,36, +120,156,237,27,253,115,218,200,245,95,217,185,244,174,56,131,177,36,16,96,184,118,236,35,206,57,115,137,157,9,73,123,45,35,91,139,180,128,106,33,169,90,201,14,189,94,254,246,190,183,187,146,86,24,108,176,47,189,254,208,76,98,131,244,246,237,251,254,218,205,36,232,116,250,67,106,217,195,155,159,46,143,135,22,249,195,31,204,166,241,162,221,51,219,125,187,109,118,172,46,252,48,219,166,101,91,237,142,217,183,142,59,253,118,187,111,12,188,144,114,238,76,66,171,223,23,139,172,166,245,194,234,217,150,217,235,244,59,125,179,221,235,91,176,214,50,12,203,232,89,182,217,105,247,45,123,224,51,238,57,19,3,192,219,176,199,113,183,125,108,152,134,209,51,77,163,109,245,140,182,221,49,205,182,5,40,172,158,101,26,246,128,69,190,51,57,239,14,113,65,7,22,24,118,215,48,140,46,96,235,116,12,192,142,203,58,109,179,109,88,109,219,60,182,187,131,41,155,7,145,51,185,207,146,253,40,75,61,99,16,100,108,169,56,162,157,225,203,19,123,104,194,210,110,179,251, +162,7,219,118,108,216,236,24,57,106,195,50,203,234,218,199,166,221,1,146,58,134,53,72,217,63,243,32,101,75,22,101,10,67,96,154,150,57,156,154,189,33,144,240,229,203,151,150,217,49,164,164,122,64,139,105,0,221,150,9,207,128,143,158,105,31,27,199,118,223,236,27,237,94,199,178,123,192,122,66,83,186,84,156,76,59,214,80,241,209,111,246,95,116,205,46,72,212,232,3,253,246,49,32,48,128,9,248,13,130,180,225,111,187,63,200,212,98,92,135,139,142,155,199,47,64,72,109,219,232,29,27,189,78,207,238,0,39,150,217,53,65,144,6,242,15,106,24,68,113,186,164,161,51,193,5,6,202,250,145,63,131,87,108,70,243,16,216,253,229,250,87,50,33,191,252,98,226,227,147,6,168,176,213,177,90,198,1,153,112,99,248,237,183,100,242,242,164,55,236,144,49,95,140,25,231,65,28,57,206,175,191,126,231,76,120,123,72,240,151,57,28,124,74,18,119,224,14,42,16,252,38,44,108,64,38,39,13,163,101,180,128,217,131,54,81,86,215,38,215,206,228,101,91,199,137, +207,6,240,84,135,78,242,105,24,120,5,248,73,123,40,86,56,184,169,49,124,33,212,4,244,125,92,4,92,34,38,44,242,104,194,243,144,102,140,19,74,56,243,242,148,17,190,96,97,72,26,183,44,197,157,136,117,0,208,1,104,26,222,139,189,91,228,77,70,0,71,202,120,18,71,60,152,134,140,204,226,148,48,158,81,32,128,47,130,104,222,36,52,207,22,176,40,240,104,38,191,71,62,89,210,136,130,197,206,97,47,47,93,37,89,60,79,105,178,0,144,48,92,169,221,125,181,189,218,139,192,95,26,145,241,248,220,34,94,188,76,194,128,10,66,82,160,174,165,201,67,49,4,84,249,44,13,110,1,205,44,141,151,100,114,149,197,73,224,129,120,143,220,163,81,156,50,247,8,80,185,71,60,245,220,35,212,194,53,160,112,175,127,160,156,185,215,44,114,15,115,238,190,168,180,83,170,229,74,8,146,76,1,78,238,36,249,89,80,78,0,253,13,16,4,172,1,175,188,85,41,186,48,145,215,13,211,234,31,252,40,126,158,152,149,149,144,247,66,93,228,29,203,22,177,79, +222,6,60,91,179,20,123,139,165,124,12,150,44,206,51,183,17,68,153,123,0,38,115,125,117,15,238,170,102,44,149,149,16,247,59,231,26,54,87,56,156,134,254,14,240,225,203,147,54,89,114,231,0,73,176,144,214,49,203,56,201,228,2,114,75,195,156,1,36,89,6,160,107,230,197,145,207,91,8,130,106,38,160,243,53,200,44,38,23,57,40,52,201,17,9,188,214,148,22,79,255,193,188,12,183,141,201,52,140,189,27,68,177,140,125,214,34,31,88,150,167,17,39,238,203,12,237,21,237,107,41,5,229,45,104,16,1,96,139,92,196,25,224,95,80,48,8,190,32,60,159,242,21,135,152,198,133,110,0,44,138,88,8,54,17,45,192,36,50,220,59,72,193,60,132,27,215,137,228,210,90,36,68,97,229,82,17,192,62,126,232,60,172,145,17,152,102,170,190,54,166,113,28,62,85,45,26,162,186,106,16,169,210,205,212,185,118,255,116,173,191,204,210,156,105,250,58,139,192,15,129,41,144,153,31,112,249,249,239,194,125,20,106,33,78,159,102,20,86,210,136,207,192,211,119,147, +184,70,158,240,53,137,221,39,211,85,33,216,150,140,47,106,37,157,205,64,193,82,239,119,139,24,2,69,25,67,62,130,86,24,108,2,182,148,145,101,206,51,50,69,179,186,141,111,0,31,11,96,69,10,79,4,0,141,86,64,61,104,211,203,112,99,154,129,146,147,12,217,187,3,56,48,69,68,191,163,171,23,74,219,224,237,154,62,255,10,161,107,20,71,179,96,126,69,170,207,14,97,183,16,210,234,98,224,222,2,242,32,68,84,8,83,192,1,79,152,23,204,2,224,225,54,160,210,29,80,196,73,156,102,133,80,184,244,21,61,86,60,102,95,23,113,205,194,158,106,93,53,52,78,163,178,152,87,27,205,4,220,154,46,65,252,92,103,184,49,163,33,103,7,255,183,151,221,237,101,119,61,255,196,86,220,109,0,237,192,94,1,144,165,32,74,247,59,183,185,223,227,231,68,33,36,163,30,126,196,38,240,174,66,38,54,2,68,226,247,6,36,16,168,146,52,184,97,43,167,73,158,143,41,159,254,86,152,22,41,36,241,53,76,90,112,197,68,48,11,66,246,64,140,53,134, +69,41,37,19,227,2,93,100,181,4,19,78,33,157,67,77,133,165,13,26,30,144,204,49,255,129,161,230,28,172,20,62,106,85,17,19,43,75,251,158,124,123,168,209,87,132,147,98,157,15,81,37,65,19,199,53,32,215,91,92,15,248,155,104,213,224,16,10,28,237,124,69,26,81,156,65,117,6,158,12,5,186,207,252,29,157,181,74,167,119,64,163,116,18,73,84,41,20,34,74,109,150,1,33,128,5,69,210,44,9,151,202,22,185,183,120,36,181,70,184,208,7,7,239,131,58,96,138,17,145,1,249,62,6,22,196,10,72,179,133,16,20,110,137,85,37,58,238,173,224,79,0,112,21,36,2,41,236,34,133,79,217,130,222,6,113,14,133,224,37,186,255,29,148,35,8,176,218,180,209,146,45,227,116,69,166,249,12,179,29,218,78,38,249,150,250,243,178,156,134,66,97,186,28,2,81,231,38,49,151,69,46,80,136,209,49,135,215,178,212,150,20,98,233,160,125,111,208,27,218,210,117,36,148,14,58,248,24,131,113,96,252,3,188,77,194,3,168,102,87,164,12,193,9,214,175, +160,69,169,66,208,143,168,154,234,146,220,171,38,145,117,165,44,18,155,10,226,47,88,237,60,53,42,72,132,219,42,198,108,149,8,183,42,17,139,189,174,136,248,85,84,149,18,195,122,101,41,76,154,129,94,176,252,191,151,46,209,86,17,68,125,85,18,17,219,129,76,75,104,245,92,65,57,149,161,46,233,170,80,55,246,56,160,242,176,64,38,188,135,18,168,99,33,59,204,212,67,168,237,49,77,200,61,99,120,83,209,166,144,35,124,97,190,41,0,160,201,35,116,200,104,13,28,0,160,87,200,118,242,190,253,53,11,137,66,151,244,59,154,60,79,177,24,241,235,202,3,148,74,127,240,169,166,194,251,221,193,102,61,112,80,145,194,46,165,204,23,113,30,250,165,62,192,168,221,67,217,39,36,20,100,217,196,208,147,50,25,57,83,134,181,3,54,158,165,7,42,169,161,242,85,11,166,234,247,10,182,84,49,10,25,194,68,144,132,247,107,176,6,63,216,174,229,223,91,189,239,33,18,220,197,169,127,10,97,227,233,181,158,142,69,47,245,170,156,165,53,232,144,172,10,209, +198,216,229,66,40,75,212,250,53,184,61,184,221,137,87,17,55,161,222,120,38,179,58,154,253,184,213,34,247,87,229,244,28,140,12,231,12,207,84,107,13,205,126,156,46,208,204,113,132,241,149,117,10,106,152,198,244,185,246,171,99,217,143,207,27,181,210,61,132,236,196,82,42,139,137,6,112,18,134,44,154,179,35,53,184,98,7,95,87,14,167,115,64,253,60,33,148,40,116,9,20,237,125,206,197,40,45,194,233,135,123,72,17,84,80,188,141,169,237,149,159,222,130,169,209,46,47,28,3,163,159,86,204,20,5,173,10,183,123,136,227,71,150,157,3,178,144,149,226,120,251,230,7,28,236,65,147,117,54,30,191,185,188,184,34,235,79,234,50,121,41,100,82,226,41,101,82,114,72,33,83,8,157,23,197,100,24,76,65,56,86,57,77,92,136,133,56,84,228,185,231,49,156,227,93,124,122,251,22,31,204,104,16,230,41,219,143,161,31,112,198,148,34,67,162,25,169,41,185,222,140,40,202,229,2,160,252,250,126,39,83,42,184,82,24,83,163,78,247,143,28,60,23,151,146,96, +70,232,45,208,138,54,176,31,177,239,94,217,175,129,20,150,130,58,161,38,220,157,232,250,194,237,196,63,176,247,248,252,212,124,218,230,107,43,159,186,187,101,119,159,188,127,125,237,35,202,251,184,0,199,40,202,31,240,38,84,165,208,164,106,29,124,226,7,115,38,11,206,186,130,49,62,99,26,210,173,51,78,91,162,15,168,12,84,107,79,96,43,40,81,74,194,4,37,80,187,112,68,157,210,59,50,13,34,138,61,207,42,195,106,9,155,194,5,251,140,219,7,25,124,231,177,234,111,240,133,15,46,239,101,208,143,8,76,251,219,214,56,246,110,88,182,30,232,62,122,137,124,113,69,202,143,155,194,92,137,64,15,115,149,83,139,138,11,250,106,86,184,117,225,206,92,44,218,211,11,138,226,121,131,5,108,174,122,73,181,106,187,238,171,161,64,69,119,209,87,240,60,193,218,115,67,115,195,107,202,198,80,91,118,128,114,113,21,151,200,184,196,162,87,193,132,166,172,170,126,229,104,205,253,6,3,181,251,141,194,88,68,11,173,191,89,4,222,162,152,25,148,5,179,108,211, +235,45,145,106,221,155,155,183,145,197,183,251,141,222,51,67,146,45,138,114,92,3,69,126,24,223,177,212,195,163,147,144,101,25,206,154,247,169,134,65,248,152,0,53,181,213,52,6,86,27,167,160,47,241,219,249,126,171,55,255,89,41,82,195,165,140,109,55,205,229,224,167,155,75,14,109,116,94,42,239,86,144,83,83,159,112,214,56,4,97,160,144,103,113,190,13,157,16,155,151,67,139,17,161,67,150,36,12,64,224,147,81,89,151,59,168,95,249,68,36,106,156,15,148,143,48,148,136,74,175,122,180,177,42,114,10,35,17,32,81,28,225,19,73,171,254,164,28,207,34,249,208,245,196,115,113,138,7,186,197,30,10,143,81,128,243,53,110,228,92,188,60,43,4,166,128,25,49,206,2,211,169,2,95,121,146,134,137,89,20,166,241,146,102,234,72,176,132,212,79,100,74,5,191,206,192,81,119,58,156,17,163,224,109,115,213,131,193,198,89,32,81,203,126,131,57,104,158,134,90,191,172,240,138,66,138,202,147,77,41,10,237,236,64,49,174,122,105,92,175,149,113,105,174,87,48, +173,106,132,52,94,65,232,254,92,36,150,79,31,222,162,228,177,141,21,102,135,103,203,35,192,230,78,176,94,252,55,247,18,248,49,203,224,39,251,204,60,215,25,28,29,185,19,52,243,65,97,98,238,137,235,160,37,185,147,1,154,160,235,56,96,18,45,103,191,131,177,7,101,223,20,195,169,189,6,219,95,95,93,200,242,218,128,184,26,115,161,32,126,139,57,52,10,250,55,153,103,23,225,96,63,3,163,229,160,70,112,91,155,218,34,135,219,205,109,31,237,191,10,184,87,24,192,186,226,110,227,192,23,138,171,128,214,78,164,188,130,143,226,112,86,231,101,143,164,95,29,200,232,153,227,12,143,102,174,136,248,229,124,47,210,131,118,114,163,149,115,224,67,226,24,7,157,137,45,131,44,147,226,67,122,196,253,27,49,68,86,62,151,164,113,22,123,113,40,226,25,95,208,27,120,180,192,204,135,170,64,39,148,121,4,190,253,51,103,169,24,243,114,150,109,60,38,220,231,120,16,9,199,196,182,3,127,162,153,172,167,189,253,88,44,106,175,181,112,191,43,155,27,115,94,131, +31,236,199,108,49,220,26,129,156,231,76,103,251,117,30,137,83,191,43,82,124,114,190,151,254,211,184,103,125,7,165,84,234,248,42,237,191,153,169,174,89,225,146,23,76,160,230,102,126,19,171,231,226,160,161,56,135,20,7,39,180,154,157,121,2,159,232,169,177,228,23,103,24,60,95,207,129,45,50,82,23,108,228,116,84,107,26,34,118,87,98,43,124,82,117,253,178,210,80,69,27,6,250,144,43,233,51,127,79,219,121,143,202,219,110,60,235,145,176,18,27,174,219,230,43,133,76,192,144,60,150,138,113,175,48,18,209,158,104,199,179,224,51,85,249,43,230,16,120,197,71,78,25,130,104,134,247,180,16,142,134,45,242,190,152,3,171,2,19,16,65,43,163,29,74,65,149,1,108,188,28,145,247,231,167,227,51,247,250,213,197,184,89,124,30,93,94,92,156,141,62,190,185,188,40,31,157,159,94,188,130,254,238,167,179,242,201,233,167,143,231,151,31,222,252,253,180,6,55,254,52,26,157,141,199,206,126,82,253,11,75,131,217,74,23,235,143,52,99,87,4,127,62,80,169,222, +207,60,165,188,37,198,77,238,59,199,241,140,46,244,153,16,71,17,181,103,121,184,41,54,221,115,215,91,177,129,176,60,49,45,164,115,80,27,254,46,43,226,155,40,190,139,72,3,178,2,14,201,15,4,24,212,32,232,64,76,78,44,50,154,206,193,217,241,69,36,174,15,224,0,9,227,90,148,47,167,72,20,175,43,141,235,118,45,46,23,0,133,161,26,242,221,183,147,125,77,59,141,63,111,213,65,101,200,8,117,223,237,11,169,42,151,223,228,241,105,48,95,100,197,197,3,164,56,136,130,44,160,161,234,77,53,6,138,82,184,180,111,37,250,44,8,131,127,201,131,200,0,66,6,200,5,220,218,61,116,191,73,194,124,142,213,58,212,223,17,203,32,2,220,160,12,62,175,8,245,105,130,130,131,180,236,30,250,120,245,204,255,170,50,252,217,52,183,7,7,0,135,247,114,34,87,202,19,158,8,105,118,135,228,253,229,248,205,207,64,105,184,66,26,213,108,17,122,250,92,102,149,159,245,124,190,30,69,132,176,65,178,119,208,183,8,86,0,175,198,78,121,102,140,36,139, +91,131,104,172,52,242,132,37,98,47,10,198,159,100,98,149,10,193,226,170,218,206,151,63,70,234,14,217,198,219,31,184,97,253,130,160,120,228,236,41,220,98,206,253,88,18,219,26,47,26,15,69,146,39,188,170,178,98,65,218,166,128,131,13,218,148,122,55,242,34,168,80,107,153,213,158,60,128,87,229,128,108,64,69,0,18,22,32,114,38,152,144,60,211,67,71,43,81,201,187,126,138,0,49,42,146,152,229,133,84,138,83,142,2,84,191,66,148,233,44,52,239,221,100,141,167,197,229,0,17,24,11,164,144,163,240,48,89,243,254,165,68,70,241,158,170,199,170,75,161,109,240,81,63,144,105,75,139,116,164,1,239,212,72,5,203,97,113,144,29,100,161,56,56,199,47,104,191,105,46,141,219,145,232,212,77,154,24,178,61,158,119,35,180,204,148,26,104,65,150,94,18,148,97,21,131,84,193,64,25,190,24,102,80,154,85,58,67,105,63,84,96,136,133,24,83,214,67,138,186,93,181,207,197,215,81,172,104,199,91,136,12,68,29,238,120,241,85,251,38,251,137,151,250,249,137, +222,61,168,43,34,94,181,211,30,110,233,126,185,183,145,222,122,125,113,30,221,215,103,229,182,228,180,54,210,240,194,184,72,148,245,177,6,145,78,166,26,43,163,38,201,7,111,153,107,119,32,138,193,150,146,166,53,84,179,1,242,3,195,84,19,232,163,173,123,247,44,228,56,177,129,163,195,3,121,91,91,205,163,26,178,218,58,208,166,97,96,52,16,47,193,178,189,27,58,103,45,109,179,210,4,58,102,187,61,176,251,221,94,120,100,117,83,248,151,29,153,157,41,252,59,49,15,165,49,252,73,90,3,68,25,114,246,89,86,202,142,51,24,0,188,13,240,54,192,219,0,111,159,88,2,154,200,87,117,84,13,179,215,63,40,145,1,38,0,42,191,138,25,46,180,22,27,113,254,219,212,137,24,17,221,2,6,239,206,160,10,124,229,94,159,253,60,130,18,241,199,51,167,64,139,192,35,226,7,51,104,162,221,67,12,247,144,124,221,195,121,26,231,137,233,30,66,85,101,150,176,100,167,69,157,103,172,178,236,238,158,235,186,98,157,109,90,123,174,235,63,109,157,123,200,148, +98,159,194,229,218,234,7,184,101,158,191,144,48,238,97,4,246,157,236,3,219,238,119,118,134,181,173,173,60,120,57,148,49,16,32,204,227,130,90,247,68,30,63,182,226,116,190,251,42,103,147,157,175,185,12,94,2,64,99,255,239,121,139,253,184,179,156,95,142,63,254,116,246,183,53,95,17,103,211,62,231,219,4,32,222,167,156,62,160,2,78,247,208,237,26,240,195,202,93,3,126,64,187,130,76,230,11,77,237,162,161,145,188,173,217,80,141,61,132,211,35,72,118,99,81,234,30,252,143,69,185,209,217,197,232,195,223,222,99,199,171,42,189,7,193,199,26,120,93,72,148,113,52,251,67,47,75,201,54,65,2,140,121,108,9,152,231,129,200,157,166,30,105,164,193,63,34,159,178,80,124,5,167,91,113,138,137,55,12,242,22,148,152,143,238,50,245,30,2,177,250,15,130,180,33,211,63,15,192,163,60,123,108,23,154,122,120,96,244,200,107,192,178,13,66,156,227,236,96,182,239,78,71,228,156,138,255,193,245,251,219,110,111,7,211,5,130,119,178,89,132,171,139,100,177,164, +94,225,253,15,132,20,29,236,129,252,87,130,109,141,32,21,132,123,120,252,200,118,75,223,126,20,224,113,44,105,144,176,165,111,118,13,210,88,123,224,158,196,9,139,48,53,121,241,114,171,135,236,106,52,250,127,242,248,239,26,13,24,137,245,184,145,140,71,151,239,222,127,80,23,138,118,48,150,145,14,95,23,201,191,32,163,215,132,183,137,179,173,124,173,33,122,234,218,66,47,235,122,120,11,165,82,14,229,248,239,238,185,59,248,237,91,40,171,63,157,66,101,189,139,243,150,192,117,101,224,32,199,153,140,174,22,89,150,112,57,202,201,226,56,228,110,43,96,217,204,197,178,203,61,90,100,203,208,61,74,103,94,167,219,233,94,145,15,175,71,238,33,126,196,163,76,249,223,224,68,3,202,91,69,211,36,176,59,206,127,0,33,114,88,67,