summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2018-09-11 14:48:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2018-09-11 14:48:30 +0000
commitc7f654b441e11fb4d0f9d7e89c46c29a2ea26e96 (patch)
tree42d8ebb36b70f9e526c6d9de30aa98e791f7d829
parentReleasing progress-linux version 0.8.0~20170825.94fa1e38-2~dschinn1. (diff)
downloadlibssh-c7f654b441e11fb4d0f9d7e89c46c29a2ea26e96.zip
libssh-c7f654b441e11fb4d0f9d7e89c46c29a2ea26e96.tar.xz
Merging upstream version 0.8.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.clang_complete13
-rw-r--r--.gitignore9
-rw-r--r--.gitlab-ci.yml302
-rw-r--r--CMakeLists.txt123
-rw-r--r--CPackConfig.cmake23
-rw-r--r--ChangeLog49
-rw-r--r--ConfigureChecks.cmake56
-rw-r--r--DefineOptions.cmake25
-rw-r--r--INSTALL16
-rw-r--r--README.CodingStyle21
-rw-r--r--README.mbedtls11
-rw-r--r--README.md44
-rw-r--r--cmake/Modules/AddCMockaTest.cmake10
-rw-r--r--cmake/Modules/ExtractSymbols.cmake88
-rw-r--r--cmake/Modules/FindABIMap.cmake394
-rw-r--r--cmake/Modules/FindGCrypt.cmake4
-rw-r--r--cmake/Modules/FindMbedTLS.cmake104
-rw-r--r--cmake/Modules/GenerateMap.cmake118
-rw-r--r--cmake/Modules/GetFilesList.cmake59
-rw-r--r--cmake/Toolchain-cross-m32.cmake23
-rw-r--r--config.h.cmake32
-rw-r--r--doc/authentication.dox2
-rw-r--r--doc/guided_tour.dox152
-rw-r--r--doc/mainpage.dox6
-rw-r--r--examples/CMakeLists.txt8
-rw-r--r--examples/knownhosts.c16
-rw-r--r--examples/scp_download.c9
-rw-r--r--examples/senddata.c2
-rw-r--r--examples/ssh_client.c (renamed from examples/sample.c)0
-rw-r--r--examples/ssh_server_fork.c12
-rw-r--r--include/libssh/CMakeLists.txt7
-rw-r--r--include/libssh/agent.h1
-rw-r--r--include/libssh/auth.h16
-rw-r--r--include/libssh/bignum.h1
-rw-r--r--include/libssh/buffer.h5
-rw-r--r--include/libssh/chacha.h41
-rw-r--r--include/libssh/channels.h16
-rw-r--r--include/libssh/crypto.h29
-rw-r--r--include/libssh/dh.h16
-rw-r--r--include/libssh/ecdh.h4
-rw-r--r--include/libssh/ge25519.h2
-rw-r--r--include/libssh/kex.h3
-rw-r--r--include/libssh/keys.h6
-rw-r--r--include/libssh/knownhosts.h8
-rw-r--r--include/libssh/libcrypto.h23
-rw-r--r--include/libssh/libgcrypt.h9
-rw-r--r--include/libssh/libmbedcrypto.h113
-rw-r--r--include/libssh/libssh.h52
-rw-r--r--include/libssh/libsshpp.hpp81
-rw-r--r--include/libssh/misc.h3
-rw-r--r--include/libssh/packet.h16
-rw-r--r--include/libssh/pcap.h1
-rw-r--r--include/libssh/pki.h11
-rw-r--r--include/libssh/pki_priv.h4
-rw-r--r--include/libssh/poly1305.h21
-rw-r--r--include/libssh/priv.h49
-rw-r--r--include/libssh/server.h18
-rw-r--r--include/libssh/session.h14
-rw-r--r--include/libssh/sftp.h23
-rw-r--r--include/libssh/ssh1.h82
-rw-r--r--include/libssh/threads.h32
-rw-r--r--include/libssh/wrapper.h11
-rw-r--r--libssh-config.cmake.in2
-rwxr-xr-xobj/build_make.sh197
-rw-r--r--src/ABI/current1
-rw-r--r--src/ABI/libssh-4.5.0.symbols411
-rw-r--r--src/CMakeLists.txt103
-rw-r--r--src/agent.c111
-rw-r--r--src/auth.c676
-rw-r--r--src/auth1.c236
-rw-r--r--src/base64.c6
-rw-r--r--src/bignum.c14
-rw-r--r--src/bind.c49
-rw-r--r--src/buffer.c199
-rw-r--r--src/chachapoly.c212
-rw-r--r--src/channels.c147
-rw-r--r--src/channels1.c396
-rw-r--r--src/client.c234
-rw-r--r--src/config.c259
-rw-r--r--src/connect.c21
-rw-r--r--src/connector.c25
-rw-r--r--src/crc32.c95
-rw-r--r--src/curve25519.c51
-rw-r--r--src/dh.c321
-rw-r--r--src/ecdh.c18
-rw-r--r--src/ecdh_crypto.c11
-rw-r--r--src/ecdh_gcrypt.c15
-rw-r--r--src/ecdh_mbedcrypto.c305
-rw-r--r--src/error.c4
-rw-r--r--src/external/bcrypt_pbkdf.c8
-rw-r--r--src/external/chacha.c218
-rw-r--r--src/external/ed25519.c6
-rw-r--r--src/external/fe25519.c2
-rw-r--r--src/external/ge25519.c2
-rw-r--r--src/external/poly1305.c156
-rw-r--r--src/external/sc25519.c2
-rw-r--r--src/gcrypt_missing.c11
-rw-r--r--src/getpass.c2
-rw-r--r--src/gssapi.c62
-rw-r--r--src/gzip.c2
-rw-r--r--src/init.c183
-rw-r--r--src/kex.c152
-rw-r--r--src/kex1.c497
-rw-r--r--src/known_hosts.c321
-rw-r--r--src/knownhosts.c886
-rw-r--r--src/legacy.c32
-rw-r--r--src/libcrypto.c207
-rw-r--r--src/libgcrypt.c195
-rw-r--r--src/libmbedcrypto.c1014
-rw-r--r--src/libssh.map420
-rw-r--r--src/log.c8
-rw-r--r--src/match.c5
-rw-r--r--src/mbedcrypto_missing.c128
-rw-r--r--src/messages.c9
-rw-r--r--src/misc.c77
-rw-r--r--src/options.c184
-rw-r--r--src/packet.c190
-rw-r--r--src/packet1.c373
-rw-r--r--src/packet_cb.c24
-rw-r--r--src/packet_crypt.c157
-rw-r--r--src/pcap.c14
-rw-r--r--src/pki.c72
-rw-r--r--src/pki_container_openssh.c27
-rw-r--r--src/pki_crypto.c73
-rw-r--r--src/pki_ed25519.c31
-rw-r--r--src/pki_gcrypt.c67
-rw-r--r--src/pki_mbedcrypto.c1278
-rw-r--r--src/poll.c27
-rw-r--r--src/scp.c2
-rw-r--r--src/server.c287
-rw-r--r--src/session.c67
-rw-r--r--src/sftp.c158
-rw-r--r--src/sftpserver.c9
-rw-r--r--src/socket.c6
-rw-r--r--src/string.c8
-rw-r--r--src/threads.c199
-rw-r--r--src/threads/CMakeLists.txt132
-rw-r--r--src/threads/libcrypto.c125
-rw-r--r--src/threads/libgcrypt.c74
-rw-r--r--src/threads/mbedtls.c65
-rw-r--r--src/threads/noop.c74
-rw-r--r--src/threads/pthread.c139
-rw-r--r--src/threads/winlocks.c123
-rw-r--r--src/wrapper.c198
-rw-r--r--tests/CMakeLists.txt43
-rw-r--r--tests/chroot_wrapper.c8
-rw-r--r--tests/client/CMakeLists.txt2
-rw-r--r--tests/client/torture_algorithms.c208
-rw-r--r--tests/client/torture_auth.c8
-rw-r--r--tests/client/torture_connect.c31
-rw-r--r--tests/client/torture_forward.c4
-rw-r--r--tests/client/torture_hostkey.c230
-rw-r--r--tests/client/torture_knownhosts.c60
-rw-r--r--tests/client/torture_knownhosts_verify.c383
-rw-r--r--tests/client/torture_proxycommand.c9
-rw-r--r--tests/client/torture_request_env.c8
-rw-r--r--tests/client/torture_session.c15
-rw-r--r--tests/client/torture_sftp_dir.c2
-rw-r--r--tests/client/torture_sftp_ext.c2
-rw-r--r--tests/client/torture_sftp_fsync.c4
-rw-r--r--tests/client/torture_sftp_read.c2
-rw-r--r--tests/ctest-default.cmake4
-rw-r--r--tests/fuzz/CMakeLists.txt9
-rw-r--r--tests/fuzz/ssh_server_fuzzer.cpp101
-rw-r--r--tests/pkd/CMakeLists.txt23
-rw-r--r--tests/pkd/pkd_client.h51
-rw-r--r--tests/pkd/pkd_daemon.c25
-rw-r--r--tests/pkd/pkd_daemon.h9
-rw-r--r--tests/pkd/pkd_hello.c359
-rw-r--r--tests/pkd/pkd_keyutil.c21
-rw-r--r--tests/pkd/pkd_keyutil.h13
-rw-r--r--tests/pkd/pkd_util.c63
-rw-r--r--tests/sftp_stress/main.c2
-rw-r--r--tests/test_exec.c2
-rw-r--r--tests/test_ssh_bind_accept_fd.c8
-rw-r--r--tests/test_tunnel.c2
-rw-r--r--tests/torture.c431
-rw-r--r--tests/torture.h10
-rw-r--r--tests/torture_cmocka.c100
-rw-r--r--tests/torture_cmocka.h55
-rw-r--r--tests/torture_key.c385
-rw-r--r--tests/torture_key.h36
-rw-r--r--tests/torture_pki.c91
-rw-r--r--tests/torture_pki.h3
-rw-r--r--tests/unittests/CMakeLists.txt35
-rw-r--r--tests/unittests/torture_buffer.c2
-rw-r--r--tests/unittests/torture_callbacks.c2
-rw-r--r--tests/unittests/torture_channel.c4
-rw-r--r--tests/unittests/torture_config.c207
-rw-r--r--tests/unittests/torture_crypto.c2
-rw-r--r--tests/unittests/torture_init.c2
-rw-r--r--tests/unittests/torture_isipaddr.c75
-rw-r--r--tests/unittests/torture_keyfiles.c22
-rw-r--r--tests/unittests/torture_knownhosts_parsing.c289
-rw-r--r--tests/unittests/torture_list.c8
-rw-r--r--tests/unittests/torture_misc.c77
-rw-r--r--tests/unittests/torture_options.c103
-rw-r--r--tests/unittests/torture_packet.c208
-rw-r--r--tests/unittests/torture_pki.c1718
-rw-r--r--tests/unittests/torture_pki_dsa.c488
-rw-r--r--tests/unittests/torture_pki_ecdsa.c537
-rw-r--r--tests/unittests/torture_pki_ed25519.c436
-rw-r--r--tests/unittests/torture_pki_rsa.c567
-rw-r--r--tests/unittests/torture_rand.c15
-rw-r--r--tests/unittests/torture_server_x11.c6
-rw-r--r--tests/unittests/torture_threads_buffer.c596
-rw-r--r--tests/unittests/torture_threads_crypto.c181
-rw-r--r--tests/unittests/torture_threads_init.c95
-rw-r--r--tests/unittests/torture_threads_pki_rsa.c743
209 files changed, 17406 insertions, 7190 deletions
diff --git a/.clang_complete b/.clang_complete
deleted file mode 100644
index b5a5040..0000000
--- a/.clang_complete
+++ /dev/null
@@ -1,13 +0,0 @@
--DWITH_SERVER=1
--DWITH_GSSAPI=1
--DWITH_ZLIB=1
--DWITH_SFTP=1
--DWITH_SSH1=1
--DWITH_PCAP=1
--DHAVE_ECDH=1
--DHAVE_ECC=1
--Iinclude/libssh
--Iinclude
--Ibuild
--Itests
--Isrc
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 0baa4fa..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-*.a
-*.o
-.*
-*.swp
-*~$
-cscope.*
-tags
-/build
-/obj*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..abdb7c4
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,302 @@
+variables:
+ BUILD_IMAGES_PROJECT: libssh/build-images
+ FEDORA_BUILD: buildenv-fedora
+ CENTOS7_BUILD: buildenv-centos7
+ TUMBLEWEED_BUILD: buildenv-tumbleweed
+ MINGW_BUILD: buildenv-mingw
+ DEBIAN_CROSS_BUILD: buildenv-debian-cross
+
+# torture_auth fails on centos7 docker images, so we don't use -DCLIENT_TESTING=ON
+centos7/openssl_1.0.x/x86-64:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake3 -DUNIT_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
+ -DWITH_PCAP=ON .. && make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+fedora/openssl_1.1.x/x86-64:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
+ make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+# Address sanitizer doesn't mix well with LD_PRELOAD used in the testsuite
+.fedora/address-sanitizer:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake
+ -DCMAKE_C_FLAGS="-O2 -g -fsanitize=address"
+ -DCMAKE_LINK_FLAGS="-fsanitize=address -static-libasan"
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
+ make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+fedora/undefined-sanitizer:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake
+ -DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
+ && make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+fedora/static-analysis:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
+ script:
+ - export CCC_CC=clang
+ - export CCC_CXX=clang++
+ - mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
+ -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. &&
+ scan-build --status-bugs -o scan make -j$(nproc)
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/scan
+
+# That is a specific runner that we cannot enable universally.
+# We restrict it to builds under the $BUILD_IMAGES_PROJECT project.
+freebsd/x86-64:
+ image:
+ script:
+ - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON .. &&
+ make && ctest --output-on-failure
+ tags:
+ - freebsd
+ except:
+ - tags
+ only:
+ - branches@libssh/libssh-mirror
+ - branches@cryptomilk/libssh-mirror
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+fedora/libgcrypt/x86-64:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
+ -DWITH_GCRYPT=ON .. &&
+ make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+fedora/mbedtls/x86-64:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
+ -DWITH_MBEDTLS=ON .. &&
+ make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+tumbleweed/openssl_1.1.x/x86-64:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
+ make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+tumbleweed/openssl_1.1.x/x86:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-m32.cmake
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON .. &&
+ make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+tumbleweed/undefined-sanitizer:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
+ script:
+ - mkdir -p obj && cd obj && cmake
+ -DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
+ && make -j$(nproc) && ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+tumbleweed/static-analysis:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
+ script:
+ - export CCC_CC=clang
+ - export CCC_CXX=clang++
+ - mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
+ -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. &&
+ scan-build --status-bugs -o scan make -j$(nproc)
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/scan
+
+# Unit testing only, no client and pkd testing, because cwrap is not available
+# for MinGW
+mingw64:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
+ script:
+ - Xvfb :1 -screen 0 1024x768x16 -ac +extension GLX +render -noreset -nolisten tcp &
+ - export DISPLAY=:1
+ - mkdir -p obj && cd obj && mingw64-cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON .. &&
+ make -j$(nproc)
+ - export WINEPATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
+ - ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+# Unit testing only, no client and pkd testing, because cwrap is not available
+# for MinGW
+mingw32:
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
+ script:
+ - Xvfb :1 -screen 0 1024x768x16 -ac +extension GLX +render -noreset -nolisten tcp &
+ - export DISPLAY=:1
+ - mkdir -p obj && cd obj && mingw32-cmake -DCMAKE_BUILD_TYPE=Debug
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
+ -DUNIT_TESTING=ON .. &&
+ make -j$(nproc)
+ - export WINEPATH=/usr/i686-w64-mingw32/sys-root/mingw/bin
+ - ctest --output-on-failure
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+.Debian.cross.template: &Debian_cross_template
+ stage: test
+ image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$DEBIAN_CROSS_BUILD
+ script:
+ - build=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
+ - host="${CI_JOB_NAME#*.cross.}"
+ - mkdir -p obj && cd obj && cmake
+ -DCMAKE_C_COMPILER="$(which $host-gcc)"
+ -DCMAKE_CXX_COMPILER="$(which $host-g++)"
+ -DCMAKE_BUILD_TYPE=Debug
+ -DUNIT_TESTING=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
+ -DWITH_PCAP=ON .. && make -j$(nproc)
+ - ctest --output-on-failure -j$(nproc)
+ tags:
+ - shared
+ except:
+ - tags
+ artifacts:
+ expire_in: 1 week
+ when: on_failure
+ paths:
+ - obj/
+
+Debian.cross.mips-linux-gnu:
+ <<: *Debian_cross_template
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 30b1025..16989ea 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,17 +1,11 @@
-project(libssh C)
+cmake_minimum_required(VERSION 3.2.0)
+cmake_policy(SET CMP0048 NEW)
-# Required cmake version
-cmake_minimum_required(VERSION 2.8.5)
+project(libssh VERSION 0.8.0 LANGUAGES C)
-# global needed variables
+# global needed variable
set(APPLICATION_NAME ${PROJECT_NAME})
-set(APPLICATION_VERSION_MAJOR "0")
-set(APPLICATION_VERSION_MINOR "7")
-set(APPLICATION_VERSION_PATCH "0")
-
-set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
-
# SOVERSION scheme: CURRENT.AGE.REVISION
# If there was an incompatible interface change:
# Increment CURRENT. Set AGE and REVISION to 0
@@ -19,7 +13,7 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO
# Increment AGE. Set REVISION to 0
# If the source code was changed, but there were no interface changes:
# Increment REVISION.
-set(LIBRARY_VERSION "4.4.0")
+set(LIBRARY_VERSION "4.5.0")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
@@ -49,18 +43,27 @@ if (WITH_GCRYPT)
if (NOT GCRYPT_FOUND)
message(FATAL_ERROR "Could not find GCrypt")
endif (NOT GCRYPT_FOUND)
+elseif(WITH_MBEDTLS)
+ find_package(MbedTLS REQUIRED)
+ if (NOT MBEDTLS_FOUND)
+ message(FATAL_ERROR "Could not find mbedTLS")
+ endif (NOT MBEDTLS_FOUND)
else (WITH_GCRYPT)
find_package(OpenSSL)
if (NOT OPENSSL_FOUND)
find_package(GCrypt)
if (NOT GCRYPT_FOUND)
- message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
+ find_package(MbedTLS)
+ if (NOT MBEDTLS_FOUND)
+ message(FATAL_ERROR "Could not find OpenSSL, GCrypt or mbedTLS")
+ endif (NOT MBEDTLS_FOUND)
endif (NOT GCRYPT_FOUND)
endif (NOT OPENSSL_FOUND)
endif(WITH_GCRYPT)
# Find out if we have threading available
set(CMAKE_THREAD_PREFER_PTHREADS ON)
+set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
if (WITH_GSSAPI)
@@ -78,6 +81,13 @@ if (BSD OR SOLARIS OR OSX)
find_package(Argp)
endif (BSD OR SOLARIS OR OSX)
+# Disable symbol versioning in non UNIX platforms
+if (UNIX)
+ find_package(ABIMap)
+else (UNIX)
+ set(WITH_SYMBOL_VERSIONING OFF)
+endif (UNIX)
+
# config.h checks
include(ConfigureChecks.cmake)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
@@ -93,30 +103,15 @@ configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
- ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
DESTINATION
${LIB_INSTALL_DIR}/pkgconfig
COMPONENT
pkgconfig
)
-
- if (LIBSSH_THREADS)
- configure_file(libssh_threads.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc)
- install(
- FILES
- ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
- ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
- DESTINATION
- ${LIB_INSTALL_DIR}/pkgconfig
- COMPONENT
- pkgconfig
- )
- endif (LIBSSH_THREADS)
endif (UNIX)
# cmake config files
set(LIBSSH_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
-set(LIBSSH_THREADS_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
configure_file(${PROJECT_NAME}-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake @ONLY)
configure_file(${PROJECT_NAME}-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake @ONLY)
@@ -138,32 +133,94 @@ if (WITH_EXAMPLES)
add_subdirectory(examples)
endif (WITH_EXAMPLES)
-if (WITH_TESTING)
+if (UNIT_TESTING)
find_package(CMocka REQUIRED)
include(AddCMockaTest)
add_subdirectory(tests)
-endif (WITH_TESTING)
-
+endif (UNIT_TESTING)
+
+### SOURCE PACKAGE
+if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
+ # Get the current ABI version from source
+ get_filename_component(current_abi_path
+ "${CMAKE_SOURCE_DIR}/src/ABI/current"
+ ABSOLUTE)
+
+ # Check if the ABI version should be updated
+ file(READ ${current_abi_path} CURRENT_ABI_CONTENT)
+ string(STRIP "${CURRENT_ABI_CONTENT}" CURRENT_ABI_VERSION)
+
+ if (LIBRARY_VERSION VERSION_GREATER CURRENT_ABI_VERSION)
+ set(UPDATE_ABI TRUE)
+ endif ()
+
+ if (UPDATE_ABI)
+ message(STATUS "Library version bumped to ${LIBRARY_VERSION}: Updating ABI")
+
+ # Get the list of header files
+ get_file_list("${PROJECT_NAME}_header_list"
+ DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libssh"
+ FILES_PATTERNS "*.h")
+
+ # Extract the symbols marked as "LIBSSH_API" from the header files
+ extract_symbols(${PROJECT_NAME}.symbols
+ HEADERS_LIST_FILE "${PROJECT_NAME}_header_list"
+ FILTER_PATTERN "LIBSSH_API"
+ COPY_TO "${CMAKE_SOURCE_DIR}/src/ABI/${PROJECT_NAME}-${LIBRARY_VERSION}.symbols")
+
+ if (WITH_ABI_BREAK)
+ set(ALLOW_ABI_BREAK "BREAK_ABI")
+ endif()
+
+ # Target we can depend on in 'make dist'
+ set(_SYMBOL_TARGET "${PROJECT_NAME}.map")
+
+ # Set the path to the current map file
+ set(MAP_PATH "${CMAKE_SOURCE_DIR}/src/${_SYMBOL_TARGET}")
+
+ # Generate the symbol version map file
+ generate_map_file(${_SYMBOL_TARGET}
+ SYMBOLS "${PROJECT_NAME}.symbols"
+ RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION}
+ CURRENT_MAP ${MAP_PATH}
+ COPY_TO ${MAP_PATH}
+ FINAL
+ ${ALLOW_ABI_BREAK})
+
+ # Write the current version to the source
+ file(WRITE ${current_abi_path} ${LIBRARY_VERSION})
+ endif(UPDATE_ABI)
+endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
+
+add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET})
message(STATUS "********************************************")
message(STATUS "********** ${PROJECT_NAME} build options : **********")
message(STATUS "zlib support: ${WITH_ZLIB}")
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
+message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}")
message(STATUS "libnacl support: ${WITH_NACL}")
-message(STATUS "SSH-1 support: ${WITH_SSH1}")
message(STATUS "SFTP support: ${WITH_SFTP}")
message(STATUS "Server support : ${WITH_SERVER}")
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
message(STATUS "With static library: ${WITH_STATIC_LIB}")
-message(STATUS "Unit testing: ${WITH_TESTING}")
-message(STATUS "Client code Unit testing: ${WITH_CLIENT_TESTING}")
+message(STATUS "Unit testing: ${UNIT_TESTING}")
+message(STATUS "Client code testing: ${CLIENT_TESTING}")
+set(_SERVER_TESTING OFF)
+if (WITH_SERVER)
+ set(_SERVER_TESTING ${SERVER_TESTING})
+endif()
+message(STATUS "Server code testing: ${_SERVER_TESTING}")
if (WITH_INTERNAL_DOC)
message(STATUS "Internal documentation generation")
else (WITH_INTERNAL_DOC)
message(STATUS "Public API documentation generation")
endif (WITH_INTERNAL_DOC)
message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
+message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
+message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
+message(STATUS "Release is final: ${WITH_FINAL}")
message(STATUS "********************************************")
diff --git a/CPackConfig.cmake b/CPackConfig.cmake
index 66c40f0..51b300c 100644
--- a/CPackConfig.cmake
+++ b/CPackConfig.cmake
@@ -1,27 +1,19 @@
-# For help take a look at:
-# http://www.cmake.org/Wiki/CMake:CPackConfiguration
-
-### general settings
-set(CPACK_PACKAGE_NAME ${APPLICATION_NAME})
-set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH library")
+### GENERAL SETTINGS
+set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH Library")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
set(CPACK_PACKAGE_VENDOR "The SSH Library Development Team")
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
+set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
-### versions
-set(CPACK_PACKAGE_VERSION_MAJOR ${APPLICATION_VERSION_MAJOR})
-set(CPACK_PACKAGE_VERSION_MINOR ${APPLICATION_VERSION_MINOR})
-set(CPACK_PACKAGE_VERSION_PATCH ${APPLICATION_VERSION_PATCH})
-set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
-
-
-### source generator
+# SOURCE GENERATOR
set(CPACK_SOURCE_GENERATOR "TXZ")
-set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;/obj*/;tags;cscope.*")
+set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;.gitignore;/build*;/obj*;tags;cscope.*")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
+### NSIS INSTALLER
if (WIN32)
set(CPACK_GENERATOR "ZIP")
@@ -46,7 +38,6 @@ set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
set(CPACK_COMPONENT_HEADERS_DESCRIPTION
"C/C++ header files for use with libssh")
set(CPACK_COMPONENT_HEADERS_DEPENDS libraries)
-#set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime")
set(CPACK_COMPONENT_LIBRARIES_GROUP "Development")
set(CPACK_COMPONENT_HEADERS_GROUP "Development")
diff --git a/ChangeLog b/ChangeLog
index 069c219..85b2ae3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,54 @@
ChangeLog
==========
-version 0.7.0 (released 2015-05-xx)
+version 0.8.0 (released 2018-08-10)
+ * Removed support for deprecated SSHv1 protocol
+ * Added new connector API for clients
+ * Added new known_hosts parsing API
+ * Added support for OpenSSL 1.1
+ * Added support for chacha20-poly1305 cipher
+ * Added crypto backend for mbedtls crypto library
+ * Added ECDSA support with gcrypt backend
+ * Added advanced client and server testing using cwrap.org
+ * Added support for curve25519-sha256 alias
+ * Added support for global known_hosts file
+ * Added support for symbol versioning
+ * Improved ssh_config parsing
+ * Improved threading support
+
+version 0.7.5 (released 2017-04-13)
+ * Fixed a memory allocation issue with buffers
+ * Fixed PKI on Windows
+ * Fixed some SSHv1 functions
+ * Fixed config hostname expansion
+
+version 0.7.4 (released 2017-02-03)
+ * Added id_ed25519 to the default identity list
+ * Fixed sftp EOF packet handling
+ * Fixed ssh_send_banner() to confirm with RFC 4253
+ * Fixed some memory leaks
+
+version 0.7.3 (released 2016-01-23)
+ * Fixed CVE-2016-0739
+ * Fixed ssh-agent on big endian
+ * Fixed some documentation issues
+
+version 0.7.2 (released 2015-09-15)
+ * Fixed OpenSSL detection on Windows
+ * Fixed return status for ssh_userauth_agent()
+ * Fixed KEX to prefer hmac-sha2-256
+ * Fixed sftp packet handling
+ * Fixed return values of ssh_key_is_(public|private)
+ * Fixed bug in global success reply
+
+version 0.7.1 (released 2015-06-30)
+ * Fixed SSH_AUTH_PARTIAL auth with auto public key
+ * Fixed memory leak in session options
+ * Fixed allocation of ed25519 public keys
+ * Fixed channel exit-status and exit-signal
+ * Reintroduce ssh_forward_listen()
+
+version 0.7.0 (released 2015-05-11)
* Added support for ed25519 keys
* Added SHA2 algorithms for HMAC
* Added improved and more secure buffer handling code
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index 3e497dc..07c53c7 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -42,20 +42,20 @@ if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
"void __attribute__((visibility(\"default\"))) test() {}
int main(void){ return 0; }
" WITH_VISIBILITY_HIDDEN)
- set(CMAKE_REQUIRED_FLAGS "")
+ unset(CMAKE_REQUIRED_FLAGS)
endif (NOT GNUCC_VERSION EQUAL 34)
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
# HEADER FILES
-set(CMAKE_REQUIRED_INCLUDES_SAVE ${CMAKE_REQUIRED_INCLUDES})
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ARGP_INCLUDE_DIR})
check_include_file(argp.h HAVE_ARGP_H)
-set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_SAVE})
+unset(CMAKE_REQUIRED_INCLUDES)
check_include_file(pty.h HAVE_PTY_H)
check_include_file(utmp.h HAVE_UTMP_H)
check_include_file(termios.h HAVE_TERMIOS_H)
check_include_file(unistd.h HAVE_UNISTD_H)
+check_include_file(stdint.h HAVE_STDINT_H)
check_include_file(util.h HAVE_UTIL_H)
check_include_file(libutil.h HAVE_LIBUTIL_H)
check_include_file(sys/time.h HAVE_SYS_TIME_H)
@@ -63,6 +63,7 @@ check_include_file(sys/utime.h HAVE_SYS_UTIME_H)
check_include_file(sys/param.h HAVE_SYS_PARAM_H)
check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
check_include_file(byteswap.h HAVE_BYTESWAP_H)
+check_include_file(glob.h HAVE_GLOB_H)
if (WIN32)
check_include_file(io.h HAVE_IO_H)
@@ -118,13 +119,20 @@ if (OPENSSL_FOUND)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(EVP_CIPHER_CTX_new HAVE_OPENSSL_EVP_CIPHER_CTX_NEW)
+
+ set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
+ check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
+
+ unset(CMAKE_REQUIRED_INCLUDES)
+ unset(CMAKE_REQUIRED_LIBRARIES)
endif()
if (CMAKE_HAVE_PTHREAD_H)
set(HAVE_PTHREAD_H 1)
endif (CMAKE_HAVE_PTHREAD_H)
-if (NOT WITH_GCRYPT)
+if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS)
if (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H)
set(HAVE_OPENSSL_ECC 1)
endif (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H)
@@ -132,13 +140,23 @@ if (NOT WITH_GCRYPT)
if (HAVE_OPENSSL_ECC)
set(HAVE_ECC 1)
endif (HAVE_OPENSSL_ECC)
-endif (NOT WITH_GCRYPT)
+endif ()
+
+if (NOT WITH_MBEDTLS)
+ set(HAVE_DSA 1)
+endif (NOT WITH_MBEDTLS)
# FUNCTIONS
check_function_exists(isblank HAVE_ISBLANK)
check_function_exists(strncpy HAVE_STRNCPY)
check_function_exists(strtoull HAVE_STRTOULL)
+check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
+check_function_exists(memset_s HAVE_MEMSET_S)
+
+if (HAVE_GLOB_H)
+ check_function_exists(glob HAVE_GLOB)
+endif (HAVE_GLOB_H)
if (NOT WIN32)
check_function_exists(vsnprintf HAVE_VSNPRINTF)
@@ -163,12 +181,14 @@ if (WIN32)
check_symbol_exists(poll "winsock2.h;ws2tcpip.h" HAVE_SELECT)
# The getaddrinfo function is defined to the WspiapiGetAddrInfo inline function
check_symbol_exists(getaddrinfo "winsock2.h;ws2tcpip.h" HAVE_GETADDRINFO)
- set(CMAKE_REQUIRED_LIBRARIES)
+ unset(CMAKE_REQUIRED_LIBRARIES)
endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
check_function_exists(_strtoui64 HAVE__STRTOUI64)
set(HAVE_SELECT TRUE)
+
+ check_symbol_exists(SecureZeroMemory "windows.h" HAVE_SECURE_ZERO_MEMORY)
else (WIN32)
check_function_exists(poll HAVE_POLL)
check_function_exists(select HAVE_SELECT)
@@ -185,13 +205,13 @@ if (UNIX)
check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET)
if (HAVE_LIBSOCKET)
set(HAVE_GETADDRINFO TRUE)
- set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket)
+ set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} socket)
endif (HAVE_LIBSOCKET)
# libnsl/inet_pton (Solaris)
check_library_exists(nsl inet_pton "" HAVE_LIBNSL)
if (HAVE_LIBNSL)
- set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl)
+ set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} nsl)
endif (HAVE_LIBNSL)
# librt
@@ -200,7 +220,7 @@ if (UNIX)
check_library_exists(rt clock_gettime "" HAVE_CLOCK_GETTIME)
if (HAVE_LIBRT OR HAVE_CLOCK_GETTIME)
- set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} rt)
+ set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} rt)
endif (HAVE_LIBRT OR HAVE_CLOCK_GETTIME)
check_library_exists(util forkpty "" HAVE_LIBUTIL)
@@ -208,7 +228,7 @@ if (UNIX)
check_function_exists(__strtoull HAVE___STRTOULL)
endif (UNIX)
-set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
+set(LIBSSH_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
# LIBRARIES
if (OPENSSL_FOUND)
@@ -223,6 +243,11 @@ if (GCRYPT_FOUND)
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
endif (GCRYPT_FOUND)
+if (MBEDTLS_FOUND)
+ set(HAVE_LIBMBEDCRYPTO 1)
+ set(HAVE_ECC 1)
+endif (MBEDTLS_FOUND)
+
if (CMAKE_USE_PTHREADS_INIT)
set(HAVE_PTHREAD 1)
endif (CMAKE_USE_PTHREADS_INIT)
@@ -276,7 +301,7 @@ int main(void)
{
char buf[] = \"This is some content\";
- memset(buf, '\\\\0', sizeof(buf)); __asm__ volatile(\"\" : : \"r\"(&buf) : \"memory\");
+ memset(buf, '\\\\0', sizeof(buf)); __asm__ volatile(\"\" : : \"g\"(&buf) : \"memory\");
return 0;
}" HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
@@ -308,10 +333,19 @@ int main(void) {
}" HAVE_COMPILER__FUNCTION__)
+check_c_source_compiles("
+void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits)
+ __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)));
+int main(void) { return 0; }" HAVE_GCC_BOUNDED_ATTRIBUTE)
+
if (WITH_DEBUG_CRYPTO)
set(DEBUG_CRYPTO 1)
endif (WITH_DEBUG_CRYPTO)
+if (WITH_DEBUG_PACKET)
+ set(DEBUG_PACKET 1)
+endif (WITH_DEBUG_PACKET)
+
if (WITH_DEBUG_CALLTRACE)
set(DEBUG_CALLTRACE 1)
endif (WITH_DEBUG_CALLTRACE)
diff --git a/DefineOptions.cmake b/DefineOptions.cmake
index ab7819a..eb60b09 100644
--- a/DefineOptions.cmake
+++ b/DefineOptions.cmake
@@ -1,19 +1,24 @@
option(WITH_GSSAPI "Build with GSSAPI support" ON)
option(WITH_ZLIB "Build with ZLIB support" ON)
-option(WITH_SSH1 "Build with SSH1 support" OFF)
option(WITH_SFTP "Build with SFTP support" ON)
option(WITH_SERVER "Build with SSH server support" ON)
option(WITH_STATIC_LIB "Build with a static library" OFF)
option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
+option(WITH_DEBUG_PACKET "Build with packet debug output" OFF)
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
+option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
option(WITH_PCAP "Compile with Pcap generation support" ON)
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
-option(WITH_TESTING "Build with unit tests" OFF)
-option(WITH_CLIENT_TESTING "Build with client tests; requires a running sshd" OFF)
+option(UNIT_TESTING "Build with unit tests" OFF)
+option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
+option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
option(WITH_EXAMPLES "Build examples" ON)
-option(WITH_NACL "Build with libnacl (curve25519" ON)
+option(WITH_NACL "Build with libnacl (curve25519)" ON)
+option(WITH_SYMBOL_VERSIONING "Build with symbol versioning" ON)
+option(WITH_ABI_BREAK "Allow ABI break" OFF)
+option(FUZZ_TESTING "Build with fuzzer for the server" OFF)
if (WITH_ZLIB)
set(WITH_LIBZ ON)
else (WITH_ZLIB)
@@ -21,13 +26,17 @@ else (WITH_ZLIB)
endif (WITH_ZLIB)
if(WITH_BENCHMARKS)
- set(WITH_TESTING ON)
+ set(UNIT_TESTING ON)
endif(WITH_BENCHMARKS)
-if (WITH_TESTING)
+if (UNIT_TESTING)
set(WITH_STATIC_LIB ON)
-endif (WITH_TESTING)
+endif (UNIT_TESTING)
if (WITH_NACL)
set(WITH_NACL ON)
-endif (WITH_NACL) \ No newline at end of file
+endif (WITH_NACL)
+
+if (WITH_ABI_BREAK)
+ set(WITH_SYMBOL_VERSIONING ON)
+endif (WITH_ABI_BREAK)
diff --git a/INSTALL b/INSTALL
index 9e10788..ccd76ae 100644
--- a/INSTALL
+++ b/INSTALL
@@ -14,6 +14,10 @@ or
optional:
- [libz](http://www.zlib.net) >= 1.2
+- [socket_wrapper](https://cwrap.org/) >= 1.1.5
+- [nss_wrapper](https://cwrap.org/) >= 1.1.2
+- [uid_wrapper](https://cwrap.org/) >= 1.2.0
+- [pam_wrapper](https://cwrap.org/) >= 1.0.1
Note that these version numbers are version we know works correctly. If you
build and run libssh successfully with an older version, please let us know.
@@ -31,13 +35,23 @@ First, you need to configure the compilation, using CMake. Go inside the
GNU/Linux, MacOS X, MSYS/MinGW:
- cmake -DWITH_TESTING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
+ cmake -DUNIT_TESTING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
make
On Windows you should choose a makefile gernerator with -G or use
cmake-gui.exe ..
+To enable additional client tests against a local OpenSSH server, add the
+compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH
+server package and some wrapper libraries (see optional requirements) to
+be installed.
+
+If you're interested in server testing, then a OpenSSH client should be
+installed on the system and if possible also dropbear. Once that is done
+enable server support with -DWITH_SERVER=ON and enable testing of it with
+-DSERVER_TESTING=ON.
+
## Testing build
make test
diff --git a/README.CodingStyle b/README.CodingStyle
index badd16f..11acd8d 100644
--- a/README.CodingStyle
+++ b/README.CodingStyle
@@ -287,6 +287,27 @@ Good Examples:
return rc;
}
+Initialize pointers
+-------------------
+
+All pointer variables MUST be initialized to NULL. History has
+demonstrated that uninitialized pointer variables have lead to various
+bugs and security issues.
+
+Pointers MUST be initialized even if the assignment directly follows
+the declaration, like pointer2 in the example below, because the
+instructions sequence may change over time.
+
+Good Example:
+
+ char *pointer1 = NULL;
+ char *pointer2 = NULL;
+
+ pointer2 = some_func2();
+
+ ...
+
+ pointer1 = some_func1();
Typedefs
---------
diff --git a/README.mbedtls b/README.mbedtls
new file mode 100644
index 0000000..fdf3b25
--- /dev/null
+++ b/README.mbedtls
@@ -0,0 +1,11 @@
+mbedTLS and libssh in multithreaded applications
+==================================================
+
+To use libssh with mbedTLS in a multithreaded application, mbedTLS has to be
+built with threading support enabled.
+
+If threading support is not available and multi threading is used, ssh_init
+will fail.
+
+More information about building mbedTLS with threading support can be found
+in the mbedTLS documentation.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..450b67c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,44 @@
+[![pipeline status](https://gitlab.com/libssh/libssh-mirror/badges/master/pipeline.svg)](https://gitlab.com/libssh/libssh-mirror/commits/master)
+
+```
+ _ _ _ _
+ (_) (_) (_) (_)
+ (_) _ (_) _ _ _ _ _ (_) _
+ (_) (_) (_)(_) _ (_)(_) (_)(_) (_)(_) _
+ (_) (_) (_) (_) _ (_) _ (_) (_) (_)
+ (_) (_) (_)(_)(_) (_)(_) (_)(_) (_) (_).org
+
+ The SSH library
+
+```
+
+# Why?
+
+Why not ? :) I've began to work on my own implementation of the ssh protocol
+because i didn't like the currently public ones.
+Not any allowed you to import and use the functions as a powerful library,
+and so i worked on a library-based SSH implementation which was non-existing
+in the free and open source software world.
+
+
+# How/Who?
+
+If you downloaded this file, you must know what it is : a library for
+accessing ssh client services through C libraries calls in a simple manner.
+Everybody can use this software under the terms of the LGPL - see the COPYING
+file
+
+If you ask yourself how to compile libssh, please read INSTALL before anything.
+
+# Where ?
+
+https://www.libssh.org
+
+# Contributing
+
+Please read the file 'SubmittingPatches' next to this README file. It explains
+our copyright policy and how you should send patches for upstream inclusion.
+
+Have fun and happy libssh hacking!
+
+The libssh Team
diff --git a/cmake/Modules/AddCMockaTest.cmake b/cmake/Modules/AddCMockaTest.cmake
index 3380ecd..7531813 100644
--- a/cmake/Modules/AddCMockaTest.cmake
+++ b/cmake/Modules/AddCMockaTest.cmake
@@ -23,8 +23,16 @@ if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW)
set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Address sanitizer executable linker flags")
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW)
+if (CMAKE_CROSSCOMPILING)
+ if (WIN32)
+ find_program(WINE_EXECUTABLE
+ NAMES wine)
+ set(TARGET_SYSTEM_EMULATOR ${WINE_EXECUTABLE})
+ endif()
+endif()
+
function (ADD_CMOCKA_TEST _testName _testSource)
add_executable(${_testName} ${_testSource})
target_link_libraries(${_testName} ${ARGN})
- add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName})
+ add_test(${_testName} ${TARGET_SYSTEM_EMULATOR} ${CMAKE_CURRENT_BINARY_DIR}/${_testName}${CMAKE_EXECUTABLE_SUFFIX})
endfunction (ADD_CMOCKA_TEST)
diff --git a/cmake/Modules/ExtractSymbols.cmake b/cmake/Modules/ExtractSymbols.cmake
new file mode 100644
index 0000000..d37778e
--- /dev/null
+++ b/cmake/Modules/ExtractSymbols.cmake
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+#.rst:
+# ExtractSymbols
+# --------------
+#
+# This is a helper script for FindABImap.cmake.
+#
+# Extract symbols from header files and output a list to a file.
+# This script is run in build time to extract symbols from the provided header
+# files. This way, symbols added or removed can be checked and used to update
+# the symbol version script.
+#
+# All symbols followed by the character ``'('`` are extracted. If a
+# ``FILTER_PATTERN`` is provided, only the lines containing the given string are
+# considered.
+#
+# Expected defined variables
+# --------------------------
+#
+# ``HEADERS_LIST_FILE``:
+# Required, expects a file containing the list of header files to be parsed.
+#
+# ``OUTPUT_PATH``:
+# Required, expects the output file path.
+#
+# Optionally defined variables
+# ----------------------------
+#
+# ``FILTER_PATTERN``:
+# Expects a string. Only lines containing the given string will be considered
+# when extracting symbols.
+#
+
+if (NOT DEFINED OUTPUT_PATH)
+ message(SEND_ERROR "OUTPUT_PATH not defined")
+endif()
+
+if (NOT DEFINED HEADERS_LIST_FILE)
+ message(SEND_ERROR "HEADERS not defined")
+endif()
+
+file(READ ${HEADERS_LIST_FILE} HEADERS_LIST)
+
+set(symbols)
+foreach(header ${HEADERS_LIST})
+
+ # Filter only lines containing the FILTER_PATTERN
+ file(STRINGS ${header} contain_filter
+ REGEX "^.*${FILTER_PATTERN}.*[(]"
+ )
+
+ # Remove function-like macros
+ foreach(line ${contain_filter})
+ if (NOT ${line} MATCHES ".*#[ ]*define")
+ list(APPEND not_macro ${line})
+ endif()
+ endforeach()
+
+ set(functions)
+
+ # Get only the function names followed by '('
+ foreach(line ${not_macro})
+ string(REGEX MATCHALL "[a-zA-Z0-9_]+[ ]*[(]" func ${line})
+ list(APPEND functions ${func})
+ endforeach()
+
+ set(extracted_symbols)
+
+ # Remove '('
+ foreach(line ${functions})
+ string(REGEX REPLACE "[(]" "" symbol ${line})
+ string(STRIP "${symbol}" symbol)
+ list(APPEND extracted_symbols ${symbol})
+ endforeach()
+
+ list(APPEND symbols ${extracted_symbols})
+endforeach()
+
+list(REMOVE_DUPLICATES symbols)
+
+file(WRITE ${OUTPUT_PATH} "${symbols}")
diff --git a/cmake/Modules/FindABIMap.cmake b/cmake/Modules/FindABIMap.cmake
new file mode 100644
index 0000000..78bfa36
--- /dev/null
+++ b/cmake/Modules/FindABIMap.cmake
@@ -0,0 +1,394 @@
+#
+# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+#.rst:
+# FindABIMap
+# ----------
+#
+# This file provides functions to generate the symbol version script. It uses
+# the ``abimap`` tool to generate and update the linker script file. It can be
+# installed by calling::
+#
+# $ pip install abimap
+#
+# The ``function generate_map_file`` generates a symbol version script
+# containing the provided symbols. It defines a custom command which sets
+# ``target_name`` as its ``OUTPUT``.
+#
+# The experimental function ``extract_symbols()`` is provided as a simple
+# parser to extract the symbols from C header files. It simply extracts symbols
+# followed by an opening '``(``'. It is recommended to use a filter pattern to
+# select the lines to be considered. It defines a custom command which sets
+# ``target_name`` as its output.
+#
+# The helper function ``get_files_list()`` is provided to find files given a
+# name pattern. It defines a custom command which sets ``target_name`` as its
+# output.
+#
+# Functions provided
+# ------------------
+#
+# ::
+#
+# generate_map_file(target_name
+# RELEASE_NAME_VERSION release_name
+# SYMBOLS symbols_file
+# [CURRENT_MAP cur_map]
+# [FINAL]
+# [BREAK_ABI]
+# [COPY_TO output]
+# )
+#
+# ``target_name``:
+# Required, expects the name of the file to receive the generated symbol
+# version script. It should be added as a dependency for the library. Use the
+# linker option ``--version-script filename`` to add the version information
+# to the symbols when building the library.
+#
+# ``RELEASE_NAME_VERSION``:
+# Required, expects a string containing the name and version information to be
+# added to the symbols in the format ``lib_name_1_2_3``.
+#
+# ``SYMBOLS``:
+# Required, expects a file containing the list of symbols to be added to the
+# symbol version script.
+#
+# ``CURRENT_MAP``:
+# Optional. If given, the new set of symbols will be checked against the
+# ones contained in the ``cur_map`` file and updated properly. If an
+# incompatible change is detected and ``BREAK_ABI`` is not defined, the build
+# will fail.
+#
+# ``FINAL``:
+# Optional. If given, will provide the ``--final`` option to ``abimap`` tool,
+# which will mark the modified release in the symbol version script with a
+# special comment, preventing later changes. This option should be set when
+# creating a library release and the resulting map file should be stored with
+# the source code.
+#
+# ``BREAK_ABI``:
+# Optional. If provided, will use ``abimap`` ``--allow-abi-break`` option, which
+# accepts incompatible changes to the set of symbols. This is necessary if any
+# previously existing symbol were removed.
+#
+# ``COPY_TO``:
+# Optional, expects a string containing the path to where the generated
+# map file will be copied.
+#
+# Example:
+#
+# .. code-block:: cmake
+#
+# find_package(ABIMap)
+# generate_map_file("lib.map"
+# RELEASE_NAME_VERSION "lib_1_0_0"
+# SYMBOLS "symbol1;symbol2"
+# )
+#
+# This example would result in the symbol version script to be created in
+# ``${CMAKE_CURRENT_BINARY_DIR}/lib.map`` containing the provided symbols.
+#
+# ::
+#
+# get_files_list(target_name
+# DIRECTORIES dir1 [dir2 ...]
+# FILES_PATTERNS exp1 [exp2 ...]
+# [COPY_TO output]
+# )
+#
+# ``target_name``:
+# Required, expects the name of the target to be created. A file named after
+# the string given in ``target_name`` will be created in
+# ``${CMAKE_CURRENT_BINARY_DIR}`` to receive the list of files found.
+#
+# ``DIRECTORIES``:
+# Required, expects a list of directories paths. Only absolute paths are
+# supported.
+#
+# ``FILES_PATTERN``:
+# Required, expects a list of matching expressions to find the files to be
+# considered.
+#
+# ``COPY_TO``:
+# Optional, expects a string containing the path to where the file containing
+# the list of files will be copied.
+#
+# This command searches the directories provided in ``DIRECTORIES`` for files
+# matching any of the patterns provided in ``FILES_PATTERNS``. The obtained list
+# is written to the path specified by ``output``.
+#
+# Example:
+#
+# .. code-block:: cmake
+#
+# find_package(ABIMap)
+# get_files_list(target
+# DIRECTORIES "/include/mylib"
+# FILES_PATTERNS "*.h"
+# COPY_TO "my_list.txt"
+# )
+#
+# Consider that ``/include/mylib`` contains 3 files, ``h1.h``, ``h2.h``, and
+# ``h3.hpp``
+#
+# Will result in a file ``my_list.txt`` containing::
+#
+# ``h1.h;h2.h``
+#
+# ::
+#
+# extract_symbols(target_name
+# HEADERS_LIST_FILE headers_list
+# [FILTER_PATTERN pattern]
+# [COPY_TO output]
+# )
+#
+# ``target_name``:
+# Required, expects the name of the target to be created. A file named after
+# the string given in ``target_name`` will be created in
+# ``${CMAKE_CURRENT_BINARY_DIR}`` to receive the list of symbols.
+#
+# ``HEADERS_LIST_FILE``:
+# Required, expects a path to a file containing the list of header files to be
+# parsed.
+#
+# ``FILTER_PATTERN``:
+# Optional, expects a string. Only the lines containing the filter pattern
+# will be considered.
+#
+# ``COPY_TO``:
+# Optional, expects a string containing the path to where the file containing
+# the found symbols will be copied.
+#
+# This command extracts the symbols from the files listed in
+# ``headers_list`` and write them on the ``output`` file. If ``pattern``
+# is provided, then only the lines containing the string given in ``pattern``
+# will be considered. It is recommended to provide a ``FILTER_PATTERN`` to mark
+# the lines containing exported function declaration, since this function is
+# experimental and can return wrong symbols when parsing the header files.
+#
+# Example:
+#
+# .. code-block:: cmake
+#
+# find_package(ABIMap)
+# extract_symbols("lib.symbols"
+# HEADERS_LIST_FILE "headers_list"
+# FILTER_PATTERN "API_FUNCTION"
+# )
+#
+# Where headers_list contains::
+#
+# header1.h;header2.h
+#
+# Where ``header1.h`` contains::
+#
+# API_FUNCTION int exported_func1(int a, int b);
+#
+# ``header2.h`` contains::
+#
+# API_FUNCTION int exported_func2(int a);
+#
+# int private_func2(int b);
+#
+# Will result in a file ``lib.symbols`` in ``${CMAKE_CURRENT_BINARY_DIR}`` containing::
+#
+# ``exported_func1;exported_func2``
+#
+
+# Search for python which is required
+find_package(PythonInterp REQUIRED)
+
+# Search for abimap tool used to generate the map files
+find_program(ABIMAP_EXECUTABLE NAMES abimap DOC "path to the abimap executable")
+mark_as_advanced(ABIMAP_EXECUTABLE)
+
+if (NOT ABIMAP_EXECUTABLE AND UNIX)
+ message(STATUS "Could not find `abimap` in PATH."
+ " It can be found in PyPI as `abimap`"
+ " (try `pip install abimap`)")
+else ()
+ set(ABIMAP_FOUND TRUE)
+endif ()
+
+# Define helper scripts
+set(_EXTRACT_SYMBOLS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/ExtractSymbols.cmake)
+set(_GENERATE_MAP_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/GenerateMap.cmake)
+set(_GET_FILES_LIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/GetFilesList.cmake)
+
+function(get_file_list _TARGET_NAME)
+
+ set(one_value_arguments
+ COPY_TO
+ )
+
+ set(multi_value_arguments
+ DIRECTORIES
+ FILES_PATTERNS
+ )
+
+ cmake_parse_arguments(_get_files_list
+ ""
+ "${one_value_arguments}"
+ "${multi_value_arguments}"
+ ${ARGN}
+ )
+
+ # The DIRS argument is required
+ if (NOT DEFINED _get_files_list_DIRECTORIES)
+ message(FATAL_ERROR "No directories paths provided. Provide a list of"
+ " directories paths containing header files."
+ )
+ endif()
+
+ # The FILES_PATTERNS argument is required
+ if (NOT DEFINED _get_files_list_FILES_PATTERNS)
+ message(FATAL_ERROR "No matching expressions provided. Provide a list"
+ " of matching patterns for the header files."
+ )
+ endif()
+
+ get_filename_component(_get_files_list_OUTPUT_PATH
+ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
+ ABSOLUTE
+ )
+
+ add_custom_command(
+ OUTPUT ${_TARGET_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTPUT_PATH="${_get_files_list_OUTPUT_PATH}"
+ -DDIRECTORIES="${_get_files_list_DIRECTORIES}"
+ -DFILES_PATTERNS="${_get_files_list_FILES_PATTERNS}"
+ -P ${_GET_FILES_LIST_SCRIPT}
+ COMMENT
+ "Searching for files"
+ )
+
+ if (DEFINED _get_files_list_COPY_TO)
+ # Copy the generated file back to the COPY_TO
+ add_custom_target(copy_headers_list_${TARGET_NAME} ALL
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different ${_TARGET_NAME} ${_get_files_list_COPY_TO}
+ DEPENDS "${_TARGET_NAME}"
+ COMMENT "Copying ${_TARGET_NAME} to ${_get_files_list_COPY_TO}"
+ )
+ endif()
+endfunction()
+
+function(extract_symbols _TARGET_NAME)
+
+ set(one_value_arguments
+ FILTER_PATTERN
+ HEADERS_LIST_FILE
+ COPY_TO
+ )
+
+ set(multi_value_arguments
+ )
+
+ cmake_parse_arguments(_extract_symbols
+ ""
+ "${one_value_arguments}"
+ "${multi_value_arguments}"
+ ${ARGN}
+ )
+
+ # The HEADERS_LIST_FILE argument is required
+ if (NOT DEFINED _extract_symbols_HEADERS_LIST_FILE)
+ message(FATAL_ERROR "No header files given. Provide a list of header"
+ " files containing exported symbols."
+ )
+ endif()
+
+ get_filename_component(_extract_symbols_OUTPUT_PATH
+ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
+ ABSOLUTE
+ )
+
+ add_custom_target(${_TARGET_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ -DOUTPUT_PATH="${_extract_symbols_OUTPUT_PATH}"
+ -DHEADERS_LIST_FILE="${_extract_symbols_HEADERS_LIST_FILE}"
+ -DFILTER_PATTERN=${_extract_symbols_FILTER_PATTERN}
+ -P ${_EXTRACT_SYMBOLS_SCRIPT}
+ DEPENDS ${_extract_symbols_HEADERS_LIST_FILE}
+ COMMENT "Extracting symbols from headers")
+
+ if (DEFINED _extract_symbols_COPY_TO)
+ file(READ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}" SYMBOL_CONTENT)
+ string(REPLACE ";" "\n" SYMBOL_CONTENT_NEW "${SYMBOL_CONTENT}")
+ file(WRITE "${_extract_symbols_COPY_TO}" "${SYMBOL_CONTENT_NEW}")
+ endif()
+endfunction()
+
+function(generate_map_file _TARGET_NAME)
+
+ set(options
+ FINAL
+ BREAK_ABI
+ )
+
+ set(one_value_arguments
+ RELEASE_NAME_VERSION
+ SYMBOLS
+ CURRENT_MAP
+ COPY_TO
+ )
+
+ set(multi_value_arguments
+ )
+
+ cmake_parse_arguments(_generate_map_file
+ "${options}"
+ "${one_value_arguments}"
+ "${multi_value_arguments}"
+ ${ARGN}
+ )
+
+ if (NOT DEFINED _generate_map_file_SYMBOLS)
+ message(FATAL_ERROR "No symbols file provided."
+ )
+ endif()
+
+ if (NOT DEFINED _generate_map_file_RELEASE_NAME_VERSION)
+ message(FATAL_ERROR "Release name and version not provided."
+ " (e.g. libname_1_0_0"
+ )
+ endif()
+
+ # Set generated map file path
+ get_filename_component(_generate_map_file_OUTPUT_PATH
+ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
+ ABSOLUTE
+ )
+
+ add_custom_command(
+ OUTPUT ${_TARGET_NAME}
+ COMMAND ${CMAKE_COMMAND}
+ -DABIMAP_EXECUTABLE=${ABIMAP_EXECUTABLE}
+ -DSYMBOLS="${_generate_map_file_SYMBOLS}"
+ -DCURRENT_MAP=${_generate_map_file_CURRENT_MAP}
+ -DOUTPUT_PATH="${_generate_map_file_OUTPUT_PATH}"
+ -DFINAL=${_generate_map_file_FINAL}
+ -DBREAK_ABI=${_generate_map_file_BREAK_ABI}
+ -DRELEASE_NAME_VERSION=${_generate_map_file_RELEASE_NAME_VERSION}
+ -P ${_GENERATE_MAP_SCRIPT}
+ DEPENDS ${_generate_map_file_SYMBOLS}
+ COMMENT "Generating the map ${_TARGET_NAME}"
+ )
+
+ if (DEFINED _generate_map_file_COPY_TO)
+ # Copy the generated map back to the COPY_TO
+ add_custom_target(copy_map_${_TARGET_NAME} ALL
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different ${_TARGET_NAME} ${_generate_map_file_COPY_TO}
+ DEPENDS "${_TARGET_NAME}"
+ COMMENT "Copying ${_TARGET_NAME} to ${_generate_map_file_COPY_TO}"
+ )
+ endif()
+endfunction()
diff --git a/cmake/Modules/FindGCrypt.cmake b/cmake/Modules/FindGCrypt.cmake
index 7b44408..389a031 100644
--- a/cmake/Modules/FindGCrypt.cmake
+++ b/cmake/Modules/FindGCrypt.cmake
@@ -52,9 +52,9 @@ find_library(GCRYPT_LIBRARY
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY})
if (GCRYPT_INCLUDE_DIR)
- file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+.[0-9]+.[0-9]+\"")
+ file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]")
- string(REGEX REPLACE "^.*GCRYPT_VERSION.*([0-9]+.[0-9]+.[0-9]+).*" "\\1" GCRYPT_VERSION "${_gcrypt_version_str}")
+ string(REGEX REPLACE "^.*GCRYPT_VERSION.*([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" GCRYPT_VERSION "${_gcrypt_version_str}")
endif (GCRYPT_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
diff --git a/cmake/Modules/FindMbedTLS.cmake b/cmake/Modules/FindMbedTLS.cmake
new file mode 100644
index 0000000..baec8ad
--- /dev/null
+++ b/cmake/Modules/FindMbedTLS.cmake
@@ -0,0 +1,104 @@
+# - Try to find mbedTLS
+# Once done this will define
+#
+# MBEDTLS_FOUND - system has mbedTLS
+# MBEDTLS_INCLUDE_DIRS - the mbedTLS include directory
+# MBEDTLS_LIBRARIES - Link these to use mbedTLS
+# MBEDTLS_DEFINITIONS - Compiler switches required for using mbedTLS
+#=============================================================================
+# Copyright (c) 2017 Sartura d.o.o.
+#
+# Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+#
+
+
+set(_MBEDTLS_ROOT_HINTS
+ $ENV{MBEDTLS_ROOT_DIR}
+ ${MBEDTLS_ROOT_DIR})
+
+set(_MBEDTLS_ROOT_PATHS
+ "$ENV{PROGRAMFILES}/libmbedtls")
+
+set(_MBEDTLS_ROOT_HINTS_AND_PATHS
+ HINTS ${_MBEDTLS_ROOT_HINTS}
+ PATHS ${_MBEDTLS_ROOT_PATHS})
+
+
+find_path(MBEDTLS_INCLUDE_DIR
+ NAMES
+ mbedtls/config.h
+ HINTS
+ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ include
+)
+
+find_library(MBEDTLS_SSL_LIBRARY
+ NAMES
+ mbedtls
+ HINTS
+ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ lib
+
+)
+
+find_library(MBEDTLS_CRYPTO_LIBRARY
+ NAMES
+ mbedcrypto
+ HINTS
+ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ lib
+)
+
+find_library(MBEDTLS_X509_LIBRARY
+ NAMES
+ mbedx509
+ HINTS
+ ${_MBEDTLS_ROOT_HINTS_AND_PATHS}
+ PATH_SUFFIXES
+ lib
+)
+
+set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
+ ${MBEDTLS_X509_LIBRARY})
+
+if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
+ file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
+ "^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
+
+ string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
+ "\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
+endif ()
+
+include(FindPackageHandleStandardArgs)
+if (MBEDTLS_VERSION)
+ find_package_handle_standard_args(MbedTLS
+ REQUIRED_VARS
+ MBEDTLS_INCLUDE_DIR
+ MBEDTLS_LIBRARIES
+ VERSION_VAR
+ MBEDTLS_VERSION
+ FAIL_MESSAGE
+ "Could NOT find mbedTLS, try to set the path to mbedTLS root folder
+ in the system variable MBEDTLS_ROOT_DIR"
+ )
+else (MBEDTLS_VERSION)
+ find_package_handle_standard_args(MBedTLS
+ "Could NOT find mbedTLS, try to set the path to mbedLS root folder in
+ the system variable MBEDTLS_ROOT_DIR"
+ MBEDTLS_INCLUDE_DIR
+ MBEDTLS_LIBRARIES)
+endif (MBEDTLS_VERSION)
+
+# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view
+mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES)
diff --git a/cmake/Modules/GenerateMap.cmake b/cmake/Modules/GenerateMap.cmake
new file mode 100644
index 0000000..c22dfbc
--- /dev/null
+++ b/cmake/Modules/GenerateMap.cmake
@@ -0,0 +1,118 @@
+#
+# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+#.rst:
+# GenerateMap
+# -----------
+#
+# This is a helper script for FindABImap.cmake.
+#
+# Generates a symbols version script using the abimap tool.
+# This script is run in build time to use the correct command depending on the
+# existence of the file provided ``CURRENT_MAP``.
+#
+# If the file exists, the ``abimap update`` subcommand is used to update the
+# existing map. Otherwise, the ``abimap new`` subcommand is used to create a new
+# map file.
+#
+# If the file provided in ``CURRENT_MAP`` exists, it is copied to the
+# ``OUTPUT_PATH`` before updating.
+# This is required because ``abimap`` do not generate output if no symbols were
+# changed when updating an existing file.
+#
+# Expected defined variables
+# --------------------------
+#
+# ``SYMBOLS``:
+# Required file containing the symbols to be used as input. Usually this is
+# the ``OUTPUT`` generated by ``extract_symbols()`` function provided in
+# FindABImap.cmake
+#
+# ``RELEASE_NAME_VERSION``:
+# Required, expects the library name and version information to be added to
+# the symbols in the format ``library_name_1_2_3``
+#
+# ``CURRENT_MAP``:
+# Required, expects the path to the current map file (or the path were it
+# should be)
+#
+# ``OUTPUT_PATH``:
+# Required, expects the output file path.
+#
+# ``ABIMAP_EXECUTABLE``:
+# Required, expects the path to the ``abimap`` tool.
+#
+# Optionally defined variables
+# ----------------------------
+#
+# ``FINAL``:
+# If defined, will mark the modified set of symbols in the symbol version
+# script as final, preventing later changes using ``abimap``.
+#
+# ``BREAK_ABI``:
+# If defined, the build will not fail if symbols were removed.
+# If defined and a symbol is removed, a new release is created containing
+# all symbols from all released versions. This makes an incompatible release.
+#
+
+if (NOT DEFINED RELEASE_NAME_VERSION)
+ message(SEND_ERROR "RELEASE_NAME_VERSION not defined")
+endif()
+
+if (NOT DEFINED SYMBOLS)
+ message(SEND_ERROR "SYMBOLS not defined")
+endif()
+
+if (NOT DEFINED CURRENT_MAP)
+ message(SEND_ERROR "CURRENT_MAP not defined")
+endif()
+
+if (NOT DEFINED OUTPUT_PATH)
+ message(SEND_ERROR "OUTPUT_PATH not defined")
+endif()
+
+if (NOT ABIMAP_EXECUTABLE)
+ message(SEND_ERROR "ABIMAP_EXECUTABLE not defined")
+endif()
+
+set(ARGS_LIST)
+
+if (FINAL)
+ list(APPEND ARGS_LIST "--final")
+endif()
+
+if (EXISTS ${CURRENT_MAP})
+ if (BREAK_ABI)
+ list(APPEND ARGS_LIST "--allow-abi-break")
+ endif()
+
+ execute_process(
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different ${CURRENT_MAP} ${OUTPUT_PATH}
+ COMMAND
+ ${ABIMAP_EXECUTABLE} update ${ARGS_LIST}
+ -r ${RELEASE_NAME_VERSION}
+ -i ${SYMBOLS}
+ -o ${OUTPUT_PATH}
+ ${CURRENT_MAP}
+ RESULT_VARIABLE result
+ )
+else ()
+ execute_process(
+ COMMAND
+ ${ABIMAP_EXECUTABLE} new ${ARGS_LIST}
+ -r ${RELEASE_NAME_VERSION}
+ -i ${SYMBOLS}
+ -o ${OUTPUT_PATH}
+ RESULT_VARIABLE result
+ )
+endif()
+
+if (NOT "${result}" STREQUAL "0")
+ message(SEND_ERROR "Map generation failed")
+endif()
diff --git a/cmake/Modules/GetFilesList.cmake b/cmake/Modules/GetFilesList.cmake
new file mode 100644
index 0000000..e3e8a2a
--- /dev/null
+++ b/cmake/Modules/GetFilesList.cmake
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+#.rst:
+# GetFilesList
+# ------------
+#
+# This is a helper script for FindABImap.cmake.
+#
+# Search in the provided directories for files matching the provided pattern.
+# The list of files is then written to the output file.
+#
+# Expected defined variables
+# --------------------------
+#
+# ``DIRECTORIES``:
+# Required, expects a list of directories paths.
+#
+# ``FILES_PATTERNS``:
+# Required, expects a list of patterns to be used to search files
+#
+# ``OUTPUT_PATH``:
+# Required, expects the output file path.
+
+if (NOT DEFINED DIRECTORIES)
+ message(SEND_ERROR "DIRECTORIES not defined")
+endif()
+
+if (NOT DEFINED FILES_PATTERNS)
+ message(SEND_ERROR "FILES_PATTERNS not defined")
+endif()
+
+if (NOT DEFINED OUTPUT_PATH)
+ message(SEND_ERROR "OUTPUT_PATH not defined")
+endif()
+
+string(REPLACE " " ";" DIRECTORIES_LIST "${DIRECTORIES}")
+string(REPLACE " " ";" FILES_PATTERNS_LIST "${FILES_PATTERNS}")
+
+# Create the list of expressions for the files
+set(glob_expressions)
+foreach(dir ${DIRECTORIES_LIST})
+ foreach(exp ${FILES_PATTERNS_LIST})
+ list(APPEND glob_expressions
+ "${dir}/${exp}"
+ )
+ endforeach()
+endforeach()
+
+# Create the list of files
+file(GLOB files ${glob_expressions})
+
+# Write to the output
+file(WRITE ${OUTPUT_PATH} "${files}")
diff --git a/cmake/Toolchain-cross-m32.cmake b/cmake/Toolchain-cross-m32.cmake
new file mode 100644
index 0000000..7918c60
--- /dev/null
+++ b/cmake/Toolchain-cross-m32.cmake
@@ -0,0 +1,23 @@
+set(CMAKE_C_FLAGS "-m32" CACHE STRING "C compiler flags" FORCE)
+set(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags" FORCE)
+
+set(LIB32 /usr/lib) # Fedora
+
+if(EXISTS /usr/lib32)
+ set(LIB32 /usr/lib32) # Arch, Solus
+endif()
+
+set(CMAKE_SYSTEM_LIBRARY_PATH ${LIB32} CACHE STRING "system library search path" FORCE)
+set(CMAKE_LIBRARY_PATH ${LIB32} CACHE STRING "library search path" FORCE)
+
+# this is probably unlikely to be needed, but just in case
+set(CMAKE_EXE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "executable linker flags" FORCE)
+set(CMAKE_SHARED_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "shared library linker flags" FORCE)
+set(CMAKE_MODULE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "module linker flags" FORCE)
+
+# on Fedora and Arch and similar, point pkgconfig at 32 bit .pc files. We have
+# to include the regular system .pc files as well (at the end), because some
+# are not always present in the 32 bit directory
+if(EXISTS ${LIB32}/pkgconfig)
+ set(ENV{PKG_CONFIG_LIBDIR} ${LIB32}/pkgconfig:/usr/share/pkgconfig:/usr/lib/pkgconfig:/usr/lib64/pkgconfig)
+endiF()
diff --git a/config.h.cmake b/config.h.cmake
index f8869df..421f527 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -20,6 +20,9 @@
/* Define to 1 if you have the <aprpa/inet.h> header file. */
#cmakedefine HAVE_ARPA_INET_H 1
+/* Define to 1 if you have the <glob.h> header file. */
+#cmakedefine HAVE_GLOB_H 1
+
/* Define to 1 if you have the <pty.h> header file. */
#cmakedefine HAVE_PTY_H 1
@@ -47,6 +50,9 @@
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H 1
+
/* Define to 1 if you have the <openssl/aes.h> header file. */
#cmakedefine HAVE_OPENSSL_AES_H 1
@@ -80,6 +86,9 @@
/* Define to 1 if you have eliptic curve cryptography */
#cmakedefine HAVE_ECC 1
+/* Define to 1 if you have DSA */
+#cmakedefine HAVE_DSA 1
+
/*************************** FUNCTIONS ***************************/
/* Define to 1 if you have the `EVP_aes128_ctr' function. */
@@ -151,6 +160,18 @@
/* Define to 1 if you have the `_strtoui64' function. */
#cmakedefine HAVE__STRTOUI64 1
+/* Define to 1 if you have the `glob' function. */
+#cmakedefine HAVE_GLOB 1
+
+/* Define to 1 if you have the `explicit_bzero' function. */
+#cmakedefine HAVE_EXPLICIT_BZERO 1
+
+/* Define to 1 if you have the `memset_s' function. */
+#cmakedefine HAVE_MEMSET_S 1
+
+/* Define to 1 if you have the `SecureZeroMemory' function. */
+#cmakedefine HAVE_SECURE_ZERO_MEMORY 1
+
/*************************** LIBRARIES ***************************/
/* Define to 1 if you have the `crypto' library (-lcrypto). */
@@ -159,6 +180,9 @@
/* Define to 1 if you have the `gcrypt' library (-lgcrypt). */
#cmakedefine HAVE_LIBGCRYPT 1
+/* Define to 1 if you have the 'mbedTLS' library (-lmbedtls). */
+#cmakedefine HAVE_LIBMBEDCRYPTO 1
+
/* Define to 1 if you have the `pthread' library (-lpthread). */
#cmakedefine HAVE_PTHREAD 1
@@ -175,6 +199,8 @@
#cmakedefine HAVE_COMPILER__FUNC__ 1
#cmakedefine HAVE_COMPILER__FUNCTION__ 1
+#cmakedefine HAVE_GCC_BOUNDED_ATTRIBUTE 1
+
/* Define to 1 if you want to enable GSSAPI */
#cmakedefine WITH_GSSAPI 1
@@ -184,15 +210,15 @@
/* Define to 1 if you want to enable SFTP */
#cmakedefine WITH_SFTP 1
-/* Define to 1 if you want to enable SSH1 */
-#cmakedefine WITH_SSH1 1
-
/* Define to 1 if you want to enable server support */
#cmakedefine WITH_SERVER 1
/* Define to 1 if you want to enable debug output for crypto functions */
#cmakedefine DEBUG_CRYPTO 1
+/* Define to 1 if you want to enable debug output for packet functions */
+#cmakedefine DEBUG_PACKET 1
+
/* Define to 1 if you want to enable pcap output support (experimental) */
#cmakedefine WITH_PCAP 1
diff --git a/doc/authentication.dox b/doc/authentication.dox
index 8ade542..7a0023e 100644
--- a/doc/authentication.dox
+++ b/doc/authentication.dox
@@ -46,7 +46,7 @@ The ssh_userauth_publickey_auto() function also tries to authenticate using the
SSH agent, if you have one running, or the "none" method otherwise.
If you wish to authenticate with public key by your own, follow these steps:
- - Retrieve the public key with ssh_import_pubkey_file().
+ - Retrieve the public key with ssh_pki_import_pubkey_file().
- Offer the public key to the SSH server using ssh_userauth_try_publickey().
If the return value is SSH_AUTH_SUCCESS, the SSH server accepts to
authenticate using the public key and you can go to the next step.
diff --git a/doc/guided_tour.dox b/doc/guided_tour.dox
index 94449e1..c74bfa8 100644
--- a/doc/guided_tour.dox
+++ b/doc/guided_tour.dox
@@ -158,7 +158,7 @@ you just connected to is known and safe to use (remember, SSH is about security
authentication).
There are two ways of doing this:
- - The first way (recommended) is to use the ssh_is_server_known()
+ - The first way (recommended) is to use the ssh_session_is_known_server()
function. This function will look into the known host file
(~/.ssh/known_hosts on UNIX), look for the server hostname's pattern,
and determine whether this host is present or not in the list.
@@ -185,74 +185,89 @@ examples/ directory:
int verify_knownhost(ssh_session session)
{
- int state, hlen;
- unsigned char *hash = NULL;
- char *hexa;
- char buf[10];
-
- state = ssh_is_server_known(session);
-
- hlen = ssh_get_pubkey_hash(session, &hash);
- if (hlen < 0)
- return -1;
-
- switch (state)
- {
- case SSH_SERVER_KNOWN_OK:
- break; /* ok */
-
- case SSH_SERVER_KNOWN_CHANGED:
- fprintf(stderr, "Host key for server changed: it is now:\n");
- ssh_print_hexa("Public key hash", hash, hlen);
- fprintf(stderr, "For security reasons, connection will be stopped\n");
- free(hash);
- return -1;
-
- case SSH_SERVER_FOUND_OTHER:
- fprintf(stderr, "The host key for this server was not found but an other"
- "type of key exists.\n");
- fprintf(stderr, "An attacker might change the default server key to"
- "confuse your client into thinking the key does not exist\n");
- free(hash);
- return -1;
-
- case SSH_SERVER_FILE_NOT_FOUND:
- fprintf(stderr, "Could not find known host file.\n");
- fprintf(stderr, "If you accept the host key here, the file will be"
- "automatically created.\n");
- /* fallback to SSH_SERVER_NOT_KNOWN behavior */
-
- case SSH_SERVER_NOT_KNOWN:
- hexa = ssh_get_hexa(hash, hlen);
- fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
- fprintf(stderr, "Public key hash: %s\n", hexa);
- free(hexa);
- if (fgets(buf, sizeof(buf), stdin) == NULL)
- {
- free(hash);
- return -1;
- }
- if (strncasecmp(buf, "yes", 3) != 0)
- {
- free(hash);
+ enum ssh_known_hosts_e state;
+ unsigned char *hash = NULL;
+ ssh_key srv_pubkey = NULL;
+ size_t hlen;
+ char buf[10];
+ char *hexa;
+ char *p;
+ int cmp;
+ int rc;
+
+ rc = ssh_get_server_publickey(session, &srv_pubkey);
+ if (rc < 0) {
return -1;
- }
- if (ssh_write_knownhost(session) < 0)
- {
- fprintf(stderr, "Error %s\n", strerror(errno));
- free(hash);
+ }
+
+ rc = ssh_get_publickey_hash(srv_pubkey,
+ SSH_PUBLICKEY_HASH_SHA1,
+ &hash,
+ &hlen);
+ ssh_key_free(srv_pubkey);
+ if (rc < 0) {
return -1;
- }
- break;
+ }
- case SSH_SERVER_ERROR:
- fprintf(stderr, "Error %s", ssh_get_error(session));
- free(hash);
- return -1;
- }
+ state = ssh_session_is_known_server(session);
+ switch (state) {
+ case SSH_KNOWN_HOSTS_OK:
+ /* OK */
+
+ break;
+ case SSH_KNOWN_HOSTS_CHANGED:
+ fprintf(stderr, "Host key for server changed: it is now:\n");
+ ssh_print_hexa("Public key hash", hash, hlen);
+ fprintf(stderr, "For security reasons, connection will be stopped\n");
+ ssh_clean_pubkey_hash(&hash);
+
+ return -1;
+ case SSH_KNOWN_HOSTS_OTHER:
+ fprintf(stderr, "The host key for this server was not found but an other"
+ "type of key exists.\n");
+ fprintf(stderr, "An attacker might change the default server key to"
+ "confuse your client into thinking the key does not exist\n");
+ ssh_clean_pubkey_hash(&hash);
+
+ return -1;
+ case SSH_KNOWN_HOSTS_NOT_FOUND:
+ fprintf(stderr, "Could not find known host file.\n");
+ fprintf(stderr, "If you accept the host key here, the file will be"
+ "automatically created.\n");
+
+ /* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */
+
+ case SSH_KNOWN_HOSTS_UNKNOWN:
+ hexa = ssh_get_hexa(hash, hlen);
+ fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
+ fprintf(stderr, "Public key hash: %s\n", hexa);
+ ssh_string_free_char(hexa);
+ ssh_clean_pubkey_hash(&hash);
+ p = fgets(buf, sizeof(buf), stdin);
+ if (p == NULL) {
+ return -1;
+ }
+
+ cmp = strncasecmp(buf, "yes", 3);
+ if (cmp != 0) {
+ return -1;
+ }
+
+ rc = ssh_session_update_known_hosts(session);
+ if (rc < 0) {
+ fprintf(stderr, "Error %s\n", strerror(errno));
+ return -1;
+ }
+
+ break;
+ case SSH_KNOWN_HOSTS_ERROR:
+ fprintf(stderr, "Error %s", ssh_get_error(session));
+ ssh_clean_pubkey_hash(&hash);
+ return -1;
+ }
- free(hash);
- return 0;
+ ssh_clean_pubkey_hash(&hash);
+ return 0;
}
@endcode
@@ -260,9 +275,10 @@ int verify_knownhost(ssh_session session)
@see ssh_disconnect
@see ssh_get_error
@see ssh_get_error_code
-@see ssh_get_pubkey_hash
-@see ssh_is_server_known
-@see ssh_write_knownhost
+@see ssh_get_server_publickey
+@see ssh_get_publickey_hash
+@see ssh_session_is_known_server
+@see ssh_session_update_known_hosts
@subsection auth Authenticating the user
diff --git a/doc/mainpage.dox b/doc/mainpage.dox
index 00f46cb..a65caf9 100644
--- a/doc/mainpage.dox
+++ b/doc/mainpage.dox
@@ -19,11 +19,11 @@ the interesting functions as you go.
The libssh library provides:
- - <strong>Key Exchange Methods</strong>: <i>curve25519-sha256@libssh.org, ecdh-sha2-nistp256</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
- - <strong>Hostkey Types</strong>: <i>ecdsa-sha2-nistp256</i>, ssh-dss, ssh-rsa
+ - <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
+ - <strong>Hostkey Types</strong>: <i>ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521</i>, ssh-dss, ssh-rsa
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc, none
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
- - <strong>MAC hashes</strong>: hmac-sha1, none
+ - <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-384, hmac-sha2-512, hmac-md5, none
- <strong>Authentication</strong>: none, password, public-key, hostbased, keyboard-interactive, <i>gssapi-with-mic</i>
- <strong>Channels</strong>: shell, exec (incl. SCP wrapper), direct-tcpip, subsystem, <i>auth-agent-req@openssh.com</i>
- <strong>Global Requests</strong>: tcpip-forward, forwarded-tcpip
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index e0f4878..9bfdf45 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -30,10 +30,10 @@ if (UNIX AND NOT WIN32)
target_link_libraries(samplesftp ${LIBSSH_SHARED_LIBRARY})
endif (WITH_SFTP)
- add_executable(samplessh sample.c ${examples_SRCS})
- target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY})
+ add_executable(ssh-client ssh_client.c ${examples_SRCS})
+ target_link_libraries(ssh-client ${LIBSSH_SHARED_LIBRARY})
- if (WITH_SERVER AND ARGP_LIBRARY)
+ if (WITH_SERVER AND (ARGP_LIBRARY OR HAVE_ARGP_H))
if (HAVE_LIBUTIL)
add_executable(ssh_server_fork ssh_server_fork.c)
target_link_libraries(ssh_server_fork ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY} util)
@@ -50,7 +50,7 @@ if (UNIX AND NOT WIN32)
add_executable(samplesshd-kbdint samplesshd-kbdint.c)
target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
- endif (WITH_SERVER AND ARGP_LIBRARY)
+ endif()
endif (UNIX AND NOT WIN32)
add_executable(exec exec.c ${examples_SRCS})
diff --git a/examples/knownhosts.c b/examples/knownhosts.c
index d06969f..feacfa1 100644
--- a/examples/knownhosts.c
+++ b/examples/knownhosts.c
@@ -34,15 +34,13 @@ clients must be made or how a client should react.
int verify_knownhost(ssh_session session){
char *hexa;
- int state;
+ enum ssh_known_hosts_e state;
char buf[10];
unsigned char *hash = NULL;
size_t hlen;
ssh_key srv_pubkey;
int rc;
- state=ssh_is_server_known(session);
-
rc = ssh_get_server_publickey(session, &srv_pubkey);
if (rc < 0) {
return -1;
@@ -57,22 +55,24 @@ int verify_knownhost(ssh_session session){
return -1;
}
+ state = ssh_session_is_known_server(session);
+
switch(state){
- case SSH_SERVER_KNOWN_OK:
+ case SSH_KNOWN_HOSTS_OK:
break; /* ok */
- case SSH_SERVER_KNOWN_CHANGED:
+ case SSH_KNOWN_HOSTS_CHANGED:
fprintf(stderr,"Host key for server changed : server's one is now :\n");
ssh_print_hexa("Public key hash",hash, hlen);
ssh_clean_pubkey_hash(&hash);
fprintf(stderr,"For security reason, connection will be stopped\n");
return -1;
- case SSH_SERVER_FOUND_OTHER:
+ case SSH_KNOWN_HOSTS_OTHER:
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
fprintf(stderr,"An attacker might change the default server key to confuse your client"
"into thinking the key does not exist\n"
"We advise you to rerun the client with -d or -r for more safety.\n");
return -1;
- case SSH_SERVER_FILE_NOT_FOUND:
+ case SSH_KNOWN_HOSTS_NOT_FOUND:
fprintf(stderr,"Could not find known host file. If you accept the host key here,\n");
fprintf(stderr,"the file will be automatically created.\n");
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
@@ -104,7 +104,7 @@ int verify_knownhost(ssh_session session){
}
break;
- case SSH_SERVER_ERROR:
+ case SSH_KNOWN_HOSTS_ERROR:
ssh_clean_pubkey_hash(&hash);
fprintf(stderr,"%s",ssh_get_error(session));
return -1;
diff --git a/examples/scp_download.c b/examples/scp_download.c
index ba8782a..85ccf92 100644
--- a/examples/scp_download.c
+++ b/examples/scp_download.c
@@ -22,9 +22,12 @@ program.
#include <libssh/libssh.h>
#include "examples_common.h"
-int verbosity=0;
-const char *createcommand="rm -fr /tmp/libssh_tests && mkdir /tmp/libssh_tests && cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
-char *host=NULL;
+static int verbosity = 0;
+static const char *createcommand =
+ "rm -fr /tmp/libssh_tests && mkdir /tmp/libssh_tests && "
+ "cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
+static char *host = NULL;
+
static void usage(const char *argv0){
fprintf(stderr,"Usage : %s [options] host\n"
"sample tiny scp downloader client - libssh-%s\n"
diff --git a/examples/senddata.c b/examples/senddata.c
index acc1beb..042b462 100644
--- a/examples/senddata.c
+++ b/examples/senddata.c
@@ -3,7 +3,7 @@
#include <libssh/libssh.h>
#include "examples_common.h"
-#define LIMIT 0x100000000
+#define LIMIT 0x100000000UL
int main(void) {
ssh_session session;
diff --git a/examples/sample.c b/examples/ssh_client.c
index 53f7f6c..53f7f6c 100644
--- a/examples/sample.c
+++ b/examples/ssh_client.c
diff --git a/examples/ssh_server_fork.c b/examples/ssh_server_fork.c
index 18320c8..217c529 100644
--- a/examples/ssh_server_fork.c
+++ b/examples/ssh_server_fork.c
@@ -621,6 +621,7 @@ int main(int argc, char **argv) {
ssh_session session;
ssh_event event;
struct sigaction sa;
+ int rc;
/* Set up SIGCHLD handler. */
sa.sa_handler = sigchld_handler;
@@ -631,8 +632,17 @@ int main(int argc, char **argv) {
return 1;
}
- ssh_init();
+ rc = ssh_init();
+ if (rc < 0) {
+ fprintf(stderr, "ssh_init failed\n");
+ return 1;
+ }
+
sshbind = ssh_bind_new();
+ if (sshbind == NULL) {
+ fprintf(stderr, "ssh_bind_new failed\n");
+ return 1;
+ }
#ifdef HAVE_ARGP_H
argp_parse(&argp, argc, argv, 0, 0, sshbind);
diff --git a/include/libssh/CMakeLists.txt b/include/libssh/CMakeLists.txt
index 258e85f..85ffa6f 100644
--- a/include/libssh/CMakeLists.txt
+++ b/include/libssh/CMakeLists.txt
@@ -15,13 +15,6 @@ if (WITH_SFTP)
)
endif (WITH_SFTP)
-if (WITH_SSH1)
- set(libssh_HDRS
- ${libssh_HDRS}
- ssh1.h
- )
-endif (WITH_SSH1)
-
if (WITH_SERVER)
set(libssh_HDRS
${libssh_HDRS}
diff --git a/include/libssh/agent.h b/include/libssh/agent.h
index c739273..8f9ef94 100644
--- a/include/libssh/agent.h
+++ b/include/libssh/agent.h
@@ -115,4 +115,3 @@ ssh_string ssh_agent_sign_data(ssh_session session,
#endif
#endif /* __AGENT_H */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/include/libssh/auth.h b/include/libssh/auth.h
index 2c0012b..3913f21 100644
--- a/include/libssh/auth.h
+++ b/include/libssh/auth.h
@@ -49,20 +49,6 @@ ssh_kbdint ssh_kbdint_new(void);
void ssh_kbdint_clean(ssh_kbdint kbd);
void ssh_kbdint_free(ssh_kbdint kbd);
-
-#ifdef WITH_SSH1
-void ssh_auth1_handler(ssh_session session, uint8_t type);
-
-/* auth1.c */
-int ssh_userauth1_none(ssh_session session, const char *username);
-int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
- int type, ssh_string pubkey);
-int ssh_userauth1_password(ssh_session session, const char *username,
- const char *password);
-
-
-#endif
-
/** @internal
* States of authentication in the client-side. They describe
* what was the last response from the server
@@ -104,8 +90,6 @@ enum ssh_auth_service_state_e {
SSH_AUTH_SERVICE_ACCEPTED,
/** Access to service denied (fatal) */
SSH_AUTH_SERVICE_DENIED,
- /** Specific to SSH1 */
- SSH_AUTH_SERVICE_USER_SENT
};
#endif /* AUTH_H_ */
diff --git a/include/libssh/bignum.h b/include/libssh/bignum.h
index 71970e3..3272705 100644
--- a/include/libssh/bignum.h
+++ b/include/libssh/bignum.h
@@ -23,6 +23,7 @@
#include "libssh/libcrypto.h"
#include "libssh/libgcrypt.h"
+#include "libssh/libmbedcrypto.h"
bignum ssh_make_string_bn(ssh_string string);
void ssh_make_string_bn_inplace(ssh_string string, bignum bnout);
diff --git a/include/libssh/buffer.h b/include/libssh/buffer.h
index 81d9452..2119f2c 100644
--- a/include/libssh/buffer.h
+++ b/include/libssh/buffer.h
@@ -50,6 +50,8 @@ int ssh_buffer_add_u64(ssh_buffer buffer, uint64_t data);
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len);
+void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len);
+int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer, uint32_t len);
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
const char *format,
int argc,
@@ -81,8 +83,7 @@ int ssh_buffer_get_u64(ssh_buffer buffer, uint64_t *data);
/* ssh_buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
ssh_string ssh_buffer_get_ssh_string(ssh_buffer buffer);
-/* ssh_gets a string out of a SSH-1 mpint */
-ssh_string ssh_buffer_get_mpint(ssh_buffer buffer);
+
/* ssh_buffer_pass_bytes acts as if len bytes have been read (used for padding) */
uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
diff --git a/include/libssh/chacha.h b/include/libssh/chacha.h
new file mode 100644
index 0000000..bac78c6
--- /dev/null
+++ b/include/libssh/chacha.h
@@ -0,0 +1,41 @@
+/* $OpenBSD: chacha.h,v 1.3 2014/05/02 03:27:54 djm Exp $ */
+
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+*/
+
+#ifndef CHACHA_H
+#define CHACHA_H
+
+struct chacha_ctx {
+ uint32_t 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 uint8_t *k, uint32_t kbits)
+#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
+ __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)))
+#endif
+ ;
+void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr)
+#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
+ __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN)))
+ __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN)))
+#endif
+ ;
+void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m,
+ uint8_t *c, uint32_t bytes)
+#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
+ __attribute__((__bounded__(__buffer__, 2, 4)))
+ __attribute__((__bounded__(__buffer__, 3, 4)))
+#endif
+ ;
+
+#endif /* CHACHA_H */
diff --git a/include/libssh/channels.h b/include/libssh/channels.h
index 2c34bf5..e334489 100644
--- a/include/libssh/channels.h
+++ b/include/libssh/channels.h
@@ -71,7 +71,6 @@ struct ssh_channel_struct {
ssh_buffer stdout_buffer;
ssh_buffer stderr_buffer;
void *userarg;
- int version;
int exit_status;
enum ssh_channel_request_state_e request_state;
struct ssh_list *callbacks; /* list of ssh_channel_callbacks */
@@ -100,20 +99,5 @@ int ssh_channel_flush(ssh_channel channel);
uint32_t ssh_channel_new_id(ssh_session session);
ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id);
void ssh_channel_do_free(ssh_channel channel);
-#ifdef WITH_SSH1
-SSH_PACKET_CALLBACK(ssh_packet_data1);
-SSH_PACKET_CALLBACK(ssh_packet_close1);
-SSH_PACKET_CALLBACK(ssh_packet_exist_status1);
-
-/* channels1.c */
-int ssh_channel_open_session1(ssh_channel channel);
-int ssh_channel_request_pty_size1(ssh_channel channel, const char *terminal,
- int cols, int rows);
-int ssh_channel_change_pty_size1(ssh_channel channel, int cols, int rows);
-int ssh_channel_request_shell1(ssh_channel channel);
-int ssh_channel_request_exec1(ssh_channel channel, const char *cmd);
-int ssh_channel_write1(ssh_channel channel, const void *data, int len);
-ssh_channel ssh_get_channel1(ssh_session session);
-#endif
#endif /* CHANNELS_H_ */
diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h
index cc54b33..490910f 100644
--- a/include/libssh/crypto.h
+++ b/include/libssh/crypto.h
@@ -60,15 +60,15 @@ enum ssh_key_exchange_e {
/* ecdh-sha2-nistp521 */
SSH_KEX_ECDH_SHA2_NISTP521,
/* curve25519-sha256@libssh.org */
- SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG
+ SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG,
+ /* curve25519-sha256 */
+ SSH_KEX_CURVE25519_SHA256
};
enum ssh_cipher_e {
SSH_NO_CIPHER=0,
SSH_BLOWFISH_CBC,
SSH_3DES_CBC,
- SSH_3DES_CBC_SSH1,
- SSH_DES_CBC_SSH1,
SSH_AES128_CBC,
SSH_AES192_CBC,
SSH_AES256_CBC,
@@ -84,6 +84,8 @@ struct ssh_crypto_struct {
EC_KEY *ecdh_privkey;
#elif defined HAVE_GCRYPT_ECC
gcry_sexp_t ecdh_privkey;
+#elif defined HAVE_LIBMBEDCRYPTO
+ mbedtls_ecp_keypair *ecdh_privkey;
#endif
ssh_string ecdh_client_pubkey;
ssh_string ecdh_server_pubkey;
@@ -107,8 +109,7 @@ struct ssh_crypto_struct {
struct ssh_cipher_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
enum ssh_hmac_e in_hmac, out_hmac; /* the MAC algorithms used */
- ssh_string server_pubkey;
- const char *server_pubkey_type;
+ ssh_key server_pubkey;
int do_compress_out; /* idem */
int do_compress_in; /* don't set them, set the option instead */
int delayed_compress_in; /* Use of zlib@openssh.org */
@@ -127,16 +128,23 @@ struct ssh_cipher_struct {
const char *name; /* ssh name of the algorithm */
unsigned int blocksize; /* blocksize of the algo */
enum ssh_cipher_e ciphertype;
-#ifdef HAVE_LIBGCRYPT
+ uint32_t lenfield_blocksize; /* blocksize of the packet length field */
size_t keylen; /* length of the key structure */
+#ifdef HAVE_LIBGCRYPT
gcry_cipher_hd_t *key;
#elif defined HAVE_LIBCRYPTO
struct ssh_3des_key_schedule *des3_key;
struct ssh_aes_key_schedule *aes_key;
const EVP_CIPHER *cipher;
EVP_CIPHER_CTX *ctx;
+#elif defined HAVE_LIBMBEDCRYPTO
+ mbedtls_cipher_context_t encrypt_ctx;
+ mbedtls_cipher_context_t decrypt_ctx;
+ mbedtls_cipher_type_t type;
#endif
+ struct chacha20_poly1305_keysched *chacha20_schedule;
unsigned int keysize; /* bytes of key used. != keylen */
+ size_t tag_size; /* overhead required for tag */
/* sets the new key for immediate use */
int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
@@ -144,8 +152,15 @@ struct ssh_cipher_struct {
unsigned long len);
void (*decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
unsigned long len);
+ void (*aead_encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
+ size_t len, uint8_t *mac, uint64_t seq);
+ int (*aead_decrypt_length)(struct ssh_cipher_struct *cipher, void *in,
+ uint8_t *out, size_t len, uint64_t seq);
+ int (*aead_decrypt)(struct ssh_cipher_struct *cipher, void *complete_packet, uint8_t *out,
+ size_t encrypted_size, uint64_t seq);
void (*cleanup)(struct ssh_cipher_struct *cipher);
};
-/* vim: set ts=2 sw=2 et cindent: */
+const struct ssh_cipher_struct *ssh_get_chacha20poly1305_cipher(void);
+
#endif /* _CRYPTO_H_ */
diff --git a/include/libssh/dh.h b/include/libssh/dh.h
index 8e0d5aa..cfdcfee 100644
--- a/include/libssh/dh.h
+++ b/include/libssh/dh.h
@@ -30,18 +30,28 @@ int ssh_dh_generate_f(ssh_session session);
int ssh_dh_generate_x(ssh_session session);
int ssh_dh_generate_y(ssh_session session);
-int ssh_crypto_init(void);
-void ssh_crypto_finalize(void);
+int ssh_dh_init(void);
+void ssh_dh_finalize(void);
ssh_string ssh_dh_get_e(ssh_session session);
ssh_string ssh_dh_get_f(ssh_session session);
int ssh_dh_import_f(ssh_session session,ssh_string f_string);
int ssh_dh_import_e(ssh_session session, ssh_string e_string);
-void ssh_dh_import_pubkey(ssh_session session,ssh_string pubkey_string);
+
+int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
+int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
+
int ssh_dh_build_k(ssh_session session);
int ssh_client_dh_init(ssh_session session);
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet);
+ssh_key ssh_dh_get_current_server_publickey(ssh_session session);
+int ssh_dh_get_current_server_publickey_blob(ssh_session session,
+ ssh_string *pubkey_blob);
+ssh_key ssh_dh_get_next_server_publickey(ssh_session session);
+int ssh_dh_get_next_server_publickey_blob(ssh_session session,
+ ssh_string *pubkey_blob);
+
int ssh_make_sessionid(ssh_session session);
/* add data for the final cookie */
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
diff --git a/include/libssh/ecdh.h b/include/libssh/ecdh.h
index 9f94d69..66659b8 100644
--- a/include/libssh/ecdh.h
+++ b/include/libssh/ecdh.h
@@ -37,6 +37,10 @@
#define HAVE_ECDH 1
#endif
+#ifdef HAVE_LIBMBEDCRYPTO
+#define HAVE_ECDH 1
+#endif
+
/* Common functions. */
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
diff --git a/include/libssh/ge25519.h b/include/libssh/ge25519.h
index 64f63c6..329bd04 100644
--- a/include/libssh/ge25519.h
+++ b/include/libssh/ge25519.h
@@ -28,7 +28,7 @@ typedef struct
fe25519 t;
} ge25519;
-const ge25519 ge25519_base;
+extern const ge25519 ge25519_base;
int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]);
diff --git a/include/libssh/kex.h b/include/libssh/kex.h
index e38faff..3e9b69b 100644
--- a/include/libssh/kex.h
+++ b/include/libssh/kex.h
@@ -32,9 +32,6 @@ struct ssh_kex_struct {
};
SSH_PACKET_CALLBACK(ssh_packet_kexinit);
-#ifdef WITH_SSH1
-SSH_PACKET_CALLBACK(ssh_packet_publickey1);
-#endif
int ssh_send_kex(ssh_session session, int server_kex);
void ssh_list_kex(struct ssh_kex_struct *kex);
diff --git a/include/libssh/keys.h b/include/libssh/keys.h
index 6f08e07..f25283a 100644
--- a/include/libssh/keys.h
+++ b/include/libssh/keys.h
@@ -34,6 +34,9 @@ struct ssh_public_key_struct {
#elif HAVE_LIBCRYPTO
DSA *dsa_pub;
RSA *rsa_pub;
+#elif HAVE_LIBMBEDCRYPTO
+ mbedtls_pk_context *rsa_pub;
+ void *dsa_pub;
#endif
};
@@ -45,6 +48,9 @@ struct ssh_private_key_struct {
#elif defined HAVE_LIBCRYPTO
DSA *dsa_priv;
RSA *rsa_priv;
+#elif HAVE_LIBMBEDCRYPTO
+ mbedtls_pk_context *rsa_priv;
+ void *dsa_priv;
#endif
};
diff --git a/include/libssh/knownhosts.h b/include/libssh/knownhosts.h
index 723c7eb..d40ca8d 100644
--- a/include/libssh/knownhosts.h
+++ b/include/libssh/knownhosts.h
@@ -19,9 +19,9 @@
*/
-#ifndef KNOWNHOSTS_H_
-#define KNOWNHOSTS_H_
+#ifndef SSH_KNOWNHOSTS_H_
+#define SSH_KNOWNHOSTS_H_
-char **ssh_knownhosts_algorithms(ssh_session session);
+struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
-#endif /* KNOWNHOSTS_H_ */
+#endif /* SSH_KNOWNHOSTS_H_ */
diff --git a/include/libssh/libcrypto.h b/include/libssh/libcrypto.h
index 6a08837..cee28ba 100644
--- a/include/libssh/libcrypto.h
+++ b/include/libssh/libcrypto.h
@@ -67,13 +67,18 @@ typedef BIGNUM* bignum;
typedef BN_CTX* bignum_CTX;
#define bignum_new() BN_new()
-#define bignum_free(num) BN_clear_free(num)
+#define bignum_safe_free(num) do { \
+ if ((num) != NULL) { \
+ BN_clear_free((num)); \
+ (num)=NULL; \
+ } \
+ } while(0)
#define bignum_set_word(bn,n) BN_set_word(bn,n)
#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
#define bignum_bn2dec(num) BN_bn2dec(num)
#define bignum_dec2bn(bn,data) BN_dec2bn(data,bn)
#define bignum_bn2hex(num) BN_bn2hex(num)
-#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom)
+#define bignum_rand(rnd, bits) BN_rand(rnd, bits, 0, 1)
#define bignum_ctx_new() BN_CTX_new()
#define bignum_ctx_free(num) BN_CTX_free(num)
#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
@@ -83,20 +88,6 @@ typedef BN_CTX* bignum_CTX;
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
-SHA256CTX sha256_init(void);
-void sha256_update(SHA256CTX c, const void *data, unsigned long len);
-void sha256_final(unsigned char *md, SHA256CTX c);
-
-SHA384CTX sha384_init(void);
-void sha384_update(SHA384CTX c, const void *data, unsigned long len);
-void sha384_final(unsigned char *md, SHA384CTX c);
-
-SHA512CTX sha512_init(void);
-void sha512_update(SHA512CTX c, const void *data, unsigned long len);
-void sha512_final(unsigned char *md, SHA512CTX c);
-
-struct ssh_cipher_struct *ssh_get_ciphertab(void);
-
#endif /* HAVE_LIBCRYPTO */
#endif /* LIBCRYPTO_H_ */
diff --git a/include/libssh/libgcrypt.h b/include/libssh/libgcrypt.h
index ec35391..5695663 100644
--- a/include/libssh/libgcrypt.h
+++ b/include/libssh/libgcrypt.h
@@ -61,7 +61,12 @@ int ssh_gcry_dec2bn(bignum *bn, const char *data);
char *ssh_gcry_bn2dec(bignum bn);
#define bignum_new() gcry_mpi_new(0)
-#define bignum_free(num) gcry_mpi_release(num)
+#define bignum_safe_free(num) do { \
+ if ((num) != NULL) { \
+ gcry_mpi_release((num)); \
+ (num)=NULL; \
+ } \
+ } while (0)
#define bignum_set_word(bn,n) gcry_mpi_set_ui(bn,n)
#define bignum_bin2bn(bn,datalen,data) gcry_mpi_scan(data,GCRYMPI_FMT_USG,bn,datalen,NULL)
#define bignum_bn2dec(num) ssh_gcry_bn2dec(num)
@@ -88,6 +93,4 @@ ssh_string ssh_sexp_extract_mpi(const gcry_sexp_t sexp,
#endif /* HAVE_LIBGCRYPT */
-struct ssh_cipher_struct *ssh_get_ciphertab(void);
-
#endif /* LIBGCRYPT_H_ */
diff --git a/include/libssh/libmbedcrypto.h b/include/libssh/libmbedcrypto.h
new file mode 100644
index 0000000..7522cd1
--- /dev/null
+++ b/include/libssh/libmbedcrypto.h
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef LIBMBEDCRYPTO_H_
+#define LIBMBEDCRYPTO_H_
+
+#include "config.h"
+
+#ifdef HAVE_LIBMBEDCRYPTO
+
+#include <mbedtls/md.h>
+#include <mbedtls/bignum.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/cipher.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+
+typedef mbedtls_md_context_t *SHACTX;
+typedef mbedtls_md_context_t *SHA256CTX;
+typedef mbedtls_md_context_t *SHA384CTX;
+typedef mbedtls_md_context_t *SHA512CTX;
+typedef mbedtls_md_context_t *MD5CTX;
+typedef mbedtls_md_context_t *HMACCTX;
+typedef mbedtls_md_context_t *EVPCTX;
+
+#define SHA_DIGEST_LENGTH 20
+#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
+#define MD5_DIGEST_LEN 16
+#define SHA256_DIGEST_LENGTH 32
+#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH
+#define SHA384_DIGEST_LENGTH 48
+#define SHA384_DIGEST_LEN SHA384_DIGEST_LENGTH
+#define SHA512_DIGEST_LENGTH 64
+#define SHA512_DIGEST_LEN SHA512_DIGEST_LENGTH
+
+#ifndef EVP_MAX_MD_SIZE
+#define EVP_MAX_MD_SIZE 64
+#endif
+
+#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
+
+typedef mbedtls_mpi *bignum;
+
+/* Constants for curves */
+#define NID_mbedtls_nistp256 0
+#define NID_mbedtls_nistp384 1
+#define NID_mbedtls_nistp521 2
+
+struct mbedtls_ecdsa_sig {
+ bignum r;
+ bignum s;
+};
+
+bignum ssh_mbedcry_bn_new(void);
+void ssh_mbedcry_bn_free(bignum num);
+char *ssh_mbedcry_bn2num(bignum num, int radix);
+int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
+int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
+
+#define bignum_new() ssh_mbedcry_bn_new()
+#define bignum_safe_free(num) do { \
+ if ((num) != NULL) { \
+ ssh_mbedcry_bn_free(num); \
+ (num)=NULL; \
+ } \
+ } while(0)
+#define bignum_set_word(bn, n) mbedtls_mpi_lset(bn, n) /* TODO fix
+ overflow/underflow */
+#define bignum_bin2bn(data, datalen, bn) mbedtls_mpi_read_binary(bn, data, \
+ datalen)
+#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10)
+#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data)
+#define bignum_bn2hex(num) ssh_mbedcry_bn2num(num, 16)
+#define bignum_rand(rnd, bits) ssh_mbedcry_rand((rnd), (bits), 0, 1)
+#define bignum_mod_exp(dest, generator, exp, modulo, ctx) \
+ mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL)
+#define bignum_num_bytes(num) mbedtls_mpi_size(num)
+#define bignum_num_bits(num) mbedtls_mpi_bitlen(num)
+#define bignum_is_bit_set(num, bit) ssh_mbedcry_is_bit_set(num, bit)
+#define bignum_bn2bin(num, ptr) mbedtls_mpi_write_binary(num, ptr, \
+ mbedtls_mpi_size(num))
+#define bignum_cmp(num1, num2) mbedtls_mpi_cmp_mpi(num1, num2)
+
+mbedtls_entropy_context ssh_mbedtls_entropy;
+mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
+
+int ssh_mbedtls_random(void *where, int len, int strong);
+
+ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const
+ mbedtls_ecp_point *p);
+
+#endif /* HAVE_LIBMBEDCRYPTO */
+#endif /* LIBMBEDCRYPTO_H_ */
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index 504a645..e78b8a2 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -79,7 +79,7 @@
/* libssh version */
#define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 7
-#define LIBSSH_VERSION_MICRO 0
+#define LIBSSH_VERSION_MICRO 90
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
LIBSSH_VERSION_MINOR, \
@@ -238,6 +238,15 @@ enum ssh_server_known_e {
SSH_SERVER_FILE_NOT_FOUND
};
+enum ssh_known_hosts_e {
+ SSH_KNOWN_HOSTS_ERROR = -2,
+ SSH_KNOWN_HOSTS_NOT_FOUND = -1,
+ SSH_KNOWN_HOSTS_UNKNOWN = 0,
+ SSH_KNOWN_HOSTS_OK,
+ SSH_KNOWN_HOSTS_CHANGED,
+ SSH_KNOWN_HOSTS_OTHER,
+};
+
#ifndef MD5_DIGEST_LEN
#define MD5_DIGEST_LEN 16
#endif
@@ -267,6 +276,16 @@ enum ssh_keycmp_e {
SSH_KEY_CMP_PRIVATE
};
+#define SSH_ADDRSTRLEN 46
+
+struct ssh_knownhosts_entry {
+ char *hostname;
+ char *unparsed;
+ ssh_key publickey;
+ char *comment;
+};
+
+
/* Error return codes */
#define SSH_OK 0 /* No error */
#define SSH_ERROR -1 /* Error of some kind */
@@ -351,6 +370,12 @@ enum ssh_options_e {
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
SSH_OPTIONS_HMAC_C_S,
SSH_OPTIONS_HMAC_S_C,
+ SSH_OPTIONS_PASSWORD_AUTH,
+ SSH_OPTIONS_PUBKEY_AUTH,
+ SSH_OPTIONS_KBDINT_AUTH,
+ SSH_OPTIONS_GSSAPI_AUTH,
+ SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
+ SSH_OPTIONS_NODELAY,
};
enum {
@@ -412,6 +437,7 @@ LIBSSH_API int ssh_channel_request_pty_size(ssh_channel channel, const char *ter
int cols, int rows);
LIBSSH_API int ssh_channel_request_shell(ssh_channel channel);
LIBSSH_API int ssh_channel_request_send_signal(ssh_channel channel, const char *signum);
+LIBSSH_API int ssh_channel_request_send_break(ssh_channel channel, uint32_t length);
LIBSSH_API int ssh_channel_request_sftp(ssh_channel channel);
LIBSSH_API int ssh_channel_request_subsystem(ssh_channel channel, const char *subsystem);
LIBSSH_API int ssh_channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
@@ -498,6 +524,29 @@ LIBSSH_API int ssh_is_blocking(ssh_session session);
LIBSSH_API int ssh_is_connected(ssh_session session);
LIBSSH_API int ssh_is_server_known(ssh_session session);
+/* KNOWN HOSTS */
+LIBSSH_API void ssh_knownhosts_entry_free(struct ssh_knownhosts_entry *entry);
+#define SSH_KNOWNHOSTS_ENTRY_FREE(e) do { \
+ if ((e) != NULL) { \
+ ssh_knownhosts_entry_free(e); \
+ e = NULL; \
+ } \
+} while(0)
+
+LIBSSH_API int ssh_known_hosts_parse_line(const char *host,
+ const char *line,
+ struct ssh_knownhosts_entry **entry);
+LIBSSH_API enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session);
+
+LIBSSH_API int ssh_session_export_known_hosts_entry(ssh_session session,
+ char **pentry_string);
+LIBSSH_API int ssh_session_update_known_hosts(ssh_session session);
+
+LIBSSH_API enum ssh_known_hosts_e
+ssh_session_get_known_hosts_entry(ssh_session session,
+ struct ssh_knownhosts_entry **pentry);
+LIBSSH_API enum ssh_known_hosts_e ssh_session_is_known_server(ssh_session session);
+
/* LOGGING */
LIBSSH_API int ssh_set_log_level(int level);
LIBSSH_API int ssh_get_log_level(void);
@@ -725,4 +774,3 @@ LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
}
#endif
#endif /* _LIBSSH_H */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/include/libssh/libsshpp.hpp b/include/libssh/libsshpp.hpp
index af08a91..c324cea 100644
--- a/include/libssh/libsshpp.hpp
+++ b/include/libssh/libsshpp.hpp
@@ -194,6 +194,43 @@ public:
ssh_throw(ret);
return ret;
}
+
+ /** @brief Authenticate through the "keyboard-interactive" method.
+ * @param[in] The username to authenticate. You can specify NULL if ssh_option_set_username() has been used. You cannot try two different logins in a row.
+ * @param[in] Undocumented. Set it to NULL.
+ * @throws SshException on error
+ * @returns SSH_AUTH_SUCCESS, SSH_AUTH_PARTIAL, SSH_AUTH_DENIED, SSH_AUTH_ERROR, SSH_AUTH_INFO, SSH_AUTH_AGAIN
+ * @see ssh_userauth_kbdint
+ */
+ int userauthKbdint(const char* username, const char* submethods){
+ int ret=ssh_userauth_kbdint(c_session,NULL,NULL);
+ ssh_throw(ret);
+ return ret;
+ }
+
+ /** @brief Get the number of prompts (questions) the server has given.
+ * @returns The number of prompts.
+ * @see ssh_userauth_kbdint_getnprompts
+ */
+ int userauthKbdintGetNPrompts(){
+ return ssh_userauth_kbdint_getnprompts(c_session);
+ }
+
+ /** @brief Set the answer for a question from a message block..
+ * @param[in] index The number of the ith prompt.
+ * @param[in] The answer to give to the server. The answer MUST be encoded UTF-8. It is up to the server how to interpret the value and validate it. However, if you read the answer in some other encoding, you MUST convert it to UTF-8.
+ * @throws SshException on error
+ * @returns 0 on success, < 0 on error
+ * @see ssh_userauth_kbdint_setanswer
+ */
+ int userauthKbdintSetAnswer(unsigned int i, const char* answer){
+ int ret=ssh_userauth_kbdint_setanswer(c_session, i, answer);
+ ssh_throw(ret);
+ return ret;
+ }
+
+
+
/** @brief Authenticates using the password method.
* @param[in] password password to use for authentication
* @throws SshException on error
@@ -228,8 +265,7 @@ public:
ssh_throw(ret);
return ret;
}
- int userauthPrivatekeyFile(const char *filename,
- const char *passphrase);
+
/** @brief Returns the available authentication methods from the server
* @throws SshException on error
* @returns Bitfield of available methods.
@@ -281,8 +317,12 @@ public:
*/
std::string getIssueBanner(){
char *banner=ssh_get_issue_banner(c_session);
- std::string ret= std::string(banner);
- ::free(banner);
+ std::string ret;
+ if (banner)
+ {
+ ret= std::string(banner);
+ ::free(banner);
+ }
return ret;
}
/** @brief returns the OpenSSH version (server) if possible
@@ -303,12 +343,12 @@ public:
* @throws SshException on error
* @returns Integer value depending on the knowledge of the
* server key
- * @see ssh_is_server_known
+ * @see ssh_session_update_known_hosts
*/
int isServerKnown(){
- int ret=ssh_is_server_known(c_session);
- ssh_throw(ret);
- return ret;
+ int state = ssh_session_is_known_server(c_session);
+ ssh_throw(state);
+ return state;
}
void log(int priority, const char *format, ...){
char buffer[1024];
@@ -378,11 +418,14 @@ public:
return_throwable;
}
-private:
- ssh_session c_session;
ssh_session getCSession(){
return c_session;
}
+
+protected:
+ ssh_session c_session;
+
+private:
/* No copy constructor, no = operator */
Session(const Session &);
Session& operator=(const Session &);
@@ -481,12 +524,12 @@ public:
ssh_throw(err);
return err;
}
- int read(void *dest, size_t count, bool is_stderr){
+ int read(void *dest, size_t count){
int err;
/* handle int overflow */
if(count > 0x7fffffff)
count = 0x7fffffff;
- err=ssh_channel_read_timeout(channel,dest,count,is_stderr,-1);
+ err=ssh_channel_read_timeout(channel,dest,count,false,-1);
ssh_throw(err);
return err;
}
@@ -584,16 +627,24 @@ public:
ssh_throw(ret);
return ret;
}
-private:
+
ssh_session getCSession(){
return session->getCSession();
}
+
+ ssh_channel getCChannel() {
+ return channel;
+ }
+
+protected:
+ Session *session;
+ ssh_channel channel;
+
+private:
Channel (Session &session, ssh_channel c_channel){
this->channel=c_channel;
this->session=&session;
}
- Session *session;
- ssh_channel channel;
/* No copy and no = operator */
Channel(const Channel &);
Channel &operator=(const Channel &);
diff --git a/include/libssh/misc.h b/include/libssh/misc.h
index 128e2ba..bc50cff 100644
--- a/include/libssh/misc.h
+++ b/include/libssh/misc.h
@@ -29,7 +29,7 @@ int ssh_file_readaccess_ok(const char *file);
char *ssh_path_expand_tilde(const char *d);
char *ssh_path_expand_escape(ssh_session session, const char *s);
-int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2);
+int ssh_analyze_banner(ssh_session session, int server);
int ssh_is_ipaddr_v4(const char *str);
int ssh_is_ipaddr(const char *str);
@@ -54,6 +54,7 @@ struct ssh_list *ssh_list_new(void);
void ssh_list_free(struct ssh_list *list);
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
struct ssh_iterator *ssh_list_find(const struct ssh_list *list, void *value);
+size_t ssh_list_count(const struct ssh_list *list);
int ssh_list_append(struct ssh_list *list, const void *data);
int ssh_list_prepend(struct ssh_list *list, const void *data);
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);
diff --git a/include/libssh/packet.h b/include/libssh/packet.h
index 3a84eb7..1a9283d 100644
--- a/include/libssh/packet.h
+++ b/include/libssh/packet.h
@@ -45,17 +45,6 @@ enum ssh_packet_state_e {
int ssh_packet_send(ssh_session session);
-#ifdef WITH_SSH1
-int ssh_packet_send1(ssh_session session) ;
-void ssh_packet_set_default_callbacks1(ssh_session session);
-
-SSH_PACKET_CALLBACK(ssh_packet_disconnect1);
-SSH_PACKET_CALLBACK(ssh_packet_smsg_success1);
-SSH_PACKET_CALLBACK(ssh_packet_smsg_failure1);
-int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user);
-
-#endif
-
SSH_PACKET_CALLBACK(ssh_packet_unimplemented);
SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback);
SSH_PACKET_CALLBACK(ssh_packet_ignore_callback);
@@ -78,8 +67,9 @@ void ssh_packet_set_default_callbacks(ssh_session session);
void ssh_packet_process(ssh_session session, uint8_t type);
/* PACKET CRYPT */
-uint32_t ssh_packet_decrypt_len(ssh_session session, char *crypted);
-int ssh_packet_decrypt(ssh_session session, void *packet, unsigned int len);
+uint32_t ssh_packet_decrypt_len(ssh_session session, uint8_t *destination, uint8_t *source);
+int ssh_packet_decrypt(ssh_session session, uint8_t *destination, uint8_t *source,
+ size_t start, size_t encrypted_size);
unsigned char *ssh_packet_encrypt(ssh_session session,
void *packet,
unsigned int len);
diff --git a/include/libssh/pcap.h b/include/libssh/pcap.h
index ca57156..2e43ae8 100644
--- a/include/libssh/pcap.h
+++ b/include/libssh/pcap.h
@@ -43,4 +43,3 @@ int ssh_pcap_context_write(ssh_pcap_context,enum ssh_pcap_direction direction, v
#endif /* WITH_PCAP */
#endif /* PCAP_H_ */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/include/libssh/pki.h b/include/libssh/pki.h
index e0e30f1..4a4ce61 100644
--- a/include/libssh/pki.h
+++ b/include/libssh/pki.h
@@ -48,6 +48,10 @@ struct ssh_key_struct {
gcry_sexp_t dsa;
gcry_sexp_t rsa;
gcry_sexp_t ecdsa;
+#elif HAVE_LIBMBEDCRYPTO
+ mbedtls_pk_context *rsa;
+ mbedtls_ecdsa_context *ecdsa;
+ void *dsa;
#elif HAVE_LIBCRYPTO
DSA *dsa;
RSA *rsa;
@@ -78,6 +82,9 @@ struct ssh_signature_struct {
# else
void *ecdsa_sig;
# endif
+#elif defined HAVE_LIBMBEDCRYPTO
+ ssh_string rsa_sig;
+ struct mbedtls_ecdsa_sig ecdsa_sig;
#endif
ed25519_signature *ed25519_sig;
};
@@ -108,10 +115,6 @@ int ssh_pki_export_pubkey_blob(const ssh_key key,
ssh_string *pblob);
int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
ssh_key *pkey);
-int ssh_pki_export_pubkey_rsa1(const ssh_key key,
- const char *host,
- char *rsa1,
- size_t rsa1_len);
int ssh_pki_import_cert_blob(const ssh_string cert_blob,
ssh_key *pkey);
diff --git a/include/libssh/pki_priv.h b/include/libssh/pki_priv.h
index 9a8857d..af04150 100644
--- a/include/libssh/pki_priv.h
+++ b/include/libssh/pki_priv.h
@@ -80,10 +80,6 @@ int pki_pubkey_build_rsa(ssh_key key,
ssh_string n);
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e);
ssh_string pki_publickey_to_blob(const ssh_key key);
-int pki_export_pubkey_rsa1(const ssh_key key,
- const char *host,
- char *rsa1,
- size_t rsa1_len);
/* SSH Signature Functions */
ssh_string pki_signature_to_blob(const ssh_signature sign);
diff --git a/include/libssh/poly1305.h b/include/libssh/poly1305.h
new file mode 100644
index 0000000..9174bd1
--- /dev/null
+++ b/include/libssh/poly1305.h
@@ -0,0 +1,21 @@
+/*
+ * Public Domain poly1305 from Andrew Moon
+ * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
+ */
+
+#ifndef POLY1305_H
+#define POLY1305_H
+
+#define POLY1305_KEYLEN 32
+#define POLY1305_TAGLEN 16
+
+void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen,
+ const uint8_t key[POLY1305_KEYLEN])
+#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
+ __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN)))
+ __attribute__((__bounded__(__buffer__, 2, 3)))
+ __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN)))
+#endif
+ ;
+
+#endif /* POLY1305_H */
diff --git a/include/libssh/priv.h b/include/libssh/priv.h
index 8e6a8e6..16c6200 100644
--- a/include/libssh/priv.h
+++ b/include/libssh/priv.h
@@ -29,7 +29,8 @@
#ifndef _LIBSSH_PRIV_H
#define _LIBSSH_PRIV_H
-#include "config.h"
+#include <stdlib.h>
+#include <string.h>
#if !defined(HAVE_STRTOULL)
# if defined(HAVE___STRTOULL)
@@ -47,6 +48,10 @@
#include <byteswap.h>
#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
#ifndef bswap_32
#define bswap_32(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
@@ -145,12 +150,11 @@ int gettimeofday(struct timeval *__p, void *__t);
#ifndef ERROR_BUFFERLEN
#define ERROR_BUFFERLEN 1024
#endif
-#ifndef CLIENTBANNER1
-#define CLIENTBANNER1 "SSH-1.5-libssh_" SSH_STRINGIFY(LIBSSH_VERSION)
-#endif
-#ifndef CLIENTBANNER2
-#define CLIENTBANNER2 "SSH-2.0-libssh_" SSH_STRINGIFY(LIBSSH_VERSION)
-#endif
+
+#ifndef CLIENT_BANNER_SSH2
+#define CLIENT_BANNER_SSH2 "SSH-2.0-libssh_" SSH_STRINGIFY(LIBSSH_VERSION)
+#endif /* CLIENT_BANNER_SSH2 */
+
#ifndef KBDINT_MAX_PROMPT
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
#endif
@@ -279,33 +283,9 @@ int ssh_connector_remove_event(ssh_connector connector);
/** Get the size of an array */
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
-/*
- * See http://llvm.org/bugs/show_bug.cgi?id=15495
- */
-#if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
-/** Overwrite a string with '\0' */
-# define BURN_STRING(x) do { \
- if ((x) != NULL) \
- memset((x), '\0', strlen((x))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
- } while(0)
-
-/** Overwrite the buffer with '\0' */
-# define BURN_BUFFER(x, size) do { \
- if ((x) != NULL) \
- memset((x), '\0', (size)); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
- } while(0)
-#else /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
-/** Overwrite a string with '\0' */
-# define BURN_STRING(x) do { \
- if ((x) != NULL) memset((x), '\0', strlen((x))); \
- } while(0)
-
-/** Overwrite the buffer with '\0' */
-# define BURN_BUFFER(x, size) do { \
- if ((x) != NULL) \
- memset((x), '\0', (size)); \
- } while(0)
-#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
+#ifndef HAVE_EXPLICIT_BZERO
+void explicit_bzero(void *s, size_t n);
+#endif /* !HAVE_EXPLICIT_BZERO */
/**
* This is a hack to fix warnings. The idea is to use this everywhere that we
@@ -394,4 +374,3 @@ int ssh_connector_remove_event(ssh_connector connector);
void ssh_agent_state_free(void *data);
#endif /* _LIBSSH_PRIV_H */
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/include/libssh/server.h b/include/libssh/server.h
index c2132de..aeacda0 100644
--- a/include/libssh/server.h
+++ b/include/libssh/server.h
@@ -188,6 +188,24 @@ LIBSSH_API ssh_gssapi_creds ssh_gssapi_get_creds(ssh_session session);
LIBSSH_API int ssh_handle_key_exchange(ssh_session session);
/**
+ * @brief Initialize the set of key exchange, hostkey, ciphers, MACs, and
+ * compression algorithms for the given ssh_session.
+ *
+ * The selection of algorithms and keys used are determined by the
+ * options that are currently set in the given ssh_session structure.
+ * May only be called before the initial key exchange has begun.
+ *
+ * @param session The session structure to initialize.
+ *
+ * @see ssh_handle_key_exchange
+ * @see ssh_options_set
+ *
+ * @return SSH_OK if initialization succeeds.
+ */
+
+LIBSSH_API int ssh_server_init_kex(ssh_session session);
+
+/**
* @brief Free a ssh servers bind.
*
* @param ssh_bind_o The ssh server bind to free.
diff --git a/include/libssh/session.h b/include/libssh/session.h
index 60d7857..5421056 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -79,6 +79,13 @@ enum ssh_pending_call_e {
/* Don't block at all */
#define SSH_TIMEOUT_NONBLOCKING 0
+/* options flags */
+/* Authentication with *** allowed */
+#define SSH_OPT_FLAG_PASSWORD_AUTH 0x1
+#define SSH_OPT_FLAG_PUBKEY_AUTH 0x2
+#define SSH_OPT_FLAG_KBDINT_AUTH 0x4
+#define SSH_OPT_FLAG_GSSAPI_AUTH 0x8
+
/* members that are common to ssh_session and ssh_bind */
struct ssh_common_struct {
struct error_struct error;
@@ -150,7 +157,7 @@ struct ssh_session_struct {
/* keyb interactive data */
struct ssh_kbdint_struct *kbdint;
struct ssh_gssapi_struct *gssapi;
- int version; /* 1 or 2 */
+
/* server host keys */
struct {
ssh_key rsa_key;
@@ -182,6 +189,7 @@ struct ssh_session_struct {
char *bindaddr; /* bind the client to an ip addr */
char *sshdir;
char *knownhosts;
+ char *global_knownhosts;
char *wanted_methods[10];
char *ProxyCommand;
char *custombanner;
@@ -190,12 +198,12 @@ struct ssh_session_struct {
unsigned int port;
socket_t fd;
int StrictHostKeyChecking;
- int ssh2;
- int ssh1;
char compressionlevel;
char *gss_server_identity;
char *gss_client_identity;
int gss_delegate_creds;
+ int flags;
+ int nodelay;
} opts;
/* counters */
ssh_counter socket_counter;
diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h
index 63673ca..b07f269 100644
--- a/include/libssh/sftp.h
+++ b/include/libssh/sftp.h
@@ -863,18 +863,18 @@ LIBSSH_API void sftp_client_message_set_filename(sftp_client_message msg, const
LIBSSH_API const char *sftp_client_message_get_data(sftp_client_message msg);
LIBSSH_API uint32_t sftp_client_message_get_flags(sftp_client_message msg);
LIBSSH_API int sftp_send_client_message(sftp_session sftp, sftp_client_message msg);
-int sftp_reply_name(sftp_client_message msg, const char *name,
+LIBSSH_API int sftp_reply_name(sftp_client_message msg, const char *name,
sftp_attributes attr);
-int sftp_reply_handle(sftp_client_message msg, ssh_string handle);
-ssh_string sftp_handle_alloc(sftp_session sftp, void *info);
-int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr);
-void *sftp_handle(sftp_session sftp, ssh_string handle);
-int sftp_reply_status(sftp_client_message msg, uint32_t status, const char *message);
-int sftp_reply_names_add(sftp_client_message msg, const char *file,
+LIBSSH_API int sftp_reply_handle(sftp_client_message msg, ssh_string handle);
+LIBSSH_API ssh_string sftp_handle_alloc(sftp_session sftp, void *info);
+LIBSSH_API int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr);
+LIBSSH_API void *sftp_handle(sftp_session sftp, ssh_string handle);
+LIBSSH_API int sftp_reply_status(sftp_client_message msg, uint32_t status, const char *message);
+LIBSSH_API int sftp_reply_names_add(sftp_client_message msg, const char *file,
const char *longname, sftp_attributes attr);
-int sftp_reply_names(sftp_client_message msg);
-int sftp_reply_data(sftp_client_message msg, const void *data, int len);
-void sftp_handle_remove(sftp_session sftp, void *handle);
+LIBSSH_API int sftp_reply_names(sftp_client_message msg);
+LIBSSH_API int sftp_reply_data(sftp_client_message msg, const void *data, int len);
+LIBSSH_API void sftp_handle_remove(sftp_session sftp, void *handle);
/* SFTP commands and constants */
#define SSH_FXP_INIT 1
@@ -1017,10 +1017,9 @@ void sftp_handle_remove(sftp_session sftp, void *handle);
#define SSH_FXE_STATVFS_ST_NOSUID 0x2 /* no setuid */
#ifdef __cplusplus
-} ;
+}
#endif
#endif /* SFTP_H */
/** @} */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/include/libssh/ssh1.h b/include/libssh/ssh1.h
deleted file mode 100644
index ce67f20..0000000
--- a/include/libssh/ssh1.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef __SSH1_H
-#define __SSH1_H
-
-#define SSH_MSG_NONE 0 /* no message */
-#define SSH_MSG_DISCONNECT 1 /* cause (string) */
-#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
-#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
-#define SSH_CMSG_USER 4 /* user (string) */
-#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */
-#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */
-#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */
-#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */
-#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */
-#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */
-#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */
-#define SSH_CMSG_EXEC_SHELL 12 /* */
-#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */
-#define SSH_SMSG_SUCCESS 14 /* */
-#define SSH_SMSG_FAILURE 15 /* */
-#define SSH_CMSG_STDIN_DATA 16 /* data (string) */
-#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */
-#define SSH_SMSG_STDERR_DATA 18 /* data (string) */
-#define SSH_CMSG_EOF 19 /* */
-#define SSH_SMSG_EXITSTATUS 20 /* status (int) */
-#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */
-#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */
-#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */
-#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */
-#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */
-/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */
-#define SSH_SMSG_X11_OPEN 27 /* channel (int) */
-#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */
-#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */
-#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */
-#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */
-#define SSH_MSG_IGNORE 32 /* string */
-#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */
-#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */
-#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */
-#define SSH_MSG_DEBUG 36 /* string */
-#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
-#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
-#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
-#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
-#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
-#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
-#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
-#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
-#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */
-
-/* protocol version 1.5 overloads some version 1.3 message types */
-#define SSH_MSG_CHANNEL_INPUT_EOF SSH_MSG_CHANNEL_CLOSE
-#define SSH_MSG_CHANNEL_OUTPUT_CLOSE SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
-
-/*
- * Authentication methods. New types can be added, but old types should not
- * be removed for compatibility. The maximum allowed value is 31.
- */
-#define SSH_AUTH_RHOSTS 1
-#define SSH_AUTH_RSA 2
-#define SSH_AUTH_PASSWORD 3
-#define SSH_AUTH_RHOSTS_RSA 4
-#define SSH_AUTH_TIS 5
-#define SSH_AUTH_KERBEROS 6
-#define SSH_PASS_KERBEROS_TGT 7
- /* 8 to 15 are reserved */
-#define SSH_PASS_AFS_TOKEN 21
-
-/* Protocol flags. These are bit masks. */
-#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
-#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
-
-/* cipher flags. they are bit numbers */
-#define SSH_CIPHER_NONE 0 /* No encryption */
-#define SSH_CIPHER_IDEA 1 /* IDEA in CFB mode */
-#define SSH_CIPHER_DES 2 /* DES in CBC mode */
-#define SSH_CIPHER_3DES 3 /* Triple-DES in CBC mode */
-#define SSH_CIPHER_RC4 5 /* RC4 */
-#define SSH_CIPHER_BLOWFISH 6
-
-#endif
-
diff --git a/include/libssh/threads.h b/include/libssh/threads.h
index 7007264..e8ccf7b 100644
--- a/include/libssh/threads.h
+++ b/include/libssh/threads.h
@@ -24,8 +24,40 @@
#include <libssh/libssh.h>
#include <libssh/callbacks.h>
+#if HAVE_PTHREAD
+
+#include <pthread.h>
+#define SSH_MUTEX pthread_mutex_t
+
+#if defined _GNU_SOURCE
+#define SSH_MUTEX_STATIC_INIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+#else
+#define SSH_MUTEX_STATIC_INIT PTHREAD_MUTEX_INITIALIZER
+#endif
+
+#elif (defined _WIN32) || (defined _WIN64)
+
+#include <windows.h>
+#include <winbase.h>
+#define SSH_MUTEX CRITICAL_SECTION *
+#define SSH_MUTEX_STATIC_INIT NULL
+
+#else
+
+# define SSH_MUTEX void *
+#define SSH_MUTEX_STATIC_INIT NULL
+
+#endif
+
int ssh_threads_init(void);
void ssh_threads_finalize(void);
const char *ssh_threads_get_type(void);
+void ssh_mutex_lock(SSH_MUTEX *mutex);
+void ssh_mutex_unlock(SSH_MUTEX *mutex);
+
+struct ssh_threads_callbacks_struct *ssh_threads_get_default(void);
+int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks);
+void crypto_thread_finalize(void);
+
#endif /* THREADS_H_ */
diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h
index cdd72d6..62a974f 100644
--- a/include/libssh/wrapper.h
+++ b/include/libssh/wrapper.h
@@ -25,6 +25,7 @@
#include "libssh/libssh.h"
#include "libssh/libcrypto.h"
#include "libssh/libgcrypt.h"
+#include "libssh/libmbedcrypto.h"
enum ssh_mac_e {
SSH_MAC_SHA1=1,
@@ -38,7 +39,8 @@ enum ssh_hmac_e {
SSH_HMAC_SHA256,
SSH_HMAC_SHA384,
SSH_HMAC_SHA512,
- SSH_HMAC_MD5
+ SSH_HMAC_MD5,
+ SSH_HMAC_AEAD_POLY1305
};
enum ssh_des_e {
@@ -51,6 +53,8 @@ struct ssh_hmac_struct {
enum ssh_hmac_e hmac_type;
};
+struct ssh_cipher_struct;
+
typedef struct ssh_mac_ctx_struct *ssh_mac_ctx;
MD5CTX md5_init(void);
void md5_update(MD5CTX c, const void *data, unsigned long len);
@@ -90,15 +94,18 @@ void hmac_update(HMACCTX c, const void *data, unsigned long len);
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
size_t hmac_digest_len(enum ssh_hmac_e type);
-int crypt_set_algorithms(ssh_session session, enum ssh_des_e des_type);
+int crypt_set_algorithms_client(ssh_session session);
int crypt_set_algorithms_server(ssh_session session);
struct ssh_crypto_struct *crypto_new(void);
void crypto_free(struct ssh_crypto_struct *crypto);
void ssh_reseed(void);
+int ssh_crypto_init(void);
+void ssh_crypto_finalize(void);
void ssh_cipher_clear(struct ssh_cipher_struct *cipher);
struct ssh_hmac_struct *ssh_get_hmactab(void);
+struct ssh_cipher_struct *ssh_get_ciphertab(void);
const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type);
#endif /* WRAPPER_H_ */
diff --git a/libssh-config.cmake.in b/libssh-config.cmake.in
index fa9cecf..b34cd4f 100644
--- a/libssh-config.cmake.in
+++ b/libssh-config.cmake.in
@@ -11,3 +11,5 @@ set(LIBSSH_LIBRARY @LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@)
set(LIBSSH_LIBRARIES @LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@)
set(LIBSSH_THREADS_LIBRARY @LIB_INSTALL_DIR@/@LIBSSH_THREADS_LIBRARY_NAME@)
+
+mark_as_advanced(LIBSSH_LIBRARIES LIBSSH_INCLUDE_DIR)
diff --git a/obj/build_make.sh b/obj/build_make.sh
deleted file mode 100755
index 2f2e4a6..0000000
--- a/obj/build_make.sh
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/bin/bash
-#
-# Last Change: 2008-06-18 14:13:46
-#
-# Script to build libssh on UNIX.
-#
-# Copyright (c) 2006-2007 Andreas Schneider <asn@cryptomilk.org>
-#
-
-SOURCE_DIR=".."
-
-LANG=C
-export LANG
-
-SCRIPT="$0"
-COUNT=0
-while [ -L "${SCRIPT}" ]
-do
- SCRIPT=$(readlink ${SCRIPT})
- COUNT=$(expr ${COUNT} + 1)
- if [ ${COUNT} -gt 100 ]; then
- echo "Too many symbolic links"
- exit 1
- fi
-done
-BUILDDIR=$(dirname ${SCRIPT})
-
-cleanup_and_exit () {
- if test "$1" = 0 -o -z "$1" ; then
- exit 0
- else
- exit $1
- fi
-}
-
-function configure() {
- if [ -n "${CMAKEDIR}" ]; then
- ${CMAKEDIR}/bin/cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
- else
- cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
- fi
-}
-
-function compile() {
- if [ -f /proc/cpuinfo ]; then
- CPUCOUNT=$(grep -c processor /proc/cpuinfo)
- elif test `uname` = "SunOS" ; then
- CPUCOUNT=$(psrinfo -p)
- else
- CPUCOUNT="1"
- fi
-
- if [ "${CPUCOUNT}" -gt "1" ]; then
- ${MAKE} -j${CPUCOUNT} $1 || cleanup_and_exit $?
- else
- ${MAKE} $1 || exit $?
- fi
-}
-
-function clean_build_dir() {
- find ! -path "*.svn*" ! -name "*.bat" ! -name "*.sh" ! -name "." -print0 | xargs -0 rm -rf
-}
-
-function usage () {
-echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help|--clang|--cmakedir /directory|--make
-(gmake|make)|--ccompiler (gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withssh1|--withserver]"
- cleanup_and_exit
-}
-
-cd ${BUILDDIR}
-
-# the default CMake options:
-OPTIONS="--graphviz=${BUILDDIR}/libssh.dot"
-
-# the default 'make' utility:
-MAKE="make"
-
-while test -n "$1"; do
- PARAM="$1"
- ARG="$2"
- shift
- case ${PARAM} in
- *-*=*)
- ARG=${PARAM#*=}
- PARAM=${PARAM%%=*}
- set -- "----noarg=${PARAM}" "$@"
- esac
- case ${PARAM} in
- *-help|-h)
- #echo_help
- usage
- cleanup_and_exit
- ;;
- *-build)
- DOMAKE="1"
- BUILD_TYPE="${ARG}"
- test -n "${BUILD_TYPE}" && shift
- ;;
- *-clean)
- clean_build_dir
- cleanup_and_exit
- ;;
- *-clang)
- OPTIONS="${OPTIONS} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
- ;;
- *-verbose)
- DOVERBOSE="1"
- ;;
- *-memtest)
- OPTIONS="${OPTIONS} -DMEM_NULL_TESTS=ON"
- ;;
- *-libsuffix)
- OPTIONS="${OPTIONS} -DLIB_SUFFIX=${ARG}"
- shift
- ;;
- *-prefix)
- OPTIONS="${OPTIONS} -DCMAKE_INSTALL_PREFIX=${ARG}"
- shift
- ;;
- *-sysconfdir)
- OPTIONS="${OPTIONS} -DSYSCONF_INSTALL_DIR=${ARG}"
- shift
- ;;
- *-cmakedir)
- CMAKEDIR="${ARG}"
- shift
- ;;
- *-make)
- MAKE="${ARG}"
- shift
- ;;
- *-ccompiler)
- OPTIONS="${OPTIONS} -DCMAKE_C_COMPILER=${ARG}"
- shift
- ;;
- *-withstaticlib)
- OPTIONS="${OPTIONS} -DWITH_STATIC_LIB=ON"
- ;;
- *-unittesting)
- OPTIONS="${OPTIONS} -DWITH_TESTING=ON"
- ;;
- *-clientunittesting)
- OPTIONS="${OPTIONS} -DWITH_CLIENT_TESTING=ON"
- ;;
- *-withssh1)
- OPTIONS="${OPTIONS} -DWITH_SSH1=ON"
- ;;
- *-withserver)
- OPTIONS="${OPTIONS} -DWITH_SERVER=ON"
- ;;
- ----noarg)
- echo "$ARG does not take an argument"
- cleanup_and_exit
- ;;
- -*)
- echo Unknown Option "$PARAM". Exit.
- cleanup_and_exit 1
- ;;
- *)
- usage
- ;;
- esac
-done
-
-if [ "${DOMAKE}" == "1" ]; then
- OPTIONS="${OPTIONS} -DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
-fi
-
-if [ -n "${DOVERBOSE}" ]; then
- OPTIONS="${OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=1"
-else
- OPTIONS="${OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=0"
-fi
-
-test -f "${BUILDDIR}/.build.log" && rm -f ${BUILDDIR}/.build.log
-touch ${BUILDDIR}/.build.log
-# log everything from here to .build.log
-exec 1> >(exec -a 'build logging tee' tee -a ${BUILDDIR}/.build.log) 2>&1
-echo "${HOST} started build at $(date)."
-echo
-
-configure ${OPTIONS} "$@"
-
-if [ -n "${DOMAKE}" ]; then
- test -n "${DOVERBOSE}" && compile VERBOSE=1 || compile
-fi
-
-DOT=$(which dot 2>/dev/null)
-if [ -n "${DOT}" ]; then
- ${DOT} -Tpng -o${BUILDDIR}/libssh.png ${BUILDDIR}/libssh.dot
- ${DOT} -Tsvg -o${BUILDDIR}/libssh.svg ${BUILDDIR}/libssh.dot
-fi
-
-exec >&0 2>&0 # so that the logging tee finishes
-sleep 1 # wait till tee terminates
-
-cleanup_and_exit 0
diff --git a/src/ABI/current b/src/ABI/current
new file mode 100644
index 0000000..a84947d
--- /dev/null
+++ b/src/ABI/current
@@ -0,0 +1 @@
+4.5.0
diff --git a/src/ABI/libssh-4.5.0.symbols b/src/ABI/libssh-4.5.0.symbols
new file mode 100644
index 0000000..1848fe0
--- /dev/null
+++ b/src/ABI/libssh-4.5.0.symbols
@@ -0,0 +1,411 @@
+ssh_set_server_callbacks
+ssh_set_callbacks
+ssh_set_channel_callbacks
+ssh_add_channel_callbacks
+ssh_remove_channel_callbacks
+ssh_threads_set_callbacks
+ssh_threads_get_pthread
+ssh_threads_get_noop
+ssh_set_log_callback
+ssh_get_log_callback
+ssh_auth_list
+ssh_userauth_offer_pubkey
+ssh_userauth_pubkey
+ssh_userauth_agent_pubkey
+ssh_userauth_autopubkey
+ssh_userauth_privatekey_file
+buffer_free
+buffer_get
+buffer_get_len
+buffer_new
+channel_accept_x11
+channel_change_pty_size
+channel_forward_accept
+channel_close
+channel_forward_cancel
+channel_forward_listen
+channel_free
+channel_get_exit_status
+channel_get_session
+channel_is_closed
+channel_is_eof
+channel_is_open
+channel_new
+channel_open_forward
+channel_open_session
+channel_poll
+channel_read
+channel_read_buffer
+channel_read_nonblocking
+channel_request_env
+channel_request_exec
+channel_request_pty
+channel_request_pty_size
+channel_request_shell
+channel_request_send_signal
+channel_request_sftp
+channel_request_subsystem
+channel_request_x11
+channel_send_eof
+channel_select
+channel_set_blocking
+channel_write
+privatekey_free
+privatekey_from_file
+publickey_free
+ssh_publickey_to_file
+publickey_from_file
+publickey_from_privatekey
+publickey_to_string
+ssh_try_publickey_from_file
+ssh_privatekey_type
+ssh_get_pubkey
+ssh_message_retrieve
+ssh_message_auth_publickey
+string_burn
+string_copy
+string_data
+string_fill
+string_free
+string_from_char
+string_len
+string_new
+string_to_char
+ssh_blocking_flush
+ssh_channel_accept_x11
+ssh_channel_change_pty_size
+ssh_channel_close
+ssh_channel_free
+ssh_channel_get_exit_status
+ssh_channel_get_session
+ssh_channel_is_closed
+ssh_channel_is_eof
+ssh_channel_is_open
+ssh_channel_new
+ssh_channel_open_auth_agent
+ssh_channel_open_forward
+ssh_channel_open_session
+ssh_channel_open_x11
+ssh_channel_poll
+ssh_channel_poll_timeout
+ssh_channel_read
+ssh_channel_read_timeout
+ssh_channel_read_nonblocking
+ssh_channel_request_env
+ssh_channel_request_exec
+ssh_channel_request_pty
+ssh_channel_request_pty_size
+ssh_channel_request_shell
+ssh_channel_request_send_signal
+ssh_channel_request_send_break
+ssh_channel_request_sftp
+ssh_channel_request_subsystem
+ssh_channel_request_x11
+ssh_channel_request_auth_agent
+ssh_channel_send_eof
+ssh_channel_select
+ssh_channel_set_blocking
+ssh_channel_set_counter
+ssh_channel_write
+ssh_channel_write_stderr
+ssh_channel_window_size
+ssh_basename
+ssh_clean_pubkey_hash
+ssh_connect
+ssh_connector_new
+ssh_connector_free
+ssh_connector_set_in_channel
+ssh_connector_set_out_channel
+ssh_connector_set_in_fd
+ssh_connector_set_out_fd
+ssh_copyright
+ssh_disconnect
+ssh_dirname
+ssh_finalize
+ssh_channel_accept_forward
+ssh_channel_cancel_forward
+ssh_channel_listen_forward
+ssh_free
+ssh_get_disconnect_message
+ssh_get_error
+ssh_get_error_code
+ssh_get_fd
+ssh_get_hexa
+ssh_get_issue_banner
+ssh_get_openssh_version
+ssh_get_server_publickey
+ssh_get_publickey_hash
+ssh_get_pubkey_hash
+ssh_forward_accept
+ssh_forward_cancel
+ssh_forward_listen
+ssh_get_publickey
+ssh_get_random
+ssh_get_version
+ssh_get_status
+ssh_get_poll_flags
+ssh_init
+ssh_is_blocking
+ssh_is_connected
+ssh_is_server_known
+ssh_knownhosts_entry_free
+ssh_known_hosts_parse_line
+ssh_session_has_known_hosts_entry
+ssh_session_export_known_hosts_entry
+ssh_session_update_known_hosts
+ssh_session_is_known_server
+ssh_set_log_level
+ssh_get_log_level
+ssh_get_log_userdata
+ssh_set_log_userdata
+_ssh_log
+ssh_log
+ssh_message_channel_request_open_reply_accept
+ssh_message_channel_request_reply_success
+ssh_message_free
+ssh_message_get
+ssh_message_subtype
+ssh_message_type
+ssh_mkdir
+ssh_new
+ssh_options_copy
+ssh_options_getopt
+ssh_options_parse_config
+ssh_options_set
+ssh_options_get
+ssh_options_get_port
+ssh_pcap_file_close
+ssh_pcap_file_free
+ssh_pcap_file_new
+ssh_pcap_file_open
+ssh_key_new
+ssh_key_free
+ssh_key_type
+ssh_key_type_to_char
+ssh_key_type_from_name
+ssh_key_is_public
+ssh_key_is_private
+ssh_key_cmp
+ssh_pki_generate
+ssh_pki_import_privkey_base64
+ssh_pki_import_privkey_file
+ssh_pki_export_privkey_file
+ssh_pki_copy_cert_to_privkey
+ssh_pki_import_pubkey_base64
+ssh_pki_import_pubkey_file
+ssh_pki_import_cert_base64
+ssh_pki_import_cert_file
+ssh_pki_export_privkey_to_pubkey
+ssh_pki_export_pubkey_base64
+ssh_pki_export_pubkey_file
+ssh_pki_key_ecdsa_name
+ssh_print_hexa
+ssh_send_ignore
+ssh_send_debug
+ssh_gssapi_set_creds
+ssh_scp_accept_request
+ssh_scp_close
+ssh_scp_deny_request
+ssh_scp_free
+ssh_scp_init
+ssh_scp_leave_directory
+ssh_scp_new
+ssh_scp_pull_request
+ssh_scp_push_directory
+ssh_scp_push_file
+ssh_scp_push_file64
+ssh_scp_read
+ssh_scp_request_get_filename
+ssh_scp_request_get_permissions
+ssh_scp_request_get_size
+ssh_scp_request_get_size64
+ssh_scp_request_get_warning
+ssh_scp_write
+ssh_select
+ssh_service_request
+ssh_set_agent_channel
+ssh_set_agent_socket
+ssh_set_blocking
+ssh_set_counters
+ssh_set_fd_except
+ssh_set_fd_toread
+ssh_set_fd_towrite
+ssh_silent_disconnect
+ssh_set_pcap_file
+ssh_userauth_none
+ssh_userauth_list
+ssh_userauth_try_publickey
+ssh_userauth_publickey
+ssh_userauth_agent
+ssh_userauth_publickey_auto
+ssh_userauth_password
+ssh_userauth_kbdint
+ssh_userauth_kbdint_getinstruction
+ssh_userauth_kbdint_getname
+ssh_userauth_kbdint_getnprompts
+ssh_userauth_kbdint_getprompt
+ssh_userauth_kbdint_getnanswers
+ssh_userauth_kbdint_getanswer
+ssh_userauth_kbdint_setanswer
+ssh_userauth_gssapi
+ssh_version
+ssh_write_knownhost
+ssh_dump_knownhost
+ssh_string_burn
+ssh_string_copy
+ssh_string_data
+ssh_string_fill
+ssh_string_free
+ssh_string_from_char
+ssh_string_len
+ssh_string_new
+ssh_string_get_char
+ssh_string_to_char
+ssh_string_free_char
+ssh_getpass
+ssh_event_new
+ssh_event_add_fd
+ssh_event_add_session
+ssh_event_add_connector
+ssh_event_dopoll
+ssh_event_remove_fd
+ssh_event_remove_session
+ssh_event_remove_connector
+ssh_event_free
+ssh_get_clientbanner
+ssh_get_serverbanner
+ssh_get_kex_algo
+ssh_get_cipher_in
+ssh_get_cipher_out
+ssh_get_hmac_in
+ssh_get_hmac_out
+ssh_buffer_new
+ssh_buffer_free
+ssh_buffer_reinit
+ssh_buffer_add_data
+ssh_buffer_get_data
+ssh_buffer_get
+ssh_buffer_get_len
+ssh_bind_new
+ssh_bind_options_set
+ssh_bind_listen
+ssh_bind_set_callbacks
+ssh_bind_set_blocking
+ssh_bind_get_fd
+ssh_bind_set_fd
+ssh_bind_fd_toaccept
+ssh_bind_accept
+ssh_bind_accept_fd
+ssh_gssapi_get_creds
+ssh_handle_key_exchange
+ssh_server_init_kex
+ssh_bind_free
+ssh_set_auth_methods
+ssh_message_reply_default
+ssh_message_auth_user
+ssh_message_auth_password
+ssh_message_auth_pubkey
+ssh_message_auth_kbdint_is_response
+ssh_message_auth_publickey_state
+ssh_message_auth_reply_success
+ssh_message_auth_reply_pk_ok
+ssh_message_auth_reply_pk_ok_simple
+ssh_message_auth_set_methods
+ssh_message_auth_interactive_request
+ssh_message_service_reply_success
+ssh_message_service_service
+ssh_message_global_request_reply_success
+ssh_set_message_callback
+ssh_execute_message_callbacks
+ssh_message_channel_request_open_originator
+ssh_message_channel_request_open_originator_port
+ssh_message_channel_request_open_destination
+ssh_message_channel_request_open_destination_port
+ssh_message_channel_request_channel
+ssh_message_channel_request_pty_term
+ssh_message_channel_request_pty_width
+ssh_message_channel_request_pty_height
+ssh_message_channel_request_pty_pxwidth
+ssh_message_channel_request_pty_pxheight
+ssh_message_channel_request_env_name
+ssh_message_channel_request_env_value
+ssh_message_channel_request_command
+ssh_message_channel_request_subsystem
+ssh_message_channel_request_x11_single_connection
+ssh_message_channel_request_x11_auth_protocol
+ssh_message_channel_request_x11_auth_cookie
+ssh_message_channel_request_x11_screen_number
+ssh_message_global_request_address
+ssh_message_global_request_port
+ssh_channel_open_reverse_forward
+ssh_channel_request_send_exit_status
+ssh_channel_request_send_exit_signal
+ssh_send_keepalive
+ssh_accept
+channel_write_stderr
+sftp_new
+sftp_new_channel
+sftp_free
+sftp_init
+sftp_get_error
+sftp_extensions_get_count
+sftp_extensions_get_name
+sftp_extensions_get_data
+sftp_extension_supported
+sftp_opendir
+sftp_readdir
+sftp_dir_eof
+sftp_stat
+sftp_lstat
+sftp_fstat
+sftp_attributes_free
+sftp_closedir
+sftp_close
+sftp_open
+sftp_file_set_nonblocking
+sftp_file_set_blocking
+sftp_read
+sftp_async_read_begin
+sftp_async_read
+sftp_write
+sftp_seek
+sftp_seek64
+sftp_tell
+sftp_tell64
+sftp_rewind
+sftp_unlink
+sftp_rmdir
+sftp_mkdir
+sftp_rename
+sftp_setstat
+sftp_chown
+sftp_chmod
+sftp_utimes
+sftp_symlink
+sftp_readlink
+sftp_statvfs
+sftp_fstatvfs
+sftp_statvfs_free
+sftp_fsync
+sftp_canonicalize_path
+sftp_server_version
+sftp_server_new
+sftp_server_init
+sftp_get_client_message
+sftp_client_message_free
+sftp_client_message_get_type
+sftp_client_message_get_filename
+sftp_client_message_set_filename
+sftp_client_message_get_data
+sftp_client_message_get_flags
+sftp_send_client_message
+sftp_reply_name
+sftp_reply_handle
+sftp_handle_alloc
+sftp_reply_attr
+sftp_handle
+sftp_reply_status
+sftp_reply_names_add
+sftp_reply_names
+sftp_reply_data
+sftp_handle_remove \ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e5a9353..e5746b1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,3 @@
-project(libssh-library C)
-
set(LIBSSH_PUBLIC_INCLUDE_DIRS
${libssh_SOURCE_DIR}/include
CACHE INTERNAL "libssh public include directories"
@@ -39,6 +37,17 @@ if (OPENSSL_CRYPTO_LIBRARY)
)
endif (OPENSSL_CRYPTO_LIBRARY)
+if (MBEDTLS_CRYPTO_LIBRARY)
+ set(LIBSSH_PRIVATE_INCLUDE_DIRS
+ ${LIBSSH_PRIVATE_INCLUDE_DIRS}
+ ${MBEDTLS_INCLUDE_DIR}
+ )
+ set(LIBSSH_LINK_LIBRARIES
+ ${LIBSSH_LINK_LIBRARIES}
+ ${MBEDTLS_CRYPTO_LIBRARY}
+ )
+endif (MBEDTLS_CRYPTO_LIBRARY)
+
if (GCRYPT_LIBRARY)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
@@ -124,6 +133,7 @@ set(libssh_SRCS
init.c
kex.c
known_hosts.c
+ knownhosts.c
legacy.c
log.c
match.c
@@ -146,23 +156,56 @@ set(libssh_SRCS
wrapper.c
external/bcrypt_pbkdf.c
external/blowfish.c
+ external/chacha.c
external/ed25519.c
external/fe25519.c
external/ge25519.c
+ external/poly1305.c
external/sc25519.c
+ chachapoly.c
)
+if (CMAKE_USE_PTHREADS_INIT)
+ set(libssh_SRCS
+ ${libssh_SRCS}
+ threads/noop.c
+ threads/pthread.c
+ )
+elseif (CMAKE_USE_WIN32_THREADS_INIT)
+ set(libssh_SRCS
+ ${libssh_SRCS}
+ threads/noop.c
+ threads/winlocks.c
+ )
+else()
+ set(libssh_SRCS
+ ${libssh_SRCS}
+ threads/noop.c
+ )
+endif()
+
if (WITH_GCRYPT)
set(libssh_SRCS
${libssh_SRCS}
+ threads/libgcrypt.c
libgcrypt.c
gcrypt_missing.c
pki_gcrypt.c
ecdh_gcrypt.c
)
+elseif (WITH_MBEDTLS)
+ set(libssh_SRCS
+ ${libssh_SRCS}
+ threads/mbedtls.c
+ libmbedcrypto.c
+ mbedcrypto_missing.c
+ pki_mbedcrypto.c
+ ecdh_mbedcrypto.c
+ )
else (WITH_GCRYPT)
set(libssh_SRCS
${libssh_SRCS}
+ threads/libcrypto.c
pki_crypto.c
ecdh_crypto.c
libcrypto.c
@@ -186,17 +229,6 @@ if (WITH_SFTP)
endif (WITH_SERVER)
endif (WITH_SFTP)
-if (WITH_SSH1)
- set(libssh_SRCS
- ${libssh_SRCS}
- auth1.c
- channels1.c
- crc32.c
- kex1.c
- packet1.c
- )
-endif (WITH_SSH1)
-
if (WITH_SERVER)
set(libssh_SRCS
${libssh_SRCS}
@@ -231,10 +263,52 @@ include_directories(
${LIBSSH_PRIVATE_INCLUDE_DIRS}
)
+# Set the path to the default map file
+set(MAP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.map")
+
+if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
+ # Get the list of header files
+ get_file_list("dev_header_list"
+ DIRECTORIES "${LIBSSH_PUBLIC_INCLUDE_DIRS}/libssh"
+ FILES_PATTERNS "*.h")
+
+ # Extract the symbols marked as "LIBSSH_API" from the header files
+ extract_symbols("${PROJECT_NAME}_dev.symbols"
+ HEADERS_LIST_FILE "dev_header_list"
+ FILTER_PATTERN "LIBSSH_API")
+
+ if (WITH_ABI_BREAK)
+ set(ALLOW_ABI_BREAK "BREAK_ABI")
+ endif()
+
+ # Generate the symbol version map file
+ generate_map_file("${PROJECT_NAME}_dev.map"
+ SYMBOLS "${PROJECT_NAME}_dev.symbols"
+ RELEASE_NAME_VERSION ${PROJECT_NAME}_AFTER_${LIBRARY_VERSION}
+ CURRENT_MAP ${MAP_PATH}
+ ${ALLOW_ABI_BREAK})
+
+ set(libssh_SRCS
+ ${libssh_SRCS}
+ ${PROJECT_NAME}_dev.map
+ )
+endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
+
add_library(${LIBSSH_SHARED_LIBRARY} SHARED ${libssh_SRCS})
target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
+if (WITH_SYMBOL_VERSIONING)
+ if (ABIMAP_FOUND)
+ # Change path to devel map file
+ set(MAP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_dev.map")
+ endif (ABIMAP_FOUND)
+
+ set_target_properties(${LIBSSH_SHARED_LIBRARY}
+ PROPERTIES LINK_FLAGS
+ "-Wl,--version-script,\"${MAP_PATH}\"")
+endif (WITH_SYMBOL_VERSIONING)
+
set_target_properties(
${LIBSSH_SHARED_LIBRARY}
PROPERTIES
@@ -307,6 +381,3 @@ if (WITH_STATIC_LIB)
endif (WITH_STATIC_LIB)
message(STATUS "Threads_FOUND=${Threads_FOUND}")
-if (Threads_FOUND)
- add_subdirectory(threads)
-endif (Threads_FOUND)
diff --git a/src/agent.c b/src/agent.c
index 0b145ff..114dadf 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -331,30 +331,16 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
ssh_buffer request = NULL;
ssh_buffer reply = NULL;
unsigned int type = 0;
- unsigned int c1 = 0, c2 = 0;
uint8_t buf[4] = {0};
int rc;
- switch (session->version) {
- case 1:
- c1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
- c2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
- break;
- case 2:
- c1 = SSH2_AGENTC_REQUEST_IDENTITIES;
- c2 = SSH2_AGENT_IDENTITIES_ANSWER;
- break;
- default:
- return 0;
- }
-
/* send message to the agent requesting the list of identities */
request = ssh_buffer_new();
if (request == NULL) {
ssh_set_error_oom(session);
return -1;
}
- if (ssh_buffer_add_u8(request, c1) < 0) {
+ if (ssh_buffer_add_u8(request, SSH2_AGENTC_REQUEST_IDENTITIES) < 0) {
ssh_set_error_oom(session);
ssh_buffer_free(request);
return -1;
@@ -388,12 +374,12 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
SSH_LOG(SSH_LOG_WARN,
"Answer type: %d, expected answer: %d",
- type, c2);
+ type, SSH2_AGENT_IDENTITIES_ANSWER);
if (agent_failed(type)) {
ssh_buffer_free(reply);
return 0;
- } else if (type != c2) {
+ } else if (type != SSH2_AGENT_IDENTITIES_ANSWER) {
ssh_set_error(session, SSH_FATAL,
"Bad authentication reply message type: %u", type);
ssh_buffer_free(reply);
@@ -442,47 +428,39 @@ ssh_key ssh_agent_get_next_ident(struct ssh_session_struct *session,
return NULL;
}
- switch(session->version) {
- case 1:
- return NULL;
- case 2:
- /* get the blob */
- blob = ssh_buffer_get_ssh_string(session->agent->ident);
- if (blob == NULL) {
- return NULL;
- }
-
- /* get the comment */
- tmp = ssh_buffer_get_ssh_string(session->agent->ident);
- if (tmp == NULL) {
- ssh_string_free(blob);
-
- return NULL;
- }
-
- if (comment) {
- *comment = ssh_string_to_char(tmp);
- } else {
- ssh_string_free(blob);
- ssh_string_free(tmp);
-
- return NULL;
- }
- ssh_string_free(tmp);
-
- /* get key from blob */
- rc = ssh_pki_import_pubkey_blob(blob, &key);
- if (rc == SSH_ERROR) {
- /* Try again as a cert. */
- rc = ssh_pki_import_cert_blob(blob, &key);
- }
- ssh_string_free(blob);
- if (rc == SSH_ERROR) {
- return NULL;
- }
- break;
- default:
- return NULL;
+ /* get the blob */
+ blob = ssh_buffer_get_ssh_string(session->agent->ident);
+ if (blob == NULL) {
+ return NULL;
+ }
+
+ /* get the comment */
+ tmp = ssh_buffer_get_ssh_string(session->agent->ident);
+ if (tmp == NULL) {
+ ssh_string_free(blob);
+
+ return NULL;
+ }
+
+ if (comment) {
+ *comment = ssh_string_to_char(tmp);
+ } else {
+ ssh_string_free(blob);
+ ssh_string_free(tmp);
+
+ return NULL;
+ }
+ ssh_string_free(tmp);
+
+ /* get key from blob */
+ rc = ssh_pki_import_pubkey_blob(blob, &key);
+ if (rc == SSH_ERROR) {
+ /* Try again as a cert. */
+ rc = ssh_pki_import_cert_blob(blob, &key);
+ }
+ ssh_string_free(blob);
+ if (rc == SSH_ERROR) {
+ return NULL;
}
return key;
@@ -536,6 +514,21 @@ ssh_string ssh_agent_sign_data(ssh_session session,
return NULL;
}
+ /*
+ * make sure it already can contain all the expected content:
+ * - 1 x uint8_t
+ * - 2 x uint32_t
+ * - 1 x ssh_string (uint8_t + data)
+ */
+ rc = ssh_buffer_allocate_size(request,
+ sizeof(uint8_t) * 2 +
+ sizeof(uint32_t) * 2 +
+ ssh_string_len(key_blob));
+ if (rc < 0) {
+ ssh_buffer_free(request);
+ return NULL;
+ }
+
/* adds len + blob */
rc = ssh_buffer_add_ssh_string(request, key_blob);
ssh_string_free(key_blob);
@@ -603,5 +596,3 @@ ssh_string ssh_agent_sign_data(ssh_session session,
}
#endif /* _WIN32 */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/auth.c b/src/auth.c
index 8a686dc..bd2fecc 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -22,9 +22,9 @@
* MA 02111-1307, USA.
*/
-#include <stdlib.h>
+#include "config.h"
+
#include <stdio.h>
-#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
@@ -77,18 +77,18 @@ static int ssh_userauth_request_service(ssh_session session) {
return rc;
}
-static int ssh_auth_response_termination(void *user){
- ssh_session session=(ssh_session)user;
- switch(session->auth_state){
- case SSH_AUTH_STATE_NONE:
- case SSH_AUTH_STATE_KBDINT_SENT:
- case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
- case SSH_AUTH_STATE_GSSAPI_TOKEN:
- case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
- return 0;
- default:
- return 1;
- }
+static int ssh_auth_response_termination(void *user) {
+ ssh_session session = (ssh_session)user;
+ switch (session->auth_state) {
+ case SSH_AUTH_STATE_NONE:
+ case SSH_AUTH_STATE_KBDINT_SENT:
+ case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
+ case SSH_AUTH_STATE_GSSAPI_TOKEN:
+ case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
+ return 0;
+ default:
+ return 1;
+ }
}
/**
@@ -110,10 +110,10 @@ static int ssh_userauth_get_response(ssh_session session) {
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
ssh_auth_response_termination, session);
if (rc == SSH_ERROR) {
- return SSH_AUTH_ERROR;
+ return SSH_AUTH_ERROR;
}
- if (!ssh_auth_response_termination(session)){
- return SSH_AUTH_AGAIN;
+ if (!ssh_auth_response_termination(session)) {
+ return SSH_AUTH_AGAIN;
}
switch(session->auth_state) {
@@ -133,7 +133,7 @@ static int ssh_userauth_get_response(ssh_session session) {
case SSH_AUTH_STATE_SUCCESS:
rc = SSH_AUTH_SUCCESS;
break;
- case SSH_AUTH_STATE_KBDINT_SENT:
+ case SSH_AUTH_STATE_KBDINT_SENT:
case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
case SSH_AUTH_STATE_GSSAPI_TOKEN:
case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
@@ -153,24 +153,24 @@ static int ssh_userauth_get_response(ssh_session session) {
*
* This banner should be shown to user prior to authentication
*/
-SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){
- ssh_string banner;
- (void)type;
- (void)user;
+SSH_PACKET_CALLBACK(ssh_packet_userauth_banner) {
+ ssh_string banner;
+ (void)type;
+ (void)user;
- banner = ssh_buffer_get_ssh_string(packet);
- if (banner == NULL) {
- SSH_LOG(SSH_LOG_WARN,
- "Invalid SSH_USERAUTH_BANNER packet");
- } else {
- SSH_LOG(SSH_LOG_DEBUG,
- "Received SSH_USERAUTH_BANNER packet");
- if(session->banner != NULL)
- ssh_string_free(session->banner);
- session->banner = banner;
- }
+ banner = ssh_buffer_get_ssh_string(packet);
+ if (banner == NULL) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Invalid SSH_USERAUTH_BANNER packet");
+ } else {
+ SSH_LOG(SSH_LOG_DEBUG,
+ "Received SSH_USERAUTH_BANNER packet");
+ if (session->banner != NULL)
+ ssh_string_free(session->banner);
+ session->banner = banner;
+ }
- return SSH_PACKET_USED;
+ return SSH_PACKET_USED;
}
/**
@@ -180,57 +180,57 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){
*
* This handles the complete or partial authentication failure.
*/
-SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){
- char *auth_methods = NULL;
- uint8_t partial = 0;
- int rc;
- (void) type;
- (void) user;
-
- rc = ssh_buffer_unpack(packet, "sb", &auth_methods, &partial);
- if (rc != SSH_OK) {
- ssh_set_error(session, SSH_FATAL,
- "Invalid SSH_MSG_USERAUTH_FAILURE message");
- session->auth_state=SSH_AUTH_STATE_ERROR;
- goto end;
- }
+SSH_PACKET_CALLBACK(ssh_packet_userauth_failure) {
+ char *auth_methods = NULL;
+ uint8_t partial = 0;
+ int rc;
+ (void) type;
+ (void) user;
- if (partial) {
- session->auth_state=SSH_AUTH_STATE_PARTIAL;
- SSH_LOG(SSH_LOG_INFO,
- "Partial success. Authentication that can continue: %s",
- auth_methods);
- } else {
- session->auth_state=SSH_AUTH_STATE_FAILED;
- SSH_LOG(SSH_LOG_INFO,
- "Access denied. Authentication that can continue: %s",
- auth_methods);
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Access denied. Authentication that can continue: %s",
- auth_methods);
+ rc = ssh_buffer_unpack(packet, "sb", &auth_methods, &partial);
+ if (rc != SSH_OK) {
+ ssh_set_error(session, SSH_FATAL,
+ "Invalid SSH_MSG_USERAUTH_FAILURE message");
+ session->auth_state=SSH_AUTH_STATE_ERROR;
+ goto end;
+ }
- }
- session->auth_methods = 0;
- if (strstr(auth_methods, "password") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_PASSWORD;
- }
- if (strstr(auth_methods, "keyboard-interactive") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_INTERACTIVE;
- }
- if (strstr(auth_methods, "publickey") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_PUBLICKEY;
- }
- if (strstr(auth_methods, "hostbased") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED;
- }
- if (strstr(auth_methods, "gssapi-with-mic") != NULL) {
- session->auth_methods |= SSH_AUTH_METHOD_GSSAPI_MIC;
- }
+ if (partial) {
+ session->auth_state=SSH_AUTH_STATE_PARTIAL;
+ SSH_LOG(SSH_LOG_INFO,
+ "Partial success. Authentication that can continue: %s",
+ auth_methods);
+ } else {
+ session->auth_state=SSH_AUTH_STATE_FAILED;
+ SSH_LOG(SSH_LOG_INFO,
+ "Access denied. Authentication that can continue: %s",
+ auth_methods);
+ ssh_set_error(session, SSH_REQUEST_DENIED,
+ "Access denied. Authentication that can continue: %s",
+ auth_methods);
+
+ }
+ session->auth_methods = 0;
+ if (strstr(auth_methods, "password") != NULL) {
+ session->auth_methods |= SSH_AUTH_METHOD_PASSWORD;
+ }
+ if (strstr(auth_methods, "keyboard-interactive") != NULL) {
+ session->auth_methods |= SSH_AUTH_METHOD_INTERACTIVE;
+ }
+ if (strstr(auth_methods, "publickey") != NULL) {
+ session->auth_methods |= SSH_AUTH_METHOD_PUBLICKEY;
+ }
+ if (strstr(auth_methods, "hostbased") != NULL) {
+ session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED;
+ }
+ if (strstr(auth_methods, "gssapi-with-mic") != NULL) {
+ session->auth_methods |= SSH_AUTH_METHOD_GSSAPI_MIC;
+ }
end:
- SAFE_FREE(auth_methods);
+ SAFE_FREE(auth_methods);
- return SSH_PACKET_USED;
+ return SSH_PACKET_USED;
}
/**
@@ -240,7 +240,7 @@ end:
*
* It is also used to communicate the new to the upper levels.
*/
-SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
+SSH_PACKET_CALLBACK(ssh_packet_userauth_success) {
(void)packet;
(void)type;
(void)user;
@@ -248,17 +248,17 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
SSH_LOG(SSH_LOG_DEBUG, "Authentication successful");
SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_SUCCESS");
- session->auth_state=SSH_AUTH_STATE_SUCCESS;
- session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
+ session->auth_state = SSH_AUTH_STATE_SUCCESS;
+ session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
- if(session->current_crypto && session->current_crypto->delayed_compress_out){
+ if (session->current_crypto && session->current_crypto->delayed_compress_out) {
SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT");
- session->current_crypto->do_compress_out=1;
+ session->current_crypto->do_compress_out = 1;
}
- if(session->current_crypto && session->current_crypto->delayed_compress_in){
+ if (session->current_crypto && session->current_crypto->delayed_compress_in) {
SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN");
- session->current_crypto->do_compress_in=1;
+ session->current_crypto->do_compress_in = 1;
}
return SSH_PACKET_USED;
@@ -272,24 +272,24 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
* Since the two types of packets share the same code, additional work is done
* to understand if we are in a public key or keyboard-interactive context.
*/
-SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){
- int rc;
+SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok) {
+ int rc;
SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
- if(session->auth_state==SSH_AUTH_STATE_KBDINT_SENT){
+ if (session->auth_state==SSH_AUTH_STATE_KBDINT_SENT) {
/* Assuming we are in keyboard-interactive context */
SSH_LOG(SSH_LOG_TRACE,
"keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST");
- rc=ssh_packet_userauth_info_request(session,type,packet,user);
+ rc = ssh_packet_userauth_info_request(session,type,packet,user);
#ifdef WITH_GSSAPI
- } else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT){
+ } else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) {
rc = ssh_packet_userauth_gssapi_response(session, type, packet, user);
#endif
} else {
- session->auth_state=SSH_AUTH_STATE_PK_OK;
+ session->auth_state = SSH_AUTH_STATE_PK_OK;
SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
- rc=SSH_PACKET_USED;
+ rc = SSH_PACKET_USED;
}
return rc;
@@ -323,12 +323,6 @@ int ssh_userauth_list(ssh_session session, const char *username)
return 0;
}
-#ifdef WITH_SSH1
- if(session->version == 1) {
- return SSH_AUTH_METHOD_PASSWORD;
- }
-#endif
-
return session->auth_methods;
}
@@ -354,20 +348,15 @@ int ssh_userauth_list(ssh_session session, const char *username)
int ssh_userauth_none(ssh_session session, const char *username) {
int rc;
-#ifdef WITH_SSH1
- if (session->version == 1) {
- return ssh_userauth1_none(session, username);
- }
-#endif
-
- switch(session->pending_call_state){
+ switch(session->pending_call_state) {
case SSH_PENDING_CALL_NONE:
break;
case SSH_PENDING_CALL_AUTH_NONE:
goto pending;
default:
ssh_set_error(session, SSH_FATAL,
- "Wrong state during pending SSH call");
+ "Wrong state (%d) during pending SSH call",
+ session->pending_call_state);
return SSH_AUTH_ERROR;
}
@@ -454,12 +443,6 @@ int ssh_userauth_try_publickey(ssh_session session,
return SSH_AUTH_ERROR;
}
-#ifdef WITH_SSH1
- if (session->version == 1) {
- return SSH_AUTH_DENIED;
- }
-#endif
-
switch(session->pending_call_state) {
case SSH_PENDING_CALL_NONE:
break;
@@ -468,7 +451,8 @@ int ssh_userauth_try_publickey(ssh_session session,
default:
ssh_set_error(session,
SSH_FATAL,
- "Wrong state during pending SSH call");
+ "Wrong state (%d) during pending SSH call",
+ session->pending_call_state);
return SSH_ERROR;
}
@@ -564,12 +548,6 @@ int ssh_userauth_publickey(ssh_session session,
return SSH_AUTH_ERROR;
}
-#ifdef WITH_SSH1
- if (session->version == 1) {
- return SSH_AUTH_DENIED;
- }
-#endif
-
switch(session->pending_call_state) {
case SSH_PENDING_CALL_NONE:
break;
@@ -707,6 +685,7 @@ static int ssh_userauth_agent_publickey(ssh_session session,
rc = ssh_buffer_add_ssh_string(session->out_buffer, str);
ssh_string_free(str);
+ str = NULL;
if (rc < 0) {
goto fail;
}
@@ -748,6 +727,7 @@ struct ssh_agent_state_struct {
/* Internal function */
void ssh_agent_state_free(void *data) {
struct ssh_agent_state_struct *state = data;
+
if (state) {
ssh_string_free_char(state->comment);
ssh_key_free(state->pubkey);
@@ -781,6 +761,7 @@ int ssh_userauth_agent(ssh_session session,
const char *username) {
int rc = SSH_AUTH_ERROR;
struct ssh_agent_state_struct *state;
+
if (session == NULL) {
return SSH_AUTH_ERROR;
}
@@ -788,30 +769,33 @@ int ssh_userauth_agent(ssh_session session,
if (!ssh_agent_is_running(session)) {
return SSH_AUTH_DENIED;
}
- if (!session->agent_state){
+
+ if (!session->agent_state) {
session->agent_state = malloc(sizeof(struct ssh_agent_state_struct));
- if (!session->agent_state){
+ if (!session->agent_state) {
ssh_set_error_oom(session);
return SSH_AUTH_ERROR;
}
ZERO_STRUCTP(session->agent_state);
session->agent_state->state=SSH_AGENT_STATE_NONE;
}
+
state = session->agent_state;
- if (state->pubkey == NULL)
+ if (state->pubkey == NULL) {
state->pubkey = ssh_agent_get_first_ident(session, &state->comment);
+ }
if (state->pubkey == NULL) {
return SSH_AUTH_DENIED;
}
while (state->pubkey != NULL) {
- if(state->state == SSH_AGENT_STATE_NONE){
+ if (state->state == SSH_AGENT_STATE_NONE) {
SSH_LOG(SSH_LOG_DEBUG,
"Trying identity %s", state->comment);
}
- if(state->state == SSH_AGENT_STATE_NONE ||
- state->state == SSH_AGENT_STATE_PUBKEY){
+ if (state->state == SSH_AGENT_STATE_NONE ||
+ state->state == SSH_AGENT_STATE_PUBKEY) {
rc = ssh_userauth_try_publickey(session, username, state->pubkey);
if (rc == SSH_AUTH_ERROR) {
ssh_agent_state_free (state);
@@ -835,13 +819,13 @@ int ssh_userauth_agent(ssh_session session,
"Public key of %s accepted by server", state->comment);
state->state = SSH_AGENT_STATE_AUTH;
}
- if (state->state == SSH_AGENT_STATE_AUTH){
+ if (state->state == SSH_AGENT_STATE_AUTH) {
rc = ssh_userauth_agent_publickey(session, username, state->pubkey);
if (rc == SSH_AUTH_AGAIN)
return rc;
ssh_string_free_char(state->comment);
state->comment = NULL;
- if (rc == SSH_AUTH_ERROR) {
+ if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_PARTIAL) {
ssh_agent_state_free (session->agent_state);
session->agent_state = NULL;
return rc;
@@ -866,7 +850,7 @@ int ssh_userauth_agent(ssh_session session,
#endif
enum ssh_auth_auto_state_e {
- SSH_AUTH_AUTO_STATE_NONE=0,
+ SSH_AUTH_AUTO_STATE_NONE = 0,
SSH_AUTH_AUTO_STATE_PUBKEY,
SSH_AUTH_AUTO_STATE_KEY_IMPORTED,
SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED
@@ -920,15 +904,18 @@ int ssh_userauth_publickey_auto(ssh_session session,
if (session == NULL) {
return SSH_AUTH_ERROR;
}
-
+ if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
+ session->auth_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
+ return SSH_AUTH_DENIED;
+ }
if (session->common.callbacks) {
auth_fn = session->common.callbacks->auth_function;
auth_data = session->common.callbacks->userdata;
}
- if (!session->auth_auto_state){
+ if (!session->auth_auto_state) {
session->auth_auto_state =
malloc(sizeof(struct ssh_auth_auto_state_struct));
- if (!session->auth_auto_state){
+ if (!session->auth_auto_state) {
ssh_set_error_oom(session);
return SSH_AUTH_ERROR;
}
@@ -939,7 +926,9 @@ int ssh_userauth_publickey_auto(ssh_session session,
#ifndef _WIN32
/* Try authentication with ssh-agent first */
rc = ssh_userauth_agent(session, username);
- if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_AGAIN) {
+ if (rc == SSH_AUTH_SUCCESS ||
+ rc == SSH_AUTH_PARTIAL ||
+ rc == SSH_AUTH_AGAIN ) {
return rc;
}
#endif
@@ -949,10 +938,10 @@ int ssh_userauth_publickey_auto(ssh_session session,
state->it = ssh_list_get_iterator(session->opts.identity);
}
- while (state->it != NULL){
+ while (state->it != NULL) {
const char *privkey_file = state->it->data;
char pubkey_file[1024] = {0};
- if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY){
+ if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY) {
SSH_LOG(SSH_LOG_DEBUG,
"Trying to authenticate with %s", privkey_file);
state->privkey = NULL;
@@ -1006,7 +995,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
}
state->state = SSH_AUTH_AUTO_STATE_KEY_IMPORTED;
}
- if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED){
+ if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED) {
rc = ssh_userauth_try_publickey(session, username, state->pubkey);
if (rc == SSH_AUTH_ERROR) {
SSH_LOG(SSH_LOG_WARN,
@@ -1016,7 +1005,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
ssh_key_free(state->pubkey);
SAFE_FREE(session->auth_auto_state);
return rc;
- } else if (rc == SSH_AUTH_AGAIN){
+ } else if (rc == SSH_AUTH_AGAIN) {
return rc;
} else if (rc != SSH_AUTH_SUCCESS) {
SSH_LOG(SSH_LOG_DEBUG,
@@ -1032,7 +1021,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
}
state->state = SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED;
}
- if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED){
+ if (state->state == SSH_AUTH_AUTO_STATE_PUBKEY_ACCEPTED) {
/* Public key has been accepted by the server */
if (state->privkey == NULL) {
rc = ssh_pki_import_privkey_file(privkey_file,
@@ -1053,11 +1042,11 @@ int ssh_userauth_publickey_auto(ssh_session session,
} else if (rc == SSH_EOF) {
/* If the file doesn't exist, continue */
ssh_key_free(state->pubkey);
- state->pubkey=NULL;
+ state->pubkey = NULL;
SSH_LOG(SSH_LOG_INFO,
"Private key %s doesn't exist.",
privkey_file);
- state->it=state->it->next;
+ state->it = state->it->next;
state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
continue;
}
@@ -1075,14 +1064,14 @@ int ssh_userauth_publickey_auto(ssh_session session,
}
return rc;
}
- if (rc == SSH_AUTH_AGAIN){
+ if (rc == SSH_AUTH_AGAIN) {
return rc;
}
SSH_LOG(SSH_LOG_WARN,
"The server accepted the public key but refused the signature");
- state->it=state->it->next;
- state->state=SSH_AUTH_AUTO_STATE_PUBKEY;
+ state->it = state->it->next;
+ state->state = SSH_AUTH_AUTO_STATE_PUBKEY;
/* continue */
}
}
@@ -1129,13 +1118,6 @@ int ssh_userauth_password(ssh_session session,
const char *password) {
int rc;
-#ifdef WITH_SSH1
- if (session->version == 1) {
- rc = ssh_userauth1_password(session, username, password);
- return rc;
- }
-#endif
-
switch(session->pending_call_state) {
case SSH_PENDING_CALL_NONE:
break;
@@ -1144,7 +1126,8 @@ int ssh_userauth_password(ssh_session session,
default:
ssh_set_error(session,
SSH_FATAL,
- "Wrong state during pending SSH call");
+ "Wrong state (%d) during pending SSH call",
+ session->pending_call_state);
return SSH_ERROR;
}
@@ -1245,7 +1228,7 @@ void ssh_kbdint_free(ssh_kbdint kbd) {
n = kbd->nprompts;
if (kbd->prompts) {
for (i = 0; i < n; i++) {
- BURN_STRING(kbd->prompts[i]);
+ explicit_bzero(kbd->prompts[i], strlen(kbd->prompts[i]));
SAFE_FREE(kbd->prompts[i]);
}
SAFE_FREE(kbd->prompts);
@@ -1254,7 +1237,7 @@ void ssh_kbdint_free(ssh_kbdint kbd) {
n = kbd->nanswers;
if (kbd->answers) {
for (i = 0; i < n; i++) {
- BURN_STRING(kbd->answers[i]);
+ explicit_bzero(kbd->answers[i], strlen(kbd->answers[i]));
SAFE_FREE(kbd->answers[i]);
}
SAFE_FREE(kbd->answers);
@@ -1277,7 +1260,7 @@ void ssh_kbdint_clean(ssh_kbdint kbd) {
n = kbd->nprompts;
if (kbd->prompts) {
for (i = 0; i < n; i++) {
- BURN_STRING(kbd->prompts[i]);
+ explicit_bzero(kbd->prompts[i], strlen(kbd->prompts[i]));
SAFE_FREE(kbd->prompts[i]);
}
SAFE_FREE(kbd->prompts);
@@ -1287,7 +1270,7 @@ void ssh_kbdint_clean(ssh_kbdint kbd) {
if (kbd->answers) {
for (i = 0; i < n; i++) {
- BURN_STRING(kbd->answers[i]);
+ explicit_bzero(kbd->answers[i], strlen(kbd->answers[i]));
SAFE_FREE(kbd->answers[i]);
}
SAFE_FREE(kbd->answers);
@@ -1305,15 +1288,19 @@ static int ssh_userauth_kbdint_init(ssh_session session,
const char *submethods)
{
int rc;
- if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT)
+
+ if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT) {
goto pending;
- if (session->pending_call_state != SSH_PENDING_CALL_NONE){
+ }
+ if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
ssh_set_error_invalid(session);
return SSH_ERROR;
}
+
rc = ssh_userauth_request_service(session);
- if (rc == SSH_AGAIN)
+ if (rc == SSH_AGAIN) {
return SSH_AUTH_AGAIN;
+ }
if (rc != SSH_OK) {
return SSH_AUTH_ERROR;
}
@@ -1371,7 +1358,7 @@ static int ssh_userauth_kbdint_send(ssh_session session)
int rc;
if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND)
goto pending;
- if (session->pending_call_state != SSH_PENDING_CALL_NONE){
+ if (session->pending_call_state != SSH_PENDING_CALL_NONE) {
ssh_set_error_invalid(session);
return SSH_ERROR;
}
@@ -1422,92 +1409,91 @@ fail:
* authentication state.
*/
SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) {
- ssh_string tmp = NULL;
- uint32_t nprompts;
- uint32_t i;
- int rc;
- (void)user;
- (void)type;
+ ssh_string tmp = NULL;
+ uint32_t nprompts;
+ uint32_t i;
+ int rc;
+ (void)user;
+ (void)type;
- if (session->kbdint == NULL) {
- session->kbdint = ssh_kbdint_new();
if (session->kbdint == NULL) {
- ssh_set_error_oom(session);
- return SSH_PACKET_USED;
+ session->kbdint = ssh_kbdint_new();
+ if (session->kbdint == NULL) {
+ ssh_set_error_oom(session);
+ return SSH_PACKET_USED;
+ }
+ } else {
+ ssh_kbdint_clean(session->kbdint);
}
- } else {
- ssh_kbdint_clean(session->kbdint);
- }
-
- rc = ssh_buffer_unpack(packet, "ssSd",
- &session->kbdint->name, /* name of the "asking" window shown to client */
- &session->kbdint->instruction,
- &tmp, /* to ignore */
- &nprompts
- );
-
- /* We don't care about tmp */
- ssh_string_free(tmp);
-
- if (rc != SSH_OK) {
- ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg");
- ssh_kbdint_free(session->kbdint);
- session->kbdint = NULL;
- return SSH_PACKET_USED;
- }
-
- SSH_LOG(SSH_LOG_DEBUG,
- "%d keyboard-interactive prompts", nprompts);
- if (nprompts > KBDINT_MAX_PROMPT) {
- ssh_set_error(session, SSH_FATAL,
- "Too much prompts requested by the server: %u (0x%.4x)",
- nprompts, nprompts);
- ssh_kbdint_free(session->kbdint);
- session->kbdint = NULL;
-
- return SSH_PACKET_USED;
- }
-
- session->kbdint->nprompts = nprompts;
- session->kbdint->nanswers = nprompts;
- session->kbdint->prompts = malloc(nprompts * sizeof(char *));
- if (session->kbdint->prompts == NULL) {
- session->kbdint->nprompts = 0;
- ssh_set_error_oom(session);
- ssh_kbdint_free(session->kbdint);
- session->kbdint = NULL;
- return SSH_PACKET_USED;
- }
- memset(session->kbdint->prompts, 0, nprompts * sizeof(char *));
-
- session->kbdint->echo = malloc(nprompts);
- if (session->kbdint->echo == NULL) {
- session->kbdint->nprompts = 0;
- ssh_set_error_oom(session);
- ssh_kbdint_free(session->kbdint);
- session->kbdint = NULL;
+ rc = ssh_buffer_unpack(packet, "ssSd",
+ &session->kbdint->name, /* name of the "asking" window shown to client */
+ &session->kbdint->instruction,
+ &tmp, /* to ignore */
+ &nprompts
+ );
- return SSH_PACKET_USED;
- }
- memset(session->kbdint->echo, 0, nprompts);
+ /* We don't care about tmp */
+ ssh_string_free(tmp);
- for (i = 0; i < nprompts; i++) {
- rc = ssh_buffer_unpack(packet, "sb",
- &session->kbdint->prompts[i],
- &session->kbdint->echo[i]);
- if (rc == SSH_ERROR) {
- ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet");
- ssh_kbdint_free(session->kbdint);
- session->kbdint = NULL;
+ if (rc != SSH_OK) {
+ ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg");
+ ssh_kbdint_free(session->kbdint);
+ session->kbdint = NULL;
+ return SSH_PACKET_USED;
+ }
- return SSH_PACKET_USED;
+ SSH_LOG(SSH_LOG_DEBUG,
+ "%d keyboard-interactive prompts", nprompts);
+ if (nprompts > KBDINT_MAX_PROMPT) {
+ ssh_set_error(session, SSH_FATAL,
+ "Too much prompts requested by the server: %u (0x%.4x)",
+ nprompts, nprompts);
+ ssh_kbdint_free(session->kbdint);
+ session->kbdint = NULL;
+
+ return SSH_PACKET_USED;
+ }
+
+ session->kbdint->nprompts = nprompts;
+ session->kbdint->nanswers = nprompts;
+ session->kbdint->prompts = calloc(nprompts, sizeof(char *));
+ if (session->kbdint->prompts == NULL) {
+ session->kbdint->nprompts = 0;
+ ssh_set_error_oom(session);
+ ssh_kbdint_free(session->kbdint);
+ session->kbdint = NULL;
+
+ return SSH_PACKET_USED;
+ }
+
+ session->kbdint->echo = malloc(nprompts);
+ if (session->kbdint->echo == NULL) {
+ session->kbdint->nprompts = 0;
+ ssh_set_error_oom(session);
+ ssh_kbdint_free(session->kbdint);
+ session->kbdint = NULL;
+
+ return SSH_PACKET_USED;
+ }
+ memset(session->kbdint->echo, 0, nprompts);
+
+ for (i = 0; i < nprompts; i++) {
+ rc = ssh_buffer_unpack(packet, "sb",
+ &session->kbdint->prompts[i],
+ &session->kbdint->echo[i]);
+ if (rc == SSH_ERROR) {
+ ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet");
+ ssh_kbdint_free(session->kbdint);
+ session->kbdint = NULL;
+
+ return SSH_PACKET_USED;
+ }
}
- }
- session->auth_state=SSH_AUTH_STATE_INFO;
+ session->auth_state=SSH_AUTH_STATE_INFO;
- return SSH_PACKET_USED;
+ return SSH_PACKET_USED;
}
/**
@@ -1545,11 +1531,6 @@ int ssh_userauth_kbdint(ssh_session session, const char *user,
return SSH_AUTH_ERROR;
}
-#ifdef WITH_SSH1
- if (session->version == 1) {
- return SSH_AUTH_DENIED;
- }
-#endif
if ((session->pending_call_state == SSH_PENDING_CALL_NONE && session->kbdint == NULL) ||
session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT)
rc = ssh_userauth_kbdint_init(session, user, submethods);
@@ -1586,13 +1567,14 @@ int ssh_userauth_kbdint(ssh_session session, const char *user,
* @returns The number of prompts.
*/
int ssh_userauth_kbdint_getnprompts(ssh_session session) {
- if(session==NULL)
- return SSH_ERROR;
- if(session->kbdint == NULL) {
- ssh_set_error_invalid(session);
- return SSH_ERROR;
- }
- return session->kbdint->nprompts;
+ if (session == NULL) {
+ return SSH_ERROR;
+ }
+ if (session->kbdint == NULL) {
+ ssh_set_error_invalid(session);
+ return SSH_ERROR;
+ }
+ return session->kbdint->nprompts;
}
/**
@@ -1607,13 +1589,14 @@ int ssh_userauth_kbdint_getnprompts(ssh_session session) {
* @returns The name of the message block. Do not free it.
*/
const char *ssh_userauth_kbdint_getname(ssh_session session) {
- if(session==NULL)
- return NULL;
- if(session->kbdint == NULL) {
- ssh_set_error_invalid(session);
- return NULL;
- }
- return session->kbdint->name;
+ if (session == NULL) {
+ return NULL;
+ }
+ if (session->kbdint == NULL) {
+ ssh_set_error_invalid(session);
+ return NULL;
+ }
+ return session->kbdint->name;
}
/**
@@ -1629,13 +1612,13 @@ const char *ssh_userauth_kbdint_getname(ssh_session session) {
*/
const char *ssh_userauth_kbdint_getinstruction(ssh_session session) {
- if(session==NULL)
- return NULL;
- if(session->kbdint == NULL) {
- ssh_set_error_invalid(session);
- return NULL;
- }
- return session->kbdint->instruction;
+ if (session == NULL)
+ return NULL;
+ if (session->kbdint == NULL) {
+ ssh_set_error_invalid(session);
+ return NULL;
+ }
+ return session->kbdint->instruction;
}
/**
@@ -1665,22 +1648,22 @@ const char *ssh_userauth_kbdint_getinstruction(ssh_session session) {
*/
const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i,
char *echo) {
- if(session==NULL)
- return NULL;
- if(session->kbdint == NULL) {
- ssh_set_error_invalid(session);
- return NULL;
- }
- if (i > session->kbdint->nprompts) {
- ssh_set_error_invalid(session);
- return NULL;
- }
+ if (session == NULL)
+ return NULL;
+ if (session->kbdint == NULL) {
+ ssh_set_error_invalid(session);
+ return NULL;
+ }
+ if (i > session->kbdint->nprompts) {
+ ssh_set_error_invalid(session);
+ return NULL;
+ }
- if (echo) {
- *echo = session->kbdint->echo[i];
- }
+ if (echo) {
+ *echo = session->kbdint->echo[i];
+ }
- return session->kbdint->prompts[i];
+ return session->kbdint->prompts[i];
}
#ifdef WITH_SERVER
@@ -1692,9 +1675,10 @@ const char *ssh_userauth_kbdint_getprompt(ssh_session session, unsigned int i,
* @returns The number of answers.
*/
int ssh_userauth_kbdint_getnanswers(ssh_session session) {
- if(session==NULL || session->kbdint == NULL)
- return SSH_ERROR;
- return session->kbdint->nanswers;
+ if (session == NULL || session->kbdint == NULL) {
+ return SSH_ERROR;
+ }
+ return session->kbdint->nanswers;
}
/**
@@ -1707,15 +1691,15 @@ int ssh_userauth_kbdint_getnanswers(ssh_session session) {
* @return 0 on success, < 0 on error.
*/
const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i) {
- if(session==NULL || session->kbdint == NULL
- || session->kbdint->answers == NULL) {
- return NULL;
- }
- if (i >= session->kbdint->nanswers) {
- return NULL;
- }
+ if (session == NULL || session->kbdint == NULL
+ || session->kbdint->answers == NULL) {
+ return NULL;
+ }
+ if (i >= session->kbdint->nanswers) {
+ return NULL;
+ }
- return session->kbdint->answers[i];
+ return session->kbdint->answers[i];
}
#endif
@@ -1739,35 +1723,36 @@ const char *ssh_userauth_kbdint_getanswer(ssh_session session, unsigned int i) {
*/
int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
const char *answer) {
- if (session == NULL)
- return -1;
- if (answer == NULL || session->kbdint == NULL ||
- i >= session->kbdint->nprompts) {
- ssh_set_error_invalid(session);
- return -1;
- }
+ if (session == NULL) {
+ return -1;
+ }
+ if (answer == NULL || session->kbdint == NULL ||
+ i >= session->kbdint->nprompts) {
+ ssh_set_error_invalid(session);
+ return -1;
+ }
- if (session->kbdint->answers == NULL) {
- session->kbdint->answers = malloc(sizeof(char*) * session->kbdint->nprompts);
if (session->kbdint->answers == NULL) {
- ssh_set_error_oom(session);
- return -1;
+ session->kbdint->answers = calloc(session->kbdint->nprompts, sizeof(char *));
+ if (session->kbdint->answers == NULL) {
+ ssh_set_error_oom(session);
+ return -1;
+ }
}
- memset(session->kbdint->answers, 0, sizeof(char *) * session->kbdint->nprompts);
- }
- if (session->kbdint->answers[i]) {
- BURN_STRING(session->kbdint->answers[i]);
- SAFE_FREE(session->kbdint->answers[i]);
- }
+ if (session->kbdint->answers[i]) {
+ explicit_bzero(session->kbdint->answers[i],
+ strlen(session->kbdint->answers[i]));
+ SAFE_FREE(session->kbdint->answers[i]);
+ }
- session->kbdint->answers[i] = strdup(answer);
- if (session->kbdint->answers[i] == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
+ session->kbdint->answers[i] = strdup(answer);
+ if (session->kbdint->answers[i] == NULL) {
+ ssh_set_error_oom(session);
+ return -1;
+ }
- return 0;
+ return 0;
}
/**
@@ -1784,48 +1769,47 @@ int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i,
* later.
*/
int ssh_userauth_gssapi(ssh_session session) {
- int rc = SSH_AUTH_DENIED;
+ int rc = SSH_AUTH_DENIED;
#ifdef WITH_GSSAPI
- switch(session->pending_call_state) {
- case SSH_PENDING_CALL_NONE:
- break;
- case SSH_PENDING_CALL_AUTH_GSSAPI_MIC:
- goto pending;
- default:
- ssh_set_error(session,
- SSH_FATAL,
- "Wrong state during pending SSH call");
- return SSH_ERROR;
- }
-
- rc = ssh_userauth_request_service(session);
- if (rc == SSH_AGAIN) {
- return SSH_AUTH_AGAIN;
- } else if (rc == SSH_ERROR) {
- return SSH_AUTH_ERROR;
- }
- SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi-with-mic");
- session->auth_state = SSH_AUTH_STATE_NONE;
- session->pending_call_state = SSH_PENDING_CALL_AUTH_GSSAPI_MIC;
- rc = ssh_gssapi_auth_mic(session);
-
- if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_DENIED) {
- session->auth_state = SSH_AUTH_STATE_NONE;
- session->pending_call_state = SSH_PENDING_CALL_NONE;
- return rc;
- }
+ switch(session->pending_call_state) {
+ case SSH_PENDING_CALL_NONE:
+ break;
+ case SSH_PENDING_CALL_AUTH_GSSAPI_MIC:
+ goto pending;
+ default:
+ ssh_set_error(session,
+ SSH_FATAL,
+ "Wrong state (%d) during pending SSH call",
+ session->pending_call_state);
+ return SSH_ERROR;
+ }
+
+ rc = ssh_userauth_request_service(session);
+ if (rc == SSH_AGAIN) {
+ return SSH_AUTH_AGAIN;
+ } else if (rc == SSH_ERROR) {
+ return SSH_AUTH_ERROR;
+ }
+ SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi-with-mic");
+ session->auth_state = SSH_AUTH_STATE_NONE;
+ session->pending_call_state = SSH_PENDING_CALL_AUTH_GSSAPI_MIC;
+ rc = ssh_gssapi_auth_mic(session);
+
+ if (rc == SSH_AUTH_ERROR || rc == SSH_AUTH_DENIED) {
+ session->auth_state = SSH_AUTH_STATE_NONE;
+ session->pending_call_state = SSH_PENDING_CALL_NONE;
+ return rc;
+ }
pending:
- rc = ssh_userauth_get_response(session);
- if (rc != SSH_AUTH_AGAIN) {
- session->pending_call_state = SSH_PENDING_CALL_NONE;
- }
+ rc = ssh_userauth_get_response(session);
+ if (rc != SSH_AUTH_AGAIN) {
+ session->pending_call_state = SSH_PENDING_CALL_NONE;
+ }
#else
(void) session; /* unused */
#endif
- return rc;
+ return rc;
}
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/auth1.c b/src/auth1.c
deleted file mode 100644
index a9fe58e..0000000
--- a/src/auth1.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * auth1.c - authentication with SSH-1 protocol
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2005-2008 by Aris Adamantiadis
- *
- * The SSH Library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at your
- * option) any later version.
- *
- * The SSH Library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the SSH Library; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "libssh/priv.h"
-#include "libssh/ssh1.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/session.h"
-#include "libssh/string.h"
-
-#ifdef WITH_SSH1
-
-static int ssh_auth_status_termination(void *s){
- ssh_session session=s;
- if(session->auth_state != SSH_AUTH_STATE_NONE ||
- session->session_state == SSH_SESSION_STATE_ERROR)
- return 1;
- return 0;
-}
-
-static int wait_auth1_status(ssh_session session) {
- /* wait for a packet */
- if (ssh_handle_packets_termination(session,SSH_TIMEOUT_USER,
- ssh_auth_status_termination, session) != SSH_OK){
-
- return SSH_AUTH_ERROR;
- }
- SSH_LOG(SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state);
-
- switch(session->auth_state) {
- case SSH_AUTH_STATE_SUCCESS:
- return SSH_AUTH_SUCCESS;
- case SSH_AUTH_STATE_FAILED:
- return SSH_AUTH_DENIED;
- default:
- return SSH_AUTH_AGAIN;
- }
- return SSH_AUTH_ERROR;
-}
-
-void ssh_auth1_handler(ssh_session session, uint8_t type){
- if(session->session_state != SSH_SESSION_STATE_AUTHENTICATING){
- ssh_set_error(session,SSH_FATAL,"SSH_SMSG_SUCCESS or FAILED received in wrong state");
- return;
- }
- if(type==SSH_SMSG_SUCCESS){
- session->auth_state=SSH_AUTH_STATE_SUCCESS;
- session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
- } else if(type==SSH_SMSG_FAILURE)
- session->auth_state=SSH_AUTH_STATE_FAILED;
-}
-
-static int send_username(ssh_session session, const char *username) {
- ssh_string user = NULL;
- int rc;
- /* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */
- if(session->auth_service_state == SSH_AUTH_SERVICE_USER_SENT) {
- if(session->auth_state == SSH_AUTH_STATE_FAILED)
- return SSH_AUTH_DENIED;
- if(session->auth_state == SSH_AUTH_STATE_SUCCESS)
- return SSH_AUTH_SUCCESS;
- return SSH_AUTH_ERROR;
- }
- if (session->auth_service_state == SSH_AUTH_SERVICE_SENT)
- goto pending;
- if (!username) {
- if(!(username = session->opts.username)) {
- if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
- session->auth_service_state = SSH_AUTH_SERVICE_DENIED;
- return SSH_ERROR;
- } else {
- username = session->opts.username;
- }
- }
- }
- user = ssh_string_from_char(username);
- if (user == NULL) {
- return SSH_AUTH_ERROR;
- }
-
- if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_USER) < 0) {
- ssh_string_free(user);
- return SSH_AUTH_ERROR;
- }
- if (ssh_buffer_add_ssh_string(session->out_buffer, user) < 0) {
- ssh_string_free(user);
- return SSH_AUTH_ERROR;
- }
- ssh_string_free(user);
- session->auth_state=SSH_AUTH_STATE_NONE;
- session->auth_service_state = SSH_AUTH_SERVICE_SENT;
- if (ssh_packet_send(session) == SSH_ERROR) {
- return SSH_AUTH_ERROR;
- }
- return SSH_AUTH_AGAIN;
-pending:
- rc = wait_auth1_status(session);
- switch (rc){
- case SSH_AUTH_SUCCESS:
- session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
- session->auth_state=SSH_AUTH_STATE_SUCCESS;
- ssh_set_error(session, SSH_NO_ERROR, "Authentication successful");
- return SSH_AUTH_SUCCESS;
- case SSH_AUTH_DENIED:
- session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
- ssh_set_error(session,SSH_REQUEST_DENIED,"Password authentication necessary for user %s",username);
- return SSH_AUTH_DENIED;
- case SSH_AUTH_AGAIN:
- return SSH_AUTH_AGAIN;
- default:
- session->auth_service_state = SSH_AUTH_SERVICE_NONE;
- session->auth_state=SSH_AUTH_STATE_ERROR;
- return SSH_AUTH_ERROR;
- }
-}
-
-/* use the "none" authentication question */
-int ssh_userauth1_none(ssh_session session, const char *username){
- return send_username(session, username);
-}
-
-/** \internal
- * \todo implement ssh1 public key
- */
-int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
- int type, ssh_string pubkey) {
- (void) session;
- (void) username;
- (void) type;
- (void) pubkey;
-
- return SSH_AUTH_DENIED;
-}
-
-int ssh_userauth1_password(ssh_session session, const char *username,
- const char *password) {
- ssh_string pwd = NULL;
- int rc;
-
- if (session->pending_call_state == SSH_PENDING_CALL_AUTH_PASSWORD) {
- goto pending;
- }
-
- rc = send_username(session, username);
- if (rc != SSH_AUTH_DENIED) {
- return rc;
- }
- /* we trick a bit here. A known flaw in SSH1 protocol is that it's
- * easy to guess password sizes.
- * not that sure ...
- */
-
- /* XXX fix me here ! */
- /* cisco IOS doesn't like when a password is followed by zeroes and random pad. */
- if(1 || strlen(password) >= 128) {
- /* not risky to disclose the size of such a big password .. */
- pwd = ssh_string_from_char(password);
- if (pwd == NULL) {
- return SSH_AUTH_ERROR;
- }
- } else {
- char buf[128] = {0};
- /* fill the password string from random things. the strcpy
- * ensure there is at least a nul byte after the password.
- * most implementation won't see the garbage at end.
- * why garbage ? because nul bytes will be compressed by
- * gzip and disclose password len.
- */
- pwd = ssh_string_new(sizeof(buf));
- if (pwd == NULL) {
- return SSH_AUTH_ERROR;
- }
- ssh_get_random(buf, sizeof(buf), 0);
- strcpy(buf, password);
- ssh_string_fill(pwd, buf, sizeof(buf));
- }
-
- if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_AUTH_PASSWORD) < 0) {
- ssh_string_burn(pwd);
- ssh_string_free(pwd);
-
- return SSH_AUTH_ERROR;
- }
- if (ssh_buffer_add_ssh_string(session->out_buffer, pwd) < 0) {
- ssh_string_burn(pwd);
- ssh_string_free(pwd);
-
- return SSH_AUTH_ERROR;
- }
-
- ssh_string_burn(pwd);
- ssh_string_free(pwd);
- session->auth_state=SSH_AUTH_STATE_NONE;
- session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
- if (ssh_packet_send(session) == SSH_ERROR) {
- return SSH_AUTH_ERROR;
- }
-pending:
- rc = wait_auth1_status(session);
- if (rc == SSH_AUTH_ERROR && errno == EAGAIN) {
- /* Nothing to do */
- } else if (rc != SSH_AUTH_AGAIN) {
- session->pending_call_state = SSH_PENDING_CALL_NONE;
- }
-
- return rc;
-}
-
-#endif /* WITH_SSH1 */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/base64.c b/src/base64.c
index 2a162d0..372dc65 100644
--- a/src/base64.c
+++ b/src/base64.c
@@ -22,9 +22,9 @@
*/
/* just the dirtiest part of code i ever made */
-#include <string.h>
+#include "config.h"
+
#include <stdio.h>
-#include <stdlib.h>
#include "libssh/priv.h"
#include "libssh/buffer.h"
@@ -288,5 +288,3 @@ unsigned char *bin_to_base64(const unsigned char *source, int len) {
return base64;
}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/bignum.c b/src/bignum.c
index fd6cf95..064006d 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -19,6 +19,8 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <stdio.h>
#include "libssh/priv.h"
@@ -58,6 +60,8 @@ ssh_string ssh_make_bignum_string(bignum num) {
bignum_bn2bin(num, len, ptr->data + pad);
#elif HAVE_LIBCRYPTO
bignum_bn2bin(num, ptr->data + pad);
+#elif HAVE_LIBMBEDCRYPTO
+ bignum_bn2bin(num, ptr->data + pad);
#endif
return ptr;
@@ -76,6 +80,9 @@ bignum ssh_make_string_bn(ssh_string string){
bignum_bin2bn(string->data, len, &bn);
#elif defined HAVE_LIBCRYPTO
bn = bignum_bin2bn(string->data, len, NULL);
+#elif defined HAVE_LIBMBEDCRYPTO
+ bn = bignum_new();
+ bignum_bin2bn(string->data, len, bn);
#endif
return bn;
@@ -89,6 +96,8 @@ void ssh_make_string_bn_inplace(ssh_string string, bignum bnout) {
(void) bnout;
#elif defined HAVE_LIBCRYPTO
bignum_bin2bn(string->data, len, bnout);
+#elif defined HAVE_LIBMBEDCRYPTO
+ bignum_bin2bn(string->data, len, bnout);
#endif
}
@@ -100,6 +109,9 @@ void ssh_print_bignum(const char *which, const bignum num) {
#elif defined HAVE_LIBCRYPTO
char *hex = NULL;
hex = bignum_bn2hex(num);
+#elif defined HAVE_LIBMBEDCRYPTO
+ char *hex = NULL;
+ hex = bignum_bn2hex(num);
#endif
fprintf(stderr, "%s value: ", which);
fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex);
@@ -107,5 +119,7 @@ void ssh_print_bignum(const char *which, const bignum num) {
SAFE_FREE(hex);
#elif defined HAVE_LIBCRYPTO
OPENSSL_free(hex);
+#elif defined HAVE_LIBMBEDCRYPTO
+ SAFE_FREE(hex);
#endif
}
diff --git a/src/bind.c b/src/bind.c
index fa5f8d5..b07dd57 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -149,9 +149,10 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
if (sshbind->ecdsakey == NULL &&
sshbind->dsakey == NULL &&
- sshbind->rsakey == NULL) {
+ sshbind->rsakey == NULL &&
+ sshbind->ed25519key == NULL) {
ssh_set_error(sshbind, SSH_FATAL,
- "ECDSA, DSA, or RSA host key file must be set");
+ "ECDSA, ED25519, DSA, or RSA host key file must be set");
return SSH_ERROR;
}
@@ -178,6 +179,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
}
#endif
+#ifdef HAVE_DSA
if (sshbind->dsa == NULL && sshbind->dsakey != NULL) {
rc = ssh_pki_import_privkey_file(sshbind->dsakey,
NULL,
@@ -199,6 +201,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
return SSH_ERROR;
}
}
+#endif
if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
rc = ssh_pki_import_privkey_file(sshbind->rsakey,
@@ -212,8 +215,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
return SSH_ERROR;
}
- if (ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA &&
- ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA1) {
+ if (ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA) {
ssh_set_error(sshbind, SSH_FATAL,
"The RSA host key has the wrong type");
ssh_key_free(sshbind->rsa);
@@ -222,6 +224,27 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
}
}
+ if (sshbind->ed25519 == NULL && sshbind->ed25519key != NULL) {
+ rc = ssh_pki_import_privkey_file(sshbind->ed25519key,
+ NULL,
+ NULL,
+ NULL,
+ &sshbind->ed25519);
+ if (rc == SSH_ERROR || rc == SSH_EOF) {
+ ssh_set_error(sshbind, SSH_FATAL,
+ "Failed to import private ED25519 host key");
+ return SSH_ERROR;
+ }
+
+ if (ssh_key_type(sshbind->ed25519) != SSH_KEYTYPE_ED25519) {
+ ssh_set_error(sshbind, SSH_FATAL,
+ "The ED25519 host key has the wrong type");
+ ssh_key_free(sshbind->ed25519);
+ sshbind->ed25519 = NULL;
+ return SSH_ERROR;
+ }
+ }
+
return SSH_OK;
}
@@ -230,12 +253,10 @@ int ssh_bind_listen(ssh_bind sshbind) {
socket_t fd;
int rc;
- if (ssh_init() < 0) {
- ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
- return -1;
- }
-
- if (sshbind->rsa == NULL && sshbind->dsa == NULL && sshbind->ecdsa == NULL) {
+ if (sshbind->rsa == NULL &&
+ sshbind->dsa == NULL &&
+ sshbind->ecdsa == NULL &&
+ sshbind->ed25519 == NULL) {
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
@@ -254,6 +275,7 @@ int ssh_bind_listen(ssh_bind sshbind) {
sshbind->dsa = NULL;
ssh_key_free(sshbind->rsa);
sshbind->rsa = NULL;
+ /* XXX should this clear also other structures that were allocated */
return -1;
}
@@ -266,6 +288,7 @@ int ssh_bind_listen(ssh_bind sshbind) {
sshbind->dsa = NULL;
ssh_key_free(sshbind->rsa);
sshbind->rsa = NULL;
+ /* XXX should this clear also other structures that were allocated */
return -1;
}
@@ -392,7 +415,6 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
}
session->server = 1;
- session->version = 2;
/* copy options */
for (i = 0; i < 10; i++) {
@@ -434,7 +456,8 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
*/
if (sshbind->rsa == NULL &&
sshbind->dsa == NULL &&
- sshbind->ecdsa == NULL) {
+ sshbind->ecdsa == NULL &&
+ sshbind->ed25519 == NULL) {
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
@@ -450,6 +473,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
}
}
#endif
+#ifdef HAVE_DSA
if (sshbind->dsa) {
session->srv.dsa_key = ssh_key_dup(sshbind->dsa);
if (session->srv.dsa_key == NULL) {
@@ -457,6 +481,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
return SSH_ERROR;
}
}
+#endif
if (sshbind->rsa) {
session->srv.rsa_key = ssh_key_dup(sshbind->rsa);
if (session->srv.rsa_key == NULL) {
diff --git a/src/buffer.c b/src/buffer.c
index 2da6758..51ecc49 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -21,9 +21,9 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
#include <stdarg.h>
#ifndef _WIN32
@@ -107,10 +107,10 @@ void ssh_buffer_free(struct ssh_buffer_struct *buffer) {
if (buffer->data) {
/* burn the data */
- BURN_BUFFER(buffer->data, buffer->allocated);
+ explicit_bzero(buffer->data, buffer->allocated);
SAFE_FREE(buffer->data);
}
- BURN_BUFFER(buffer, sizeof(struct ssh_buffer_struct));
+ explicit_bzero(buffer, sizeof(struct ssh_buffer_struct));
SAFE_FREE(buffer);
}
@@ -127,38 +127,40 @@ void ssh_buffer_set_secure(ssh_buffer buffer){
}
static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed) {
- size_t smallest = 1;
- char *new;
+ size_t smallest = 1;
+ char *new;
- buffer_verify(buffer);
+ buffer_verify(buffer);
- /* Find the smallest power of two which is greater or equal to needed */
- while(smallest <= needed) {
- if (smallest == 0) {
- return -1;
- }
- smallest <<= 1;
- }
- needed = smallest;
- if (buffer->secure){
- new = malloc(needed);
- if (new == NULL) {
- return -1;
- }
- memcpy(new, buffer->data,buffer->used);
- BURN_BUFFER(buffer->data, buffer->used);
- SAFE_FREE(buffer->data);
- } else {
- new = realloc(buffer->data, needed);
- if (new == NULL) {
- buffer->data = NULL;
- return -1;
- }
- }
- buffer->data = new;
- buffer->allocated = needed;
- buffer_verify(buffer);
- return 0;
+ /* Find the smallest power of two which is greater or equal to needed */
+ while(smallest <= needed) {
+ if (smallest == 0) {
+ return -1;
+ }
+ smallest <<= 1;
+ }
+ needed = smallest;
+ if (buffer->secure){
+ new = malloc(needed);
+ if (new == NULL) {
+ return -1;
+ }
+ if (buffer->used > 0) {
+ memcpy(new, buffer->data,buffer->used);
+ explicit_bzero(buffer->data, buffer->used);
+ SAFE_FREE(buffer->data);
+ }
+ } else {
+ new = realloc(buffer->data, needed);
+ if (new == NULL) {
+ buffer->data = NULL;
+ return -1;
+ }
+ }
+ buffer->data = new;
+ buffer->allocated = needed;
+ buffer_verify(buffer);
+ return 0;
}
/** @internal
@@ -177,7 +179,7 @@ static void buffer_shift(ssh_buffer buffer){
if (buffer->secure){
void *ptr = buffer->data + buffer->used;
- BURN_BUFFER(ptr, burn_pos);
+ explicit_bzero(ptr, burn_pos);
}
buffer_verify(buffer);
@@ -192,17 +194,21 @@ static void buffer_shift(ssh_buffer buffer){
*/
int ssh_buffer_reinit(struct ssh_buffer_struct *buffer)
{
- buffer_verify(buffer);
- BURN_BUFFER(buffer->data, buffer->used);
- buffer->used = 0;
- buffer->pos = 0;
- if(buffer->allocated > 127) {
- if (realloc_buffer(buffer, 127) < 0) {
- return -1;
+ buffer_verify(buffer);
+ if (buffer->used > 0) {
+ explicit_bzero(buffer->data, buffer->used);
}
- }
- buffer_verify(buffer);
- return 0;
+ buffer->used = 0;
+ buffer->pos = 0;
+
+ if (buffer->allocated > 127) {
+ if (realloc_buffer(buffer, 127) < 0) {
+ return -1;
+ }
+ }
+ buffer_verify(buffer);
+
+ return 0;
}
/**
@@ -243,6 +249,72 @@ int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint
}
/**
+ * @brief Ensure the buffer has at least a certain preallocated size.
+ *
+ * @param[in] buffer The buffer to enlarge.
+ *
+ * @param[in] len The length to ensure as allocated.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer,
+ uint32_t len)
+{
+ buffer_verify(buffer);
+
+ if (buffer->allocated < len) {
+ if (buffer->pos > 0) {
+ buffer_shift(buffer);
+ }
+ if (realloc_buffer(buffer, len) < 0) {
+ return -1;
+ }
+ }
+
+ buffer_verify(buffer);
+
+ return 0;
+}
+
+/**
+ * @internal
+ *
+ * @brief Allocate space for data at the tail of a buffer.
+ *
+ * @param[in] buffer The buffer to add the data.
+ *
+ * @param[in] len The length of the data to add.
+ *
+ * @return Pointer on the allocated space
+ * NULL on error.
+ */
+void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
+{
+ void *ptr;
+ buffer_verify(buffer);
+
+ if (buffer->used + len < len) {
+ return NULL;
+ }
+
+ if (buffer->allocated < (buffer->used + len)) {
+ if (buffer->pos > 0) {
+ buffer_shift(buffer);
+ }
+
+ if (realloc_buffer(buffer, buffer->used + len) < 0) {
+ return NULL;
+ }
+ }
+
+ ptr = buffer->data + buffer->used;
+ buffer->used+=len;
+ buffer_verify(buffer);
+
+ return ptr;
+}
+
+/**
* @internal
*
* @brief Add a SSH string to the tail of a buffer.
@@ -639,41 +711,6 @@ struct ssh_string_struct *ssh_buffer_get_ssh_string(struct ssh_buffer_struct *bu
return str;
}
-/**
- * @internal
- *
- * @brief Get a mpint out of the buffer and adjusts the read pointer.
- *
- * @note This function is SSH-1 only.
- *
- * @param[in] buffer The buffer to read.
- *
- * @returns The SSH String containing the mpint, NULL on error.
- */
-struct ssh_string_struct *ssh_buffer_get_mpint(struct ssh_buffer_struct *buffer) {
- uint16_t bits;
- uint32_t len;
- struct ssh_string_struct *str = NULL;
-
- if (ssh_buffer_get_data(buffer, &bits, sizeof(uint16_t)) != sizeof(uint16_t)) {
- return NULL;
- }
- bits = ntohs(bits);
- len = (bits + 7) / 8;
- if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
- return NULL;
- }
- str = ssh_string_new(len);
- if (str == NULL) {
- return NULL;
- }
- if (ssh_buffer_get_data(buffer, ssh_string_data(str), len) != len) {
- SAFE_FREE(str);
- return NULL;
- }
- return str;
-}
-
/** @internal
* @brief Add multiple values in a buffer on a single function call
* @param[in] buffer The buffer to add to
@@ -1059,5 +1096,3 @@ int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
}
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/chachapoly.c b/src/chachapoly.c
new file mode 100644
index 0000000..904303e
--- /dev/null
+++ b/src/chachapoly.c
@@ -0,0 +1,212 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2015 by Aris Adamantiadis
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "libssh/libssh.h"
+#include "libssh/crypto.h"
+#include "libssh/chacha.h"
+#include "libssh/poly1305.h"
+#include "libssh/misc.h"
+
+/* size of the keys k1 and k2 as defined in specs */
+#define CHACHA20_KEYLEN 32
+struct chacha20_poly1305_keysched {
+ /* key used for encrypting the length field*/
+ struct chacha_ctx k1;
+ /* key used for encrypting the packets */
+ struct chacha_ctx k2;
+};
+
+#pragma pack(push, 1)
+struct ssh_packet_header {
+ uint32_t length;
+ uint8_t payload[];
+};
+#pragma pack(pop)
+
+static const uint8_t zero_block_counter[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+static const uint8_t payload_block_counter[8] = {1, 0, 0, 0, 0, 0, 0, 0};
+
+static int chacha20_set_encrypt_key(struct ssh_cipher_struct *cipher,
+ void *key,
+ void *IV)
+{
+ struct chacha20_poly1305_keysched *sched;
+ uint8_t *u8key = key;
+ (void)IV;
+
+ if (cipher->chacha20_schedule == NULL) {
+ sched = malloc(sizeof *sched);
+ if (sched == NULL){
+ return -1;
+ }
+ } else {
+ sched = cipher->chacha20_schedule;
+ }
+
+ chacha_keysetup(&sched->k2, u8key, CHACHA20_KEYLEN * 8);
+ chacha_keysetup(&sched->k1, u8key + CHACHA20_KEYLEN, CHACHA20_KEYLEN * 8);
+ cipher->chacha20_schedule = sched;
+
+ return 0;
+}
+
+/**
+ * @internal
+ *
+ * @brief encrypts an outgoing packet with chacha20 and authenticate it
+ * with poly1305.
+ */
+static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ size_t len,
+ uint8_t *tag,
+ uint64_t seq)
+{
+ struct ssh_packet_header *in_packet = in, *out_packet = out;
+ uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0};
+ struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
+
+ seq = htonll(seq);
+ /* step 1, prepare the poly1305 key */
+ chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter);
+ chacha_encrypt_bytes(&keys->k2,
+ poly1305_ctx,
+ poly1305_ctx,
+ POLY1305_KEYLEN);
+
+ /* step 2, encrypt length field */
+ chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter);
+ chacha_encrypt_bytes(&keys->k1,
+ (uint8_t *)&in_packet->length,
+ (uint8_t *)&out_packet->length,
+ sizeof(uint32_t));
+
+ /* step 3, encrypt packet payload */
+ chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter);
+ chacha_encrypt_bytes(&keys->k2,
+ in_packet->payload,
+ out_packet->payload,
+ len - sizeof(uint32_t));
+
+ /* ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */
+ /* step 4, compute the MAC */
+ poly1305_auth(tag, (uint8_t *)out_packet, len, poly1305_ctx);
+ /* ssh_print_hexa("poly1305 src", (uint8_t *)out_packet, len);
+ ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN); */
+}
+
+static int chacha20_poly1305_aead_decrypt_length(
+ struct ssh_cipher_struct *cipher,
+ void *in,
+ uint8_t *out,
+ size_t len,
+ uint64_t seq)
+{
+ struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
+
+ if (len < sizeof(uint32_t)) {
+ return SSH_ERROR;
+ }
+ seq = htonll(seq);
+
+ chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter);
+ chacha_encrypt_bytes(&keys->k1,
+ in,
+ (uint8_t *)out,
+ sizeof(uint32_t));
+ return SSH_OK;
+}
+
+static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
+ void *complete_packet,
+ uint8_t *out,
+ size_t encrypted_size,
+ uint64_t seq)
+{
+ uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0};
+ uint8_t tag[POLY1305_TAGLEN] = {0};
+ struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
+ uint8_t *mac = (uint8_t *)complete_packet + sizeof(uint32_t) + encrypted_size;
+ int cmp;
+
+ seq = htonll(seq);
+
+ ZERO_STRUCT(poly1305_ctx);
+ chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter);
+ chacha_encrypt_bytes(&keys->k2,
+ poly1305_ctx,
+ poly1305_ctx,
+ POLY1305_KEYLEN);
+#if 0
+ ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx));
+#endif
+
+ poly1305_auth(tag, (uint8_t *)complete_packet, encrypted_size +
+ sizeof(uint32_t), poly1305_ctx);
+#if 0
+ ssh_print_hexa("poly1305 src",
+ (uint8_t*)complete_packet,
+ encrypted_size + 4);
+ ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN);
+ ssh_print_hexa("received tag", mac, POLY1305_TAGLEN);
+#endif
+
+ cmp = memcmp(tag, mac, POLY1305_TAGLEN);
+ if(cmp != 0) {
+ /* mac error */
+ SSH_LOG(SSH_LOG_PACKET,"poly1305 verify error");
+ return SSH_ERROR;
+ }
+ chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter);
+ chacha_encrypt_bytes(&keys->k2,
+ (uint8_t *)complete_packet + sizeof(uint32_t),
+ out,
+ encrypted_size);
+
+ return SSH_OK;
+}
+
+static void chacha20_cleanup(struct ssh_cipher_struct *cipher) {
+ SAFE_FREE(cipher->chacha20_schedule);
+}
+
+const struct ssh_cipher_struct chacha20poly1305_cipher = {
+ .name = "chacha20-poly1305@openssh.com",
+ .blocksize = 8,
+ .lenfield_blocksize = 4,
+ .keylen = sizeof(struct chacha20_poly1305_keysched),
+ .keysize = 512,
+ .tag_size = POLY1305_TAGLEN,
+ .set_encrypt_key = chacha20_set_encrypt_key,
+ .set_decrypt_key = chacha20_set_encrypt_key,
+ .aead_encrypt = chacha20_poly1305_aead_encrypt,
+ .aead_decrypt_length = chacha20_poly1305_aead_decrypt_length,
+ .aead_decrypt = chacha20_poly1305_aead_decrypt,
+ .cleanup = chacha20_cleanup
+};
+
+const struct ssh_cipher_struct *ssh_get_chacha20poly1305_cipher(void)
+{
+ return &chacha20poly1305_cipher;
+}
diff --git a/src/channels.c b/src/channels.c
index d32f0d7..beb2ae1 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -22,9 +22,9 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <limits.h>
-#include <string.h>
-#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
@@ -106,7 +106,6 @@ ssh_channel ssh_channel_new(ssh_session session) {
}
channel->session = session;
- channel->version = session->version;
channel->exit_status = -1;
channel->flags = SSH_CHANNEL_FLAG_NOT_BOUND;
@@ -346,13 +345,6 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize
uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE;
int rc;
-#ifdef WITH_SSH1
- if (session->version == 1){
- channel->remote_window = new_window;
-
- return SSH_OK;
- }
-#endif
if(new_window <= channel->local_window){
SSH_LOG(SSH_LOG_PROTOCOL,
"growing window (channel %d:%d) to %d bytes : not needed (%d bytes)",
@@ -398,8 +390,6 @@ error:
*
* @brief Parse a channel-related packet to resolve it to a ssh_channel.
*
- * This works on SSH1 sessions too.
- *
* @param[in] session The current SSH session.
*
* @param[in] packet The buffer to parse packet from. The read pointer will
@@ -412,11 +402,7 @@ static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
ssh_channel channel;
uint32_t chan;
int rc;
-#ifdef WITH_SSH1
- /* With SSH1, the channel is always the first one */
- if(session->version==1)
- return ssh_get_channel1(session);
-#endif
+
rc = ssh_buffer_unpack(packet,"d",&chan);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL,
@@ -547,7 +533,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
ssh_callbacks_iterate(channel->callbacks,
ssh_channel_callbacks,
channel_data_function) {
- if (ssh_buffer_get(buf) == 0) {
+ if (ssh_buffer_get(buf) == NULL) {
break;
}
rest = ssh_callbacks_iterate_exec(channel_data_function,
@@ -874,12 +860,6 @@ int ssh_channel_open_session(ssh_channel channel) {
return SSH_ERROR;
}
-#ifdef WITH_SSH1
- if (channel->session->version == 1) {
- return ssh_channel_open_session1(channel);
- }
-#endif
-
return channel_open(channel,
"session",
CHANNEL_INITIAL_WINDOW,
@@ -907,12 +887,6 @@ int ssh_channel_open_auth_agent(ssh_channel channel){
return SSH_ERROR;
}
-#ifdef WITH_SSH1
- if (channel->session->version == 1) {
- return SSH_ERROR;
- }
-#endif
-
return channel_open(channel,
"auth-agent@openssh.com",
CHANNEL_INITIAL_WINDOW,
@@ -1263,13 +1237,7 @@ static int channel_write_common(ssh_channel channel,
if (session->session_state == SSH_SESSION_STATE_ERROR) {
return SSH_ERROR;
}
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- rc = ssh_channel_write1(channel, data, len);
- return rc;
- }
-#endif
if (ssh_waitsession_unblocked(session) == 0){
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT,
ssh_waitsession_unblocked, session);
@@ -1477,8 +1445,6 @@ void ssh_channel_set_blocking(ssh_channel channel, int blocking) {
* @internal
*
* @brief handle a SSH_CHANNEL_SUCCESS packet and set the channel state.
- *
- * This works on SSH1 sessions too.
*/
SSH_PACKET_CALLBACK(ssh_packet_channel_success){
ssh_channel channel;
@@ -1509,8 +1475,6 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_success){
* @internal
*
* @brief Handle a SSH_CHANNEL_FAILURE packet and set the channel state.
- *
- * This works on SSH1 sessions too.
*/
SSH_PACKET_CALLBACK(ssh_packet_channel_failure){
ssh_channel channel;
@@ -1663,13 +1627,6 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
return rc;
}
-#ifdef WITH_SSH1
- if (channel->version==1) {
- rc = ssh_channel_request_pty_size1(channel,terminal, col, row);
-
- return rc;
- }
-#endif
switch(channel->request_state){
case SSH_CHANNEL_REQ_STATE_NONE:
break;
@@ -1741,14 +1698,6 @@ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) {
ssh_buffer buffer = NULL;
int rc = SSH_ERROR;
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- rc = ssh_channel_change_pty_size1(channel,cols,rows);
-
- return rc;
- }
-#endif
-
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(session);
@@ -1787,12 +1736,8 @@ int ssh_channel_request_shell(ssh_channel channel) {
if(channel == NULL) {
return SSH_ERROR;
}
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- return ssh_channel_request_shell1(channel);
- }
-#endif
- return channel_request(channel, "shell", NULL, 1);
+
+ return channel_request(channel, "shell", NULL, 1);
}
/**
@@ -1857,9 +1802,14 @@ static char *generate_cookie(void) {
static const char *hex = "0123456789abcdef";
char s[36];
unsigned char rnd[16];
+ int ok;
int i;
- ssh_get_random(rnd,sizeof(rnd),0);
+ ok = ssh_get_random(rnd, sizeof(rnd), 0);
+ if (!ok) {
+ return NULL;
+ }
+
for (i = 0; i < 16; i++) {
s[i*2] = hex[rnd[i] & 0x0f];
s[i*2+1] = hex[rnd[i] >> 4];
@@ -2428,11 +2378,6 @@ int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
return rc;
}
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- return ssh_channel_request_exec1(channel, cmd);
- }
-#endif
switch(channel->request_state){
case SSH_CHANNEL_REQ_STATE_NONE:
break;
@@ -2503,12 +2448,6 @@ int ssh_channel_request_send_signal(ssh_channel channel, const char *sig) {
return rc;
}
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
- }
-#endif
-
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(channel->session);
@@ -2529,6 +2468,49 @@ error:
/**
+ * @brief Send a break signal to the server (as described in RFC 4335).
+ *
+ * Sends a break signal to the remote process.
+ * Note, that remote system may not support breaks.
+ * In such a case this request will be silently ignored.
+ * Only SSH-v2 is supported.
+ *
+ * @param[in] channel The channel to send the break to.
+ *
+ * @param[in] length The break-length in milliseconds to send.
+ *
+ * @return SSH_OK on success, SSH_ERROR if an error occurred
+ * (including attempts to send signal via SSH-v1 session).
+ */
+int ssh_channel_request_send_break(ssh_channel channel, uint32_t length) {
+ ssh_buffer buffer = NULL;
+ int rc = SSH_ERROR;
+
+ if (channel == NULL) {
+ return SSH_ERROR;
+ }
+
+ buffer = ssh_buffer_new();
+ if (buffer == NULL) {
+ ssh_set_error_oom(channel->session);
+ goto error;
+ }
+
+ rc = ssh_buffer_pack(buffer, "d", length);
+ if (rc != SSH_OK) {
+ ssh_set_error_oom(channel->session);
+ goto error;
+ }
+
+ rc = channel_request(channel, "break", buffer, 0);
+
+error:
+ ssh_buffer_free(buffer);
+ return rc;
+}
+
+
+/**
* @brief Read data from a channel into a buffer.
*
* @param[in] channel The channel to read from.
@@ -3105,18 +3087,18 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
}
/* Prepare the outgoing temporary arrays */
- rchans = malloc(sizeof(ssh_channel ) * (count_ptrs(readchans) + 1));
+ rchans = calloc(count_ptrs(readchans) + 1, sizeof(ssh_channel));
if (rchans == NULL) {
return SSH_ERROR;
}
- wchans = malloc(sizeof(ssh_channel ) * (count_ptrs(writechans) + 1));
+ wchans = calloc(count_ptrs(writechans) + 1, sizeof(ssh_channel));
if (wchans == NULL) {
SAFE_FREE(rchans);
return SSH_ERROR;
}
- echans = malloc(sizeof(ssh_channel ) * (count_ptrs(exceptchans) + 1));
+ echans = calloc(count_ptrs(exceptchans) + 1, sizeof(ssh_channel));
if (echans == NULL) {
SAFE_FREE(rchans);
SAFE_FREE(wchans);
@@ -3383,12 +3365,6 @@ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
return SSH_ERROR;
}
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
- }
-#endif
-
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(channel->session);
@@ -3438,11 +3414,6 @@ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig,
ssh_set_error_invalid(channel->session);
return rc;
}
-#ifdef WITH_SSH1
- if (channel->version == 1) {
- return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
- }
-#endif
buffer = ssh_buffer_new();
if (buffer == NULL) {
@@ -3470,5 +3441,3 @@ error:
#endif
/* @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/channels1.c b/src/channels1.c
deleted file mode 100644
index 2d35722..0000000
--- a/src/channels1.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * channels1.c - Support for SSH-1 type channels
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- * Copyright (c) 2009 by Andreas Schneider <asn@cryptomilk.org>
- *
- * The SSH Library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at your
- * option) any later version.
- *
- * The SSH Library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the SSH Library; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/ssh1.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/channels.h"
-#include "libssh/session.h"
-#include "libssh/misc.h"
-
-#ifdef WITH_SSH1
-
-/*
- * This is a big hack. In fact, SSH1 doesn't make a clever use of channels.
- * The whole packets concerning shells are sent outside of a channel.
- * Thus, an inside limitation of this behavior is that you can't only
- * request one shell.
- * The question is still how they managed to embed two "channel" into one
- * protocol.
- */
-
-int ssh_channel_open_session1(ssh_channel chan) {
- ssh_session session;
-
- if (chan == NULL) {
- return -1;
- }
- session = chan->session;
-
- /*
- * We guess we are requesting an *exec* channel. It can only have one exec
- * channel. So we abort with an error if we need more than one.
- */
- if (session->exec_channel_opened) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "SSH1 supports only one execution channel. "
- "One has already been opened");
- return -1;
- }
- session->exec_channel_opened = 1;
- chan->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED;
- chan->state = SSH_CHANNEL_STATE_OPEN;
- chan->local_maxpacket = 32000;
- chan->local_window = 64000;
- SSH_LOG(SSH_LOG_PACKET, "Opened a SSH1 channel session");
-
- return 0;
-}
-
-/* 10 SSH_CMSG_REQUEST_PTY
- *
- * string TERM environment variable value (e.g. vt100)
- * 32-bit int terminal height, rows (e.g., 24)
- * 32-bit int terminal width, columns (e.g., 80)
- * 32-bit int terminal width, pixels (0 if no graphics) (e.g., 480)
- * 32-bit int terminal height, pixels (0 if no graphics) (e.g., 640)
- * n bytes tty modes encoded in binary
- * Some day, someone should have a look at that nasty tty encoded. It's
- * much simplier under ssh2. I just hope the defaults values are ok ...
- */
-
-int ssh_channel_request_pty_size1(ssh_channel channel, const char *terminal, int col,
- int row) {
- ssh_session session;
- ssh_string str = NULL;
-
- if (channel == NULL) {
- return SSH_ERROR;
- }
- session = channel->session;
-
- if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE &&
- channel->request_state != SSH_CHANNEL_REQ_STATE_ACCEPTED){
- ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
- return SSH_ERROR;
- }
- str = ssh_string_from_char(terminal);
- if (str == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
-
- if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_REQUEST_PTY) < 0 ||
- ssh_buffer_add_ssh_string(session->out_buffer, str) < 0) {
- ssh_string_free(str);
- return -1;
- }
- ssh_string_free(str);
-
- if (ssh_buffer_add_u32(session->out_buffer, ntohl(row)) < 0 ||
- ssh_buffer_add_u32(session->out_buffer, ntohl(col)) < 0 ||
- ssh_buffer_add_u32(session->out_buffer, 0) < 0 || /* x */
- ssh_buffer_add_u32(session->out_buffer, 0) < 0 || /* y */
- ssh_buffer_add_u8(session->out_buffer, 0) < 0) { /* tty things */
- return -1;
- }
-
- SSH_LOG(SSH_LOG_FUNCTIONS, "Opening a ssh1 pty");
- channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING;
- if (ssh_packet_send(session) == SSH_ERROR) {
- return -1;
- }
-
- while (channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING) {
- ssh_handle_packets(session, SSH_TIMEOUT_INFINITE);
- }
-
- switch(channel->request_state){
- case SSH_CHANNEL_REQ_STATE_ERROR:
- case SSH_CHANNEL_REQ_STATE_PENDING:
- case SSH_CHANNEL_REQ_STATE_NONE:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- return SSH_ERROR;
- case SSH_CHANNEL_REQ_STATE_ACCEPTED:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- SSH_LOG(SSH_LOG_RARE, "PTY: Success");
- return SSH_OK;
- case SSH_CHANNEL_REQ_STATE_DENIED:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Server denied PTY allocation");
- SSH_LOG(SSH_LOG_RARE, "PTY: denied");
- return SSH_ERROR;
- }
- // Not reached
- return SSH_ERROR;
-}
-
-int ssh_channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
- ssh_session session;
-
- if (channel == NULL) {
- return SSH_ERROR;
- }
- session = channel->session;
-
- if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
- ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
- return SSH_ERROR;
- }
- if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 ||
- ssh_buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 ||
- ssh_buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 ||
- ssh_buffer_add_u32(session->out_buffer, 0) < 0 ||
- ssh_buffer_add_u32(session->out_buffer, 0) < 0) {
- return SSH_ERROR;
- }
- channel->request_state=SSH_CHANNEL_REQ_STATE_PENDING;
- if (ssh_packet_send(session) == SSH_ERROR) {
- return SSH_ERROR;
- }
-
- SSH_LOG(SSH_LOG_PROTOCOL, "Change pty size send");
- while(channel->request_state==SSH_CHANNEL_REQ_STATE_PENDING){
- ssh_handle_packets(session, SSH_TIMEOUT_INFINITE);
- }
- switch(channel->request_state){
- case SSH_CHANNEL_REQ_STATE_ERROR:
- case SSH_CHANNEL_REQ_STATE_PENDING:
- case SSH_CHANNEL_REQ_STATE_NONE:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- return SSH_ERROR;
- case SSH_CHANNEL_REQ_STATE_ACCEPTED:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- SSH_LOG(SSH_LOG_PROTOCOL, "pty size changed");
- return SSH_OK;
- case SSH_CHANNEL_REQ_STATE_DENIED:
- channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
- SSH_LOG(SSH_LOG_RARE, "pty size change denied");
- ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied");
- return SSH_ERROR;
- }
- // Not reached
- return SSH_ERROR;
-
-}
-
-int ssh_channel_request_shell1(ssh_channel channel) {
- ssh_session session;
-
- if (channel == NULL) {
- return -1;
- }
- session = channel->session;
-
- if (ssh_buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL) < 0) {
- return -1;
- }
-
- if (ssh_packet_send(session) == SSH_ERROR) {
- return -1;
- }
-
- SSH_LOG(SSH_LOG_RARE, "Launched a shell");
-
- return 0;
-}
-
-int ssh_channel_request_exec1(ssh_channel channel, const char *cmd) {
- ssh_session session;
- ssh_string command = NULL;
-
- if (channel == NULL) {
- return -1;
- }
- session = channel->session;
-
- command = ssh_string_from_char(cmd);
- if (command == NULL) {
- return -1;
- }
-
- if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_EXEC_CMD) < 0 ||
- ssh_buffer_add_ssh_string(session->out_buffer, command) < 0) {
- ssh_string_free(command);
- return -1;
- }
- ssh_string_free(command);
-
- if(ssh_packet_send(session) == SSH_ERROR) {
- return -1;
- }
-
- SSH_LOG(SSH_LOG_RARE, "Executing %s ...", cmd);
-
- return 0;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_data1){
- ssh_channel channel = ssh_get_channel1(session);
- ssh_string str = NULL;
- int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1);
- (void)user;
-
- if (channel == NULL) {
- return SSH_PACKET_NOT_USED;
- }
-
- str = ssh_buffer_get_ssh_string(packet);
- if (str == NULL) {
- SSH_LOG(SSH_LOG_FUNCTIONS, "Invalid data packet !");
- return SSH_PACKET_USED;
- }
-
- SSH_LOG(SSH_LOG_PROTOCOL,
- "Adding %" PRIdS " bytes data in %d",
- ssh_string_len(str), is_stderr);
-
- if (channel_default_bufferize(channel, ssh_string_data(str), ssh_string_len(str),
- is_stderr) < 0) {
- ssh_string_free(str);
- return SSH_PACKET_USED;
- }
- ssh_string_free(str);
-
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_close1){
- ssh_channel channel = ssh_get_channel1(session);
- uint32_t status;
- int rc;
-
- (void)type;
- (void)user;
-
- if (channel == NULL) {
- return SSH_PACKET_NOT_USED;
- }
-
- ssh_buffer_get_u32(packet, &status);
- /*
- * It's much more than a channel closing. spec says it's the last
- * message sent by server (strange)
- */
-
- /* actually status is lost somewhere */
- channel->state = SSH_CHANNEL_STATE_CLOSED;
- channel->remote_eof = 1;
-
- rc = ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION);
- if (rc < 0) {
- return SSH_PACKET_NOT_USED;
- }
- ssh_packet_send(session);
-
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_exist_status1){
- ssh_channel channel = ssh_get_channel1(session);
- uint32_t status;
- (void)type;
- (void)user;
-
- if (channel == NULL) {
- return SSH_PACKET_NOT_USED;
- }
-
- ssh_buffer_get_u32(packet, &status);
- channel->state = SSH_CHANNEL_STATE_CLOSED;
- channel->remote_eof = 1;
- channel->exit_status = ntohl(status);
-
- return SSH_PACKET_USED;
-}
-
-
-int ssh_channel_write1(ssh_channel channel, const void *data, int len) {
- ssh_session session;
- int origlen = len;
- int effectivelen;
- const unsigned char *ptr=data;
-
- if (channel == NULL) {
- return -1;
- }
- session = channel->session;
-
- while (len > 0) {
- if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) {
- return -1;
- }
-
- effectivelen = len > 32000 ? 32000 : len;
-
- if (ssh_buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
- ssh_buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) {
- return -1;
- }
-
- ptr += effectivelen;
- len -= effectivelen;
-
- if (ssh_packet_send(session) == SSH_ERROR) {
- return -1;
- }
- ssh_handle_packets(session, SSH_TIMEOUT_NONBLOCKING);
- if (channel->counter != NULL) {
- channel->counter->out_bytes += effectivelen;
- }
- }
- if (ssh_blocking_flush(session,SSH_TIMEOUT_USER) == SSH_ERROR)
- return -1;
- return origlen;
-}
-
-ssh_channel ssh_get_channel1(ssh_session session){
- struct ssh_iterator *it;
-
- if (session == NULL) {
- return NULL;
- }
-
- /* With SSH1, the channel is always the first one */
- if(session->channels != NULL){
- it = ssh_list_get_iterator(session->channels);
- if(it)
- return ssh_iterator_value(ssh_channel, it);
- }
- return NULL;
-}
-#endif /* WITH_SSH1 */
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/client.c b/src/client.c
index 11a0022..00cbad3 100644
--- a/src/client.c
+++ b/src/client.c
@@ -21,9 +21,9 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
@@ -171,16 +171,13 @@ static int callback_receive_banner(const void *data, size_t len, void *user)
*/
int ssh_send_banner(ssh_session session, int server)
{
- const char *banner = NULL;
- const char *terminator = NULL;
+ const char *banner = CLIENT_BANNER_SSH2;
+ const char *terminator = "\r\n";
/* The maximum banner length is 255 for SSH2 */
char buffer[256] = {0};
size_t len;
int rc = SSH_ERROR;
- banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
- terminator = session->version == 1 ? "\n" : "\r\n";
-
if (server == 1) {
if (session->opts.custombanner == NULL){
len = strlen(banner);
@@ -211,11 +208,8 @@ int ssh_send_banner(ssh_session session, int server)
goto end;
}
- /* SSH version 1 has a banner length of 128 only */
- len = session->version == 1 ? 128 : 0;
-
snprintf(buffer,
- sizeof(buffer) - len,
+ sizeof(buffer),
"%s%s",
session->clientbanner,
terminator);
@@ -266,6 +260,7 @@ static int dh_handshake(ssh_session session) {
break;
#endif
#ifdef HAVE_CURVE25519
+ case SSH_KEX_CURVE25519_SHA256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_init(session);
break;
@@ -361,8 +356,6 @@ pending:
rc=SSH_AGAIN;
break;
case SSH_AUTH_SERVICE_NONE:
- case SSH_AUTH_SERVICE_USER_SENT:
- /* Invalid state, SSH1 specific */
rc=SSH_ERROR;
break;
}
@@ -382,122 +375,86 @@ pending:
* @brief A function to be called each time a step has been done in the
* connection.
*/
-static void ssh_client_connection_callback(ssh_session session){
- int ssh1,ssh2;
-
- switch(session->session_state){
- case SSH_SESSION_STATE_NONE:
- case SSH_SESSION_STATE_CONNECTING:
- break;
- case SSH_SESSION_STATE_SOCKET_CONNECTED:
- /* If SSHv1 is disabled, we can send the banner immedietly */
- if (session->opts.ssh1 == 0) {
- ssh_set_fd_towrite(session);
- ssh_send_banner(session, 0);
+static void ssh_client_connection_callback(ssh_session session)
+{
+ int rc;
+
+ switch(session->session_state) {
+ case SSH_SESSION_STATE_NONE:
+ case SSH_SESSION_STATE_CONNECTING:
+ break;
+ case SSH_SESSION_STATE_SOCKET_CONNECTED:
+ ssh_set_fd_towrite(session);
+ ssh_send_banner(session, 0);
+
+ break;
+ case SSH_SESSION_STATE_BANNER_RECEIVED:
+ if (session->serverbanner == NULL) {
+ goto error;
+ }
+ set_status(session, 0.4f);
+ SSH_LOG(SSH_LOG_RARE,
+ "SSH server banner: %s", session->serverbanner);
+
+ /* Here we analyze the different protocols the server allows. */
+ rc = ssh_analyze_banner(session, 0);
+ if (rc < 0) {
+ ssh_set_error(session, SSH_FATAL,
+ "No version of SSH protocol usable (banner: %s)",
+ session->serverbanner);
+ goto error;
+ }
+
+ ssh_packet_register_socket_callback(session, session->socket);
+
+ ssh_packet_set_default_callbacks(session);
+ session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
+ set_status(session, 0.5f);
+
+ break;
+ case SSH_SESSION_STATE_INITIAL_KEX:
+ /* TODO: This state should disappear in favor of get_key handle */
+ break;
+ case SSH_SESSION_STATE_KEXINIT_RECEIVED:
+ set_status(session,0.6f);
+ ssh_list_kex(&session->next_crypto->server_kex);
+ if (ssh_set_client_kex(session) < 0) {
+ goto error;
+ }
+ if (ssh_kex_select_methods(session) == SSH_ERROR)
+ goto error;
+ if (ssh_send_kex(session, 0) < 0) {
+ goto error;
+ }
+ set_status(session,0.8f);
+ session->session_state=SSH_SESSION_STATE_DH;
+ if (dh_handshake(session) == SSH_ERROR) {
+ goto error;
}
- break;
- case SSH_SESSION_STATE_BANNER_RECEIVED:
- if (session->serverbanner == NULL) {
- goto error;
- }
- set_status(session, 0.4f);
- SSH_LOG(SSH_LOG_RARE,
- "SSH server banner: %s", session->serverbanner);
-
- /* Here we analyze the different protocols the server allows. */
- if (ssh_analyze_banner(session, 0, &ssh1, &ssh2) < 0) {
- goto error;
- }
- /* Here we decide which version of the protocol to use. */
- if (ssh2 && session->opts.ssh2) {
- session->version = 2;
-#ifdef WITH_SSH1
- } else if(ssh1 && session->opts.ssh1) {
- session->version = 1;
-#endif
- } else if(ssh1 && !session->opts.ssh1){
-#ifdef WITH_SSH1
- ssh_set_error(session, SSH_FATAL,
- "SSH-1 protocol not available (configure session to allow SSH-1)");
- goto error;
-#else
- ssh_set_error(session, SSH_FATAL,
- "SSH-1 protocol not available (libssh compiled without SSH-1 support)");
- goto error;
-#endif
- } else {
- ssh_set_error(session, SSH_FATAL,
- "No version of SSH protocol usable (banner: %s)",
- session->serverbanner);
- goto error;
- }
- /* from now, the packet layer is handling incoming packets */
- if (session->version == 2) {
- ssh_packet_register_socket_callback(session, session->socket);
- }
-#ifdef WITH_SSH1
- else
- session->socket_callbacks.data=ssh_packet_socket_callback1;
-#endif
- ssh_packet_set_default_callbacks(session);
- session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
- if (session->opts.ssh1 == 1) {
- ssh_send_banner(session, 0);
- }
- set_status(session, 0.5f);
- break;
- case SSH_SESSION_STATE_INITIAL_KEX:
- /* TODO: This state should disappear in favor of get_key handle */
-#ifdef WITH_SSH1
- if(session->version==1){
- if (ssh_get_kex1(session) < 0)
- goto error;
- set_status(session,0.6f);
- session->connected = 1;
- break;
- }
-#endif
- break;
- case SSH_SESSION_STATE_KEXINIT_RECEIVED:
- set_status(session,0.6f);
- ssh_list_kex(&session->next_crypto->server_kex);
- if (ssh_set_client_kex(session) < 0) {
- goto error;
- }
- if (ssh_kex_select_methods(session) == SSH_ERROR)
- goto error;
- if (ssh_send_kex(session, 0) < 0) {
- goto error;
- }
- set_status(session,0.8f);
- session->session_state=SSH_SESSION_STATE_DH;
- if (dh_handshake(session) == SSH_ERROR) {
- goto error;
- }
/* FALL THROUGH */
- case SSH_SESSION_STATE_DH:
- if(session->dh_handshake_state==DH_STATE_FINISHED){
- set_status(session,1.0f);
- session->connected = 1;
- if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
- session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
- else
- session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
- }
- break;
- case SSH_SESSION_STATE_AUTHENTICATING:
- break;
- case SSH_SESSION_STATE_ERROR:
- goto error;
- default:
- ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
- }
+ case SSH_SESSION_STATE_DH:
+ if(session->dh_handshake_state==DH_STATE_FINISHED){
+ set_status(session,1.0f);
+ session->connected = 1;
+ if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
+ session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
+ else
+ session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
+ }
+ break;
+ case SSH_SESSION_STATE_AUTHENTICATING:
+ break;
+ case SSH_SESSION_STATE_ERROR:
+ goto error;
+ default:
+ ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
+ }
- return;
+ return;
error:
- ssh_socket_close(session->socket);
- session->alive = 0;
- session->session_state=SSH_SESSION_STATE_ERROR;
+ ssh_socket_close(session->socket);
+ session->alive = 0;
+ session->session_state=SSH_SESSION_STATE_ERROR;
}
@@ -548,9 +505,6 @@ int ssh_connect(ssh_session session) {
session->alive = 0;
session->client = 1;
- if (ssh_init() < 0) {
- return SSH_ERROR;
- }
if (session->opts.fd == SSH_INVALID_SOCKET &&
session->opts.host == NULL &&
session->opts.ProxyCommand == NULL) {
@@ -696,10 +650,11 @@ void ssh_disconnect(ssh_session session) {
if (session->socket != NULL && ssh_socket_is_open(session->socket)) {
rc = ssh_buffer_pack(session->out_buffer,
- "bds",
+ "bdss",
SSH2_MSG_DISCONNECT,
SSH2_DISCONNECT_BY_APPLICATION,
- "Bye Bye");
+ "Bye Bye",
+ ""); /* language tag */
if (rc != SSH_OK){
ssh_set_error_oom(session);
goto error;
@@ -709,6 +664,8 @@ void ssh_disconnect(ssh_session session) {
ssh_socket_close(session->socket);
}
error:
+ session->recv_seq = 0;
+ session->send_seq = 0;
session->alive = 0;
if (session->socket != NULL){
ssh_socket_reset(session->socket);
@@ -724,6 +681,13 @@ error:
crypto_free(session->current_crypto);
session->current_crypto=NULL;
}
+ if (session->next_crypto) {
+ crypto_free(session->next_crypto);
+ session->next_crypto = crypto_new();
+ if (session->next_crypto == NULL) {
+ ssh_set_error_oom(session);
+ }
+ }
if (session->in_buffer) {
ssh_buffer_reinit(session->in_buffer);
}
@@ -757,10 +721,10 @@ error:
}
const char *ssh_copyright(void) {
- return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2014 Aris Adamantiadis, Andreas Schneider, "
- "and libssh contributors. Distributed under the LGPL, please refer to COPYING "
- "file for information about your rights";
+ return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2018 "
+ "Aris Adamantiadis, Andreas Schneider "
+ "and libssh contributors. "
+ "Distributed under the LGPL, please refer to COPYING "
+ "file for information about your rights";
}
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/config.c b/src/config.c
index 42148df..12792af 100644
--- a/src/config.c
+++ b/src/config.c
@@ -27,6 +27,9 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#ifdef HAVE_GLOB_H
+# include <glob.h>
+#endif
#include "libssh/priv.h"
#include "libssh/session.h"
@@ -36,13 +39,20 @@
#define MAX_LINE_SIZE 1024
enum ssh_config_opcode_e {
+ /* Unknown opcode */
+ SOC_UNKNOWN = -3,
+ /* Known and not applicable to libssh */
+ SOC_NA = -2,
+ /* Known but not supported by current libssh version */
SOC_UNSUPPORTED = -1,
SOC_HOST,
+ SOC_MATCH,
SOC_HOSTNAME,
SOC_PORT,
SOC_USERNAME,
SOC_IDENTITY,
SOC_CIPHERS,
+ SOC_MACS,
SOC_COMPRESSION,
SOC_TIMEOUT,
SOC_PROTOCOL,
@@ -53,6 +63,15 @@ enum ssh_config_opcode_e {
SOC_GSSAPICLIENTIDENTITY,
SOC_GSSAPIDELEGATECREDENTIALS,
SOC_INCLUDE,
+ SOC_BINDADDRESS,
+ SOC_GLOBALKNOWNHOSTSFILE,
+ SOC_LOGLEVEL,
+ SOC_HOSTKEYALGORITHMS,
+ SOC_KEXALGORITHMS,
+ SOC_GSSAPIAUTHENTICATION,
+ SOC_KBDINTERACTIVEAUTHENTICATION,
+ SOC_PASSWORDAUTHENTICATION,
+ SOC_PUBKEYAUTHENTICATION,
SOC_END /* Keep this one last in the list */
};
@@ -64,11 +83,13 @@ struct ssh_config_keyword_table_s {
static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "host", SOC_HOST },
+ { "match", SOC_MATCH },
{ "hostname", SOC_HOSTNAME },
{ "port", SOC_PORT },
{ "user", SOC_USERNAME },
{ "identityfile", SOC_IDENTITY },
{ "ciphers", SOC_CIPHERS },
+ { "macs", SOC_MACS },
{ "compression", SOC_COMPRESSION },
{ "connecttimeout", SOC_TIMEOUT },
{ "protocol", SOC_PROTOCOL },
@@ -76,10 +97,91 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "userknownhostsfile", SOC_KNOWNHOSTS },
{ "proxycommand", SOC_PROXYCOMMAND },
{ "gssapiserveridentity", SOC_GSSAPISERVERIDENTITY },
- { "gssapiserveridentity", SOC_GSSAPICLIENTIDENTITY },
+ { "gssapiclientidentity", SOC_GSSAPICLIENTIDENTITY },
{ "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
{ "include", SOC_INCLUDE },
- { NULL, SOC_UNSUPPORTED }
+ { "bindaddress", SOC_BINDADDRESS},
+ { "globalknownhostsfile", SOC_GLOBALKNOWNHOSTSFILE},
+ { "loglevel", SOC_LOGLEVEL},
+ { "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
+ { "kexalgorithms", SOC_KEXALGORITHMS},
+ { "mac", SOC_UNSUPPORTED}, /* SSHv1 */
+ { "gssapiauthentication", SOC_GSSAPIAUTHENTICATION},
+ { "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
+ { "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
+ { "pubkeyauthentication", SOC_PUBKEYAUTHENTICATION},
+ { "addkeystoagent", SOC_UNSUPPORTED},
+ { "addressfamily", SOC_UNSUPPORTED},
+ { "batchmode", SOC_UNSUPPORTED},
+ { "canonicaldomains", SOC_UNSUPPORTED},
+ { "canonicalizefallbacklocal", SOC_UNSUPPORTED},
+ { "canonicalizehostname", SOC_UNSUPPORTED},
+ { "canonicalizemaxdots", SOC_UNSUPPORTED},
+ { "canonicalizepermittedcnames", SOC_UNSUPPORTED},
+ { "certificatefile", SOC_UNSUPPORTED},
+ { "challengeresponseauthentication", SOC_UNSUPPORTED},
+ { "checkhostip", SOC_UNSUPPORTED},
+ { "cipher", SOC_UNSUPPORTED}, /* SSHv1 */
+ { "compressionlevel", SOC_UNSUPPORTED}, /* SSHv1 */
+ { "connectionattempts", SOC_UNSUPPORTED},
+ { "enablesshkeysign", SOC_UNSUPPORTED},
+ { "fingerprinthash", SOC_UNSUPPORTED},
+ { "forwardagent", SOC_UNSUPPORTED},
+ { "gssapikeyexchange", SOC_UNSUPPORTED},
+ { "gssapirenewalforcesrekey", SOC_UNSUPPORTED},
+ { "gssapitrustdns", SOC_UNSUPPORTED},
+ { "hashknownhosts", SOC_UNSUPPORTED},
+ { "hostbasedauthentication", SOC_UNSUPPORTED},
+ { "hostbasedkeytypes", SOC_UNSUPPORTED},
+ { "hostkeyalias", SOC_UNSUPPORTED},
+ { "identitiesonly", SOC_UNSUPPORTED},
+ { "identityagent", SOC_UNSUPPORTED},
+ { "ipqos", SOC_UNSUPPORTED},
+ { "kbdinteractivedevices", SOC_UNSUPPORTED},
+ { "nohostauthenticationforlocalhost", SOC_UNSUPPORTED},
+ { "numberofpasswordprompts", SOC_UNSUPPORTED},
+ { "pkcs11provider", SOC_UNSUPPORTED},
+ { "preferredauthentications", SOC_UNSUPPORTED},
+ { "proxyjump", SOC_UNSUPPORTED},
+ { "proxyusefdpass", SOC_UNSUPPORTED},
+ { "pubkeyacceptedtypes", SOC_UNSUPPORTED},
+ { "rekeylimit", SOC_UNSUPPORTED},
+ { "remotecommand", SOC_UNSUPPORTED},
+ { "revokedhostkeys", SOC_UNSUPPORTED},
+ { "rhostsrsaauthentication", SOC_UNSUPPORTED},
+ { "rsaauthentication", SOC_UNSUPPORTED}, /* SSHv1 */
+ { "serveralivecountmax", SOC_UNSUPPORTED},
+ { "serveraliveinterval", SOC_UNSUPPORTED},
+ { "streamlocalbindmask", SOC_UNSUPPORTED},
+ { "streamlocalbindunlink", SOC_UNSUPPORTED},
+ { "syslogfacility", SOC_UNSUPPORTED},
+ { "tcpkeepalive", SOC_UNSUPPORTED},
+ { "updatehostkeys", SOC_UNSUPPORTED},
+ { "useprivilegedport", SOC_UNSUPPORTED},
+ { "verifyhostkeydns", SOC_UNSUPPORTED},
+ { "visualhostkey", SOC_UNSUPPORTED},
+ { "clearallforwardings", SOC_NA},
+ { "controlmaster", SOC_NA},
+ { "controlpersist", SOC_NA},
+ { "controlpath", SOC_NA},
+ { "dynamicforward", SOC_NA},
+ { "escapechar", SOC_NA},
+ { "exitonforwardfailure", SOC_NA},
+ { "forwardx11", SOC_NA},
+ { "forwardx11timeout", SOC_NA},
+ { "forwardx11trusted", SOC_NA},
+ { "gatewayports", SOC_NA},
+ { "ignoreunknown", SOC_NA},
+ { "localcommand", SOC_NA},
+ { "localforward", SOC_NA},
+ { "permitlocalcommand", SOC_NA},
+ { "remoteforward", SOC_NA},
+ { "requesttty", SOC_NA},
+ { "sendenv", SOC_NA},
+ { "tunnel", SOC_NA},
+ { "tunneldevice", SOC_NA},
+ { "xauthlocation", SOC_NA},
+ { NULL, SOC_UNKNOWN }
};
static int ssh_config_parse_line(ssh_session session, const char *line,
@@ -94,7 +196,7 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
}
}
- return SOC_UNSUPPORTED;
+ return SOC_UNKNOWN;
}
static char *ssh_config_get_cmd(char **str) {
@@ -149,9 +251,9 @@ out:
return r;
}
-static int ssh_config_get_int(char **str, int notfound) {
+static long ssh_config_get_long(char **str, long notfound) {
char *p, *endp;
- int i;
+ long i;
p = ssh_config_get_token(str);
if (p && *p) {
@@ -217,6 +319,37 @@ static void local_parse_file(ssh_session session, const char *filename, int *par
return;
}
+#ifdef HAVE_GLOB
+static void local_parse_glob(ssh_session session,
+ const char *fileglob,
+ int *parsing,
+ int seen[])
+{
+ glob_t globbuf = {
+ .gl_flags = 0,
+ };
+ int rt;
+ u_int i;
+
+ rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
+ if (rt == GLOB_NOMATCH) {
+ globfree(&globbuf);
+ return;
+ } else if (rt != 0) {
+ SSH_LOG(SSH_LOG_RARE, "Glob error: %s",
+ fileglob);
+ globfree(&globbuf);
+ return;
+ }
+
+ for (i = 0; i < globbuf.gl_pathc; i++) {
+ local_parse_file(session, globbuf.gl_pathv[i], parsing, seen);
+ }
+
+ globfree(&globbuf);
+}
+#endif /* HAVE_GLOB */
+
static int ssh_config_parse_line(ssh_session session, const char *line,
unsigned int count, int *parsing, int seen[]) {
enum ssh_config_opcode_e opcode;
@@ -226,6 +359,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
char *lowerhost;
size_t len;
int i;
+ long l;
x = s = strdup(line);
if (s == NULL) {
@@ -251,6 +385,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
opcode = ssh_config_get_opcode(keyword);
if (*parsing == 1 && opcode != SOC_HOST && opcode != SOC_UNSUPPORTED && opcode != SOC_INCLUDE) {
if (seen[opcode] != 0) {
+ SAFE_FREE(x);
return 0;
}
seen[opcode] = 1;
@@ -261,7 +396,11 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
+#ifdef HAVE_GLOB
+ local_parse_glob(session, p, parsing, seen);
+#else
local_parse_file(session, p, parsing, seen);
+#endif /* HAVE_GLOB */
}
break;
case SOC_HOST: {
@@ -296,13 +435,11 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
break;
case SOC_PORT:
- if (session->opts.port == 0) {
- p = ssh_config_get_str_tok(&s, NULL);
- if (p && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
- }
- }
- break;
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
+ }
+ break;
case SOC_USERNAME:
if (session->opts.username == NULL) {
p = ssh_config_get_str_tok(&s, NULL);
@@ -324,6 +461,13 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, p);
}
break;
+ case SOC_MACS:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, p);
+ ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, p);
+ }
+ break;
case SOC_COMPRESSION:
i = ssh_config_get_yesno(&s, -1);
if (i >= 0 && *parsing) {
@@ -345,14 +489,11 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
return -1;
}
i = 0;
- ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
for (a = strtok(b, ","); a; a = strtok(NULL, ",")) {
switch (atoi(a)) {
case 1:
- i = 1;
- ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
break;
case 2:
i = 1;
@@ -366,9 +507,9 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
break;
case SOC_TIMEOUT:
- i = ssh_config_get_int(&s, -1);
- if (i >= 0 && *parsing) {
- ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &i);
+ l = ssh_config_get_long(&s, -1);
+ if (l >= 0 && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &l);
}
break;
case SOC_STRICTHOSTKEYCHECK:
@@ -407,10 +548,92 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
ssh_options_set(session, SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, &i);
}
break;
+ case SOC_BINDADDRESS:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_BINDADDR, p);
+ }
+ break;
+ case SOC_GLOBALKNOWNHOSTSFILE:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, p);
+ }
+ break;
+ case SOC_LOGLEVEL:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ int value = -1;
+
+ if (strcasecmp(p, "quiet") == 0) {
+ value = SSH_LOG_NONE;
+ } else if (strcasecmp(p, "fatal") == 0 ||
+ strcasecmp(p, "error")== 0 ||
+ strcasecmp(p, "info") == 0) {
+ value = SSH_LOG_WARN;
+ } else if (strcasecmp(p, "verbose") == 0) {
+ value = SSH_LOG_INFO;
+ } else if (strcasecmp(p, "DEBUG") == 0 ||
+ strcasecmp(p, "DEBUG1") == 0) {
+ value = SSH_LOG_DEBUG;
+ } else if (strcasecmp(p, "DEBUG2") == 0 ||
+ strcasecmp(p, "DEBUG3") == 0) {
+ value = SSH_LOG_TRACE;
+ }
+ if (value != -1) {
+ ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &value);
+ }
+ }
+ break;
+ case SOC_HOSTKEYALGORITHMS:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, p);
+ }
+ break;
+ case SOC_KEXALGORITHMS:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p && *parsing) {
+ ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
+ }
+ break;
+ case SOC_GSSAPIAUTHENTICATION:
+ case SOC_KBDINTERACTIVEAUTHENTICATION:
+ case SOC_PASSWORDAUTHENTICATION:
+ case SOC_PUBKEYAUTHENTICATION:
+ i = ssh_config_get_yesno(&s, 0);
+ if (i>=0 && *parsing) {
+ switch(opcode){
+ case SOC_GSSAPIAUTHENTICATION:
+ ssh_options_set(session, SSH_OPTIONS_GSSAPI_AUTH, &i);
+ break;
+ case SOC_KBDINTERACTIVEAUTHENTICATION:
+ ssh_options_set(session, SSH_OPTIONS_KBDINT_AUTH, &i);
+ break;
+ case SOC_PASSWORDAUTHENTICATION:
+ ssh_options_set(session, SSH_OPTIONS_PASSWORD_AUTH, &i);
+ break;
+ case SOC_PUBKEYAUTHENTICATION:
+ ssh_options_set(session, SSH_OPTIONS_PUBKEY_AUTH, &i);
+ break;
+ /* make gcc happy */
+ default:
+ break;
+ }
+ }
+ break;
+ case SOC_NA:
+ SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d\n",
+ keyword, count);
+ break;
case SOC_UNSUPPORTED:
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d",
keyword, count);
break;
+ case SOC_UNKNOWN:
+ SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d\n",
+ keyword, count);
+ break;
default:
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
opcode);
diff --git a/src/connect.c b/src/connect.c
index 50c9e99..69bdf7e 100644
--- a/src/connect.c
+++ b/src/connect.c
@@ -74,6 +74,7 @@
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#endif /* _WIN32 */
@@ -216,6 +217,12 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host,
return s;
}
+static int set_tcp_nodelay(socket_t socket)
+{
+ int opt = 1;
+ return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
+}
+
/**
* @internal
*
@@ -387,6 +394,18 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
continue;
}
+ if (session->opts.nodelay) {
+ /* For winsock, socket options are only effective before connect */
+ rc = set_tcp_nodelay(s);
+ if (rc < 0) {
+ ssh_set_error(session, SSH_FATAL,
+ "Failed to set TCP_NODELAY on socket: %s", strerror(errno));
+ ssh_connect_socket_close(s);
+ s = -1;
+ continue;
+ }
+ }
+
errno = 0;
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
@@ -518,5 +537,3 @@ out:
}
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/connector.c b/src/connector.c
index 54e8524..407aa52 100644
--- a/src/connector.c
+++ b/src/connector.c
@@ -19,6 +19,8 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include "libssh/priv.h"
#include "libssh/poll.h"
#include "libssh/callbacks.h"
@@ -104,6 +106,15 @@ ssh_connector ssh_connector_new(ssh_session session)
void ssh_connector_free (ssh_connector connector)
{
+ if (connector->in_channel != NULL) {
+ ssh_remove_channel_callbacks(connector->in_channel,
+ &connector->in_channel_cb);
+ }
+ if (connector->out_channel != NULL) {
+ ssh_remove_channel_callbacks(connector->out_channel,
+ &connector->out_channel_cb);
+ }
+
if (connector->event != NULL){
ssh_connector_remove_event(connector);
}
@@ -118,15 +129,6 @@ void ssh_connector_free (ssh_connector connector)
connector->out_poll = NULL;
}
- if (connector->in_channel != NULL) {
- ssh_remove_channel_callbacks(connector->in_channel,
- &connector->in_channel_cb);
- }
- if (connector->out_channel != NULL) {
- ssh_remove_channel_callbacks(connector->out_channel,
- &connector->out_channel_cb);
- }
-
free(connector);
}
@@ -368,9 +370,10 @@ static int ssh_connector_fd_cb(ssh_poll_handle p,
if (revents & POLLERR) {
ssh_connector_except(connector, fd);
- } else if((revents & POLLIN) && fd == connector->in_fd) {
+ } else if((revents & (POLLIN|POLLHUP)) && fd == connector->in_fd) {
ssh_connector_fd_in_cb(connector);
- } else if((revents & POLLOUT) && fd == connector->out_fd) {
+ } else if(((revents & POLLOUT) || (revents & POLLHUP)) &&
+ fd == connector->out_fd) {
ssh_connector_fd_out_cb(connector);
}
ssh_connector_reset_pollevents(connector);
diff --git a/src/crc32.c b/src/crc32.c
deleted file mode 100644
index cb4e931..0000000
--- a/src/crc32.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * crc32.c - simple CRC32 code
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2005 by Aris Adamantiadis
- *
- * The SSH Library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at your
- * option) any later version.
- *
- * The SSH Library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the SSH Library; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include "libssh/priv.h"
-#include "libssh/crc32.h"
-
-static uint32_t crc_table[] = {
- 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
- 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
- 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
- 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
- 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
- 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
- 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
- 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
- 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
- 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
- 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
- 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
- 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
- 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
- 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
- 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
- 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
- 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
- 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
- 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
- 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
- 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
- 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
- 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
- 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
- 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
- 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
- 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
- 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
- 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
- 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
- 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
- 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
- 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
- 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
- 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
- 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
- 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
- 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
- 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
- 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
- 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
- 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
- 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
- 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
- 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
- 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
- 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
- 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
- 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
- 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
- 0x2d02ef8dUL
-};
-
-uint32_t ssh_crc32(const char *buf, uint32_t len) {
- uint32_t ret = 0;
- while(len > 0) {
- ret = crc_table[(ret ^ *buf) & 0xff] ^ (ret >> 8);
- --len;
- ++buf;
- }
-
- return ret;
-}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/curve25519.c b/src/curve25519.c
index 77fab2d..167209f 100644
--- a/src/curve25519.c
+++ b/src/curve25519.c
@@ -1,6 +1,6 @@
/*
* curve25519.c - Curve25519 ECDH functions for key exchange
- * curve25519-sha256@libssh.org
+ * curve25519-sha256@libssh.org and curve25519-sha256
*
* This file is part of the SSH Library
*
@@ -40,13 +40,14 @@
#include "libssh/bignum.h"
/** @internal
- * @brief Starts curve25519-sha256@libssh.org key exchange
+ * @brief Starts curve25519-sha256@libssh.org / curve25519-sha256 key exchange
*/
int ssh_client_curve25519_init(ssh_session session){
int rc;
+ int ok;
- rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
- if (rc == 0){
+ ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
+ if (!ok) {
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
@@ -78,6 +79,12 @@ static int ssh_curve25519_build_k(ssh_session session) {
if (session->next_crypto->k == NULL) {
return SSH_ERROR;
}
+#elif defined HAVE_LIBMBEDCRYPTO
+ session->next_crypto->k = bignum_new();
+
+ if (session->next_crypto->k == NULL) {
+ return SSH_ERROR;
+ }
#endif
if (session->server)
@@ -91,6 +98,8 @@ static int ssh_curve25519_build_k(ssh_session session) {
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->k);
#elif defined HAVE_LIBCRYPTO
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
+#elif defined HAVE_LIBMBEDCRYPTO
+ bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
#endif
#ifdef DEBUG_CRYPTO
@@ -110,17 +119,24 @@ static int ssh_curve25519_build_k(ssh_session session) {
*/
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
ssh_string q_s_string = NULL;
- ssh_string pubkey = NULL;
+ ssh_string pubkey_blob = NULL;
ssh_string signature = NULL;
int rc;
- pubkey = ssh_buffer_get_ssh_string(packet);
- if (pubkey == NULL){
+
+ pubkey_blob = ssh_buffer_get_ssh_string(packet);
+ if (pubkey_blob == NULL) {
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
- /* this is the server host key */
- session->next_crypto->server_pubkey = pubkey;
- pubkey = NULL;
+
+ rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
+ ssh_string_free(pubkey_blob);
+ if (rc != 0) {
+ ssh_set_error(session,
+ SSH_FATAL,
+ "Failed to import next public key");
+ goto error;
+ }
q_s_string = ssh_buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
@@ -170,10 +186,12 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
/* ECDH keys */
ssh_string q_c_string;
ssh_string q_s_string;
+ ssh_string server_pubkey_blob = NULL;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
+ int ok;
int rc;
/* Extract the client pubkey from the init packet */
@@ -194,8 +212,8 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
ssh_string_free(q_c_string);
/* Build server's keypair */
- rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
- if (rc == 0){
+ ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
+ if (!ok) {
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
@@ -228,9 +246,16 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
goto error;
}
+ rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
+ if (rc != 0) {
+ ssh_set_error(session, SSH_FATAL, "Could not export server public key");
+ goto error;
+ }
+
/* add host's public key */
rc = ssh_buffer_add_ssh_string(session->out_buffer,
- session->next_crypto->server_pubkey);
+ server_pubkey_blob);
+ ssh_string_free(server_pubkey_blob);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
diff --git a/src/dh.c b/src/dh.c
index 0339be0..e0d2965 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -68,6 +68,7 @@
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/err.h>
+#include "libssh/libcrypto.h"
#endif
static unsigned char p_group1_value[] = {
@@ -115,115 +116,87 @@ static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */
static bignum g;
static bignum p_group1;
static bignum p_group14;
-static int ssh_crypto_initialized;
+static int dh_crypto_initialized;
static bignum select_p(enum ssh_key_exchange_e type) {
return type == SSH_KEX_DH_GROUP14_SHA1 ? p_group14 : p_group1;
}
-int ssh_get_random(void *where, int len, int strong){
-
-#ifdef HAVE_LIBGCRYPT
- /* variable not used in gcrypt */
- (void) strong;
- /* not using GCRY_VERY_STRONG_RANDOM which is a bit overkill */
- gcry_randomize(where,len,GCRY_STRONG_RANDOM);
-
- return 1;
-#elif defined HAVE_LIBCRYPTO
- if (strong) {
- return RAND_bytes(where,len);
- } else {
- return RAND_pseudo_bytes(where,len);
- }
-#endif
-
- /* never reached */
- return 1;
-}
-
-
-/*
- * This inits the values g and p which are used for DH key agreement
- * FIXME: Make the function thread safe by adding a semaphore or mutex.
+/**
+ * @internal
+ * @brief Initialize global constants used in DH key agreement
+ * @return SSH_OK on success, SSH_ERROR otherwise.
*/
-int ssh_crypto_init(void) {
- if (ssh_crypto_initialized == 0) {
-#ifdef HAVE_LIBGCRYPT
- gcry_check_version(NULL);
- if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P,0)) {
- gcry_control(GCRYCTL_INIT_SECMEM, 4096);
- gcry_control(GCRYCTL_INITIALIZATION_FINISHED,0);
+int ssh_dh_init(void)
+{
+ if (dh_crypto_initialized) {
+ return SSH_OK;
}
-#endif
g = bignum_new();
if (g == NULL) {
- return -1;
+ return SSH_ERROR;
}
bignum_set_word(g,g_int);
-#ifdef HAVE_LIBGCRYPT
+#if defined(HAVE_LIBGCRYPT)
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, &p_group1);
if (p_group1 == NULL) {
- bignum_free(g);
- g = NULL;
- return -1;
+ bignum_safe_free(g);
+
+ return SSH_ERROR;
}
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14);
if (p_group14 == NULL) {
- bignum_free(g);
- bignum_free(p_group1);
- g = NULL;
- p_group1 = NULL;
- return -1;
- }
+ bignum_safe_free(g);
+ bignum_safe_free(p_group1);
-#elif defined HAVE_LIBCRYPTO
+ return SSH_ERROR;
+ }
+#elif defined(HAVE_LIBCRYPTO)
p_group1 = bignum_new();
if (p_group1 == NULL) {
- bignum_free(g);
- g = NULL;
- return -1;
+ bignum_safe_free(g);
+
+ return SSH_ERROR;
}
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
p_group14 = bignum_new();
if (p_group14 == NULL) {
- bignum_free(g);
- bignum_free(p_group1);
- g = NULL;
- p_group1 = NULL;
- return -1;
+ bignum_safe_free(g);
+ bignum_safe_free(p_group1);
+
+ return SSH_ERROR;
}
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
+#elif defined(HAVE_LIBMBEDCRYPTO)
+ p_group1 = bignum_new();
+ bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
- OpenSSL_add_all_algorithms();
-
+ p_group14 = bignum_new();
+ bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
#endif
+ dh_crypto_initialized = 1;
- ssh_crypto_initialized = 1;
- }
-
- return 0;
+ return 0;
}
-void ssh_crypto_finalize(void) {
- if (ssh_crypto_initialized) {
- bignum_free(g);
- g = NULL;
- bignum_free(p_group1);
- p_group1 = NULL;
- bignum_free(p_group14);
- p_group14 = NULL;
-#ifdef HAVE_LIBGCRYPT
- gcry_control(GCRYCTL_TERM_SECMEM);
-#elif defined HAVE_LIBCRYPTO
- EVP_cleanup();
- CRYPTO_cleanup_all_ex_data();
-#endif
- ssh_crypto_initialized=0;
- }
+/**
+ * @internal
+ * @brief Finalize and free global constants used in DH key agreement
+ */
+void ssh_dh_finalize(void)
+{
+ if (!dh_crypto_initialized) {
+ return;
+ }
+
+ bignum_safe_free(g);
+ bignum_safe_free(p_group1);
+ bignum_safe_free(p_group14);
+
+ dh_crypto_initialized = 0;
}
int ssh_dh_generate_x(ssh_session session) {
@@ -238,11 +211,7 @@ int ssh_dh_generate_x(ssh_session session) {
return -1;
}
-#ifdef HAVE_LIBGCRYPT
bignum_rand(session->next_crypto->x, keysize);
-#elif defined HAVE_LIBCRYPTO
- bignum_rand(session->next_crypto->x, keysize, -1, 0);
-#endif
/* not harder than this */
#ifdef DEBUG_CRYPTO
@@ -265,11 +234,7 @@ int ssh_dh_generate_y(ssh_session session) {
return -1;
}
-#ifdef HAVE_LIBGCRYPT
bignum_rand(session->next_crypto->y, keysize);
-#elif defined HAVE_LIBCRYPTO
- bignum_rand(session->next_crypto->y, keysize, -1, 0);
-#endif
/* not harder than this */
#ifdef DEBUG_CRYPTO
@@ -302,6 +267,9 @@ int ssh_dh_generate_e(ssh_session session) {
#elif defined HAVE_LIBCRYPTO
bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
select_p(session->next_crypto->kex_type), ctx);
+#elif defined HAVE_LIBMBEDCRYPTO
+ bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
+ select_p(session->next_crypto->kex_type), NULL);
#endif
#ifdef DEBUG_CRYPTO
@@ -337,6 +305,9 @@ int ssh_dh_generate_f(ssh_session session) {
#elif defined HAVE_LIBCRYPTO
bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
select_p(session->next_crypto->kex_type), ctx);
+#elif defined HAVE_LIBMBEDCRYPTO
+ bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
+ select_p(session->next_crypto->kex_type), NULL);
#endif
#ifdef DEBUG_CRYPTO
@@ -359,8 +330,17 @@ ssh_string ssh_dh_get_f(ssh_session session) {
return ssh_make_bignum_string(session->next_crypto->f);
}
-void ssh_dh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
- session->next_crypto->server_pubkey = pubkey_string;
+int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
+{
+ return ssh_pki_import_pubkey_blob(pubkey_blob,
+ &session->current_crypto->server_pubkey);
+}
+
+int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
+{
+ return ssh_pki_import_pubkey_blob(pubkey_blob,
+ &session->next_crypto->server_pubkey);
+
}
int ssh_dh_import_f(ssh_session session, ssh_string f_string) {
@@ -423,6 +403,14 @@ int ssh_dh_build_k(ssh_session session) {
bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
session->next_crypto->y, select_p(session->next_crypto->kex_type), ctx);
}
+#elif defined HAVE_LIBMBEDCRYPTO
+ if (session->client) {
+ bignum_mod_exp(session->next_crypto->k, session->next_crypto->f,
+ session->next_crypto->x, select_p(session->next_crypto->kex_type), NULL);
+ } else {
+ bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
+ session->next_crypto->y, select_p(session->next_crypto->kex_type), NULL);
+ }
#endif
#ifdef DEBUG_CRYPTO
@@ -481,15 +469,21 @@ int ssh_client_dh_init(ssh_session session){
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){
ssh_string f;
- ssh_string pubkey = NULL;
+ ssh_string pubkey_blob = NULL;
ssh_string signature = NULL;
int rc;
- pubkey = ssh_buffer_get_ssh_string(packet);
- if (pubkey == NULL){
+
+ pubkey_blob = ssh_buffer_get_ssh_string(packet);
+ if (pubkey_blob == NULL){
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
- ssh_dh_import_pubkey(session, pubkey);
+
+ rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
+ ssh_string_free(pubkey_blob);
+ if (rc != 0) {
+ goto error;
+ }
f = ssh_buffer_get_ssh_string(packet);
if (f == NULL) {
@@ -533,6 +527,7 @@ int ssh_make_sessionid(ssh_session session) {
ssh_buffer server_hash = NULL;
ssh_buffer client_hash = NULL;
ssh_buffer buf = NULL;
+ ssh_string server_pubkey_blob = NULL;
int rc = SSH_ERROR;
buf = ssh_buffer_new();
@@ -583,6 +578,11 @@ int ssh_make_sessionid(ssh_session session) {
}
}
+ rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
+ if (rc != SSH_OK) {
+ goto error;
+ }
+
rc = ssh_buffer_pack(buf,
"dPdPS",
ssh_buffer_get_len(client_hash),
@@ -591,8 +591,8 @@ int ssh_make_sessionid(ssh_session session) {
ssh_buffer_get_len(server_hash),
ssh_buffer_get_len(server_hash),
ssh_buffer_get(server_hash),
- session->next_crypto->server_pubkey);
-
+ server_pubkey_blob);
+ ssh_string_free(server_pubkey_blob);
if(rc != SSH_OK){
goto error;
}
@@ -625,7 +625,8 @@ int ssh_make_sessionid(ssh_session session) {
}
#endif
#ifdef HAVE_CURVE25519
- } else if (session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG) {
+ } else if ((session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256) ||
+ (session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG)) {
rc = ssh_buffer_pack(buf,
"dPdP",
CURVE25519_PUBKEY_SIZE,
@@ -661,6 +662,7 @@ int ssh_make_sessionid(ssh_session session) {
session->next_crypto->secret_hash);
break;
case SSH_KEX_ECDH_SHA2_NISTP256:
+ case SSH_KEX_CURVE25519_SHA256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA256;
@@ -729,11 +731,20 @@ error:
}
int ssh_hashbufout_add_cookie(ssh_session session) {
+ int rc;
+
session->out_hashbuf = ssh_buffer_new();
if (session->out_hashbuf == NULL) {
return -1;
}
+ rc = ssh_buffer_allocate_size(session->out_hashbuf,
+ sizeof(uint8_t) + 16);
+ if (rc < 0) {
+ ssh_buffer_reinit(session->out_hashbuf);
+ return -1;
+ }
+
if (ssh_buffer_add_u8(session->out_hashbuf, 20) < 0) {
ssh_buffer_reinit(session->out_hashbuf);
return -1;
@@ -757,11 +768,20 @@ int ssh_hashbufout_add_cookie(ssh_session session) {
}
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
+ int rc;
+
session->in_hashbuf = ssh_buffer_new();
if (session->in_hashbuf == NULL) {
return -1;
}
+ rc = ssh_buffer_allocate_size(session->in_hashbuf,
+ sizeof(uint8_t) + 20 + 16);
+ if (rc < 0) {
+ ssh_buffer_reinit(session->in_hashbuf);
+ return -1;
+ }
+
if (ssh_buffer_add_u8(session->in_hashbuf, 20) < 0) {
ssh_buffer_reinit(session->in_hashbuf);
return -1;
@@ -923,39 +943,55 @@ error:
* @deprecated Use ssh_get_publickey_hash()
*/
int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
- ssh_string pubkey;
- MD5CTX ctx;
- unsigned char *h;
+ ssh_key pubkey = NULL;
+ ssh_string pubkey_blob = NULL;
+ MD5CTX ctx;
+ unsigned char *h;
+ int rc;
- if (session == NULL || hash == NULL) {
- return SSH_ERROR;
- }
- *hash = NULL;
- if (session->current_crypto == NULL ||
- session->current_crypto->server_pubkey == NULL){
- ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
- return SSH_ERROR;
- }
+ if (session == NULL || hash == NULL) {
+ return SSH_ERROR;
+ }
+ *hash = NULL;
+ if (session->current_crypto == NULL ||
+ session->current_crypto->server_pubkey == NULL) {
+ ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
+ return SSH_ERROR;
+ }
- h = malloc(sizeof(unsigned char) * MD5_DIGEST_LEN);
- if (h == NULL) {
- return SSH_ERROR;
- }
+ h = calloc(MD5_DIGEST_LEN, sizeof(unsigned char));
+ if (h == NULL) {
+ return SSH_ERROR;
+ }
- ctx = md5_init();
- if (ctx == NULL) {
- SAFE_FREE(h);
- return SSH_ERROR;
- }
+ ctx = md5_init();
+ if (ctx == NULL) {
+ SAFE_FREE(h);
+ return SSH_ERROR;
+ }
- pubkey = session->current_crypto->server_pubkey;
+ rc = ssh_get_server_publickey(session, &pubkey);
+ if (rc != SSH_OK) {
+ md5_final(h, ctx);
+ SAFE_FREE(h);
+ return SSH_ERROR;
+ }
+
+ rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob);
+ ssh_key_free(pubkey);
+ if (rc != SSH_OK) {
+ md5_final(h, ctx);
+ SAFE_FREE(h);
+ return SSH_ERROR;
+ }
- md5_update(ctx, ssh_string_data(pubkey), ssh_string_len(pubkey));
- md5_final(h, ctx);
+ md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob));
+ ssh_string_free(pubkey_blob);
+ md5_final(h, ctx);
- *hash = h;
+ *hash = h;
- return MD5_DIGEST_LEN;
+ return MD5_DIGEST_LEN;
}
/**
@@ -987,14 +1023,49 @@ void ssh_clean_pubkey_hash(unsigned char **hash) {
*/
int ssh_get_server_publickey(ssh_session session, ssh_key *key)
{
- if (session==NULL ||
- session->current_crypto ==NULL ||
+ ssh_key pubkey = NULL;
+
+ if (session == NULL ||
+ session->current_crypto == NULL ||
session->current_crypto->server_pubkey == NULL) {
return SSH_ERROR;
}
- return ssh_pki_import_pubkey_blob(session->current_crypto->server_pubkey,
- key);
+ pubkey = ssh_key_dup(session->current_crypto->server_pubkey);
+ if (pubkey == NULL) {
+ return SSH_ERROR;
+ }
+
+ *key = pubkey;
+ return SSH_OK;
+}
+
+ssh_key ssh_dh_get_current_server_publickey(ssh_session session)
+{
+ return session->current_crypto->server_pubkey;
+}
+
+/* Caller need to free the blob */
+int ssh_dh_get_current_server_publickey_blob(ssh_session session,
+ ssh_string *pubkey_blob)
+{
+ const ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
+
+ return ssh_pki_export_pubkey_blob(pubkey, pubkey_blob);
+}
+
+ssh_key ssh_dh_get_next_server_publickey(ssh_session session)
+{
+ return session->next_crypto->server_pubkey;
+}
+
+/* Caller need to free the blob */
+int ssh_dh_get_next_server_publickey_blob(ssh_session session,
+ ssh_string *pubkey_blob)
+{
+ const ssh_key pubkey = ssh_dh_get_next_server_publickey(session);
+
+ return ssh_pki_export_pubkey_blob(pubkey, pubkey_blob);
}
/**
@@ -1028,7 +1099,7 @@ int ssh_get_publickey(ssh_session session, ssh_key *key)
* you at making things secure.
* OpenSSH uses SHA1 to print public key digests.
*
- * @see ssh_is_server_known()
+ * @see ssh_session_update_known_hosts()
* @see ssh_get_hexa()
* @see ssh_print_hexa()
* @see ssh_clean_pubkey_hash()
@@ -1164,5 +1235,3 @@ void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
}
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/ecdh.c b/src/ecdh.c
index ada7b18..f7fcaf1 100644
--- a/src/ecdh.c
+++ b/src/ecdh.c
@@ -30,25 +30,27 @@
#ifdef HAVE_ECDH
-static void ecdh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
- session->next_crypto->server_pubkey = pubkey_string;
-}
-
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
*/
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
ssh_string q_s_string = NULL;
- ssh_string pubkey = NULL;
+ ssh_string pubkey_blob = NULL;
ssh_string signature = NULL;
int rc;
- pubkey = ssh_buffer_get_ssh_string(packet);
- if (pubkey == NULL){
+
+ pubkey_blob = ssh_buffer_get_ssh_string(packet);
+ if (pubkey_blob == NULL) {
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
- ecdh_import_pubkey(session, pubkey);
+
+ rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
+ ssh_string_free(pubkey_blob);
+ if (rc != 0) {
+ goto error;
+ }
q_s_string = ssh_buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
diff --git a/src/ecdh_crypto.c b/src/ecdh_crypto.c
index 041e6c0..24f21c0 100644
--- a/src/ecdh_crypto.c
+++ b/src/ecdh_crypto.c
@@ -206,6 +206,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
+ ssh_string pubkey_blob = NULL;
int curve;
int len;
int rc;
@@ -289,14 +290,22 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
return SSH_ERROR;
}
+ rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
+ if (rc != SSH_OK) {
+ ssh_set_error(session, SSH_FATAL, "Could not export server public key");
+ ssh_string_free(sig_blob);
+ return SSH_ERROR;
+ }
+
rc = ssh_buffer_pack(session->out_buffer,
"bSSS",
SSH2_MSG_KEXDH_REPLY,
- session->next_crypto->server_pubkey, /* host's pubkey */
+ pubkey_blob, /* host's pubkey */
q_s_string, /* ecdh public key */
sig_blob); /* signature blob */
ssh_string_free(sig_blob);
+ ssh_string_free(pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
diff --git a/src/ecdh_gcrypt.c b/src/ecdh_gcrypt.c
index f743080..7bbccc2 100644
--- a/src/ecdh_gcrypt.c
+++ b/src/ecdh_gcrypt.c
@@ -214,7 +214,7 @@ int ecdh_build_k(ssh_session session)
goto out;
}
- if (ssh_string_len(s) != k_length) {
+ if (ssh_string_len(s) != k_len) {
ssh_string_burn(s);
ssh_string_free(s);
goto out;
@@ -223,7 +223,7 @@ int ecdh_build_k(ssh_session session)
err = gcry_mpi_scan(&session->next_crypto->k,
GCRYMPI_FMT_USG,
(const char *)ssh_string_data(s) + 1,
- k_length / 2,
+ k_len / 2,
NULL);
ssh_string_burn(s);
ssh_string_free(s);
@@ -268,6 +268,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) {
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
+ ssh_string pubkey_blob = NULL;
int rc = SSH_ERROR;
const char *curve = NULL;
@@ -333,14 +334,22 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) {
goto out;
}
+ rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
+ if (rc != SSH_OK) {
+ ssh_set_error(session, SSH_FATAL, "Could not export server public key");
+ ssh_string_free(sig_blob);
+ goto out;
+ }
+
rc = ssh_buffer_pack(session->out_buffer,
"bSSS",
SSH2_MSG_KEXDH_REPLY,
- session->next_crypto->server_pubkey, /* host's pubkey */
+ pubkey_blob, /* host's pubkey */
q_s_string, /* ecdh public key */
sig_blob); /* signature blob */
ssh_string_free(sig_blob);
+ ssh_string_free(pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
diff --git a/src/ecdh_mbedcrypto.c b/src/ecdh_mbedcrypto.c
new file mode 100644
index 0000000..aebc7ba
--- /dev/null
+++ b/src/ecdh_mbedcrypto.c
@@ -0,0 +1,305 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "libssh/session.h"
+#include "libssh/ecdh.h"
+#include "libssh/buffer.h"
+#include "libssh/ssh2.h"
+#include "libssh/dh.h"
+#include "libssh/pki.h"
+#include "libssh/bignum.h"
+#include "libssh/libmbedcrypto.h"
+
+#include <mbedtls/ecdh.h>
+#include <mbedtls/ecp.h>
+
+#ifdef HAVE_ECDH
+
+static mbedtls_ecp_group_id ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
+ if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
+ return MBEDTLS_ECP_DP_SECP256R1;
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
+ return MBEDTLS_ECP_DP_SECP384R1;
+ } else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
+ return MBEDTLS_ECP_DP_SECP521R1;
+ }
+
+ return MBEDTLS_ECP_DP_NONE;
+}
+int ssh_client_ecdh_init(ssh_session session)
+{
+ ssh_string client_pubkey = NULL;
+ mbedtls_ecp_group grp;
+ int rc;
+ mbedtls_ecp_group_id curve;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == MBEDTLS_ECP_DP_NONE) {
+ return SSH_ERROR;
+ }
+
+ rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
+ if (rc < 0) {
+ return SSH_ERROR;
+ }
+
+ session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
+ if (session->next_crypto->ecdh_privkey == NULL) {
+ return SSH_ERROR;
+ }
+
+ mbedtls_ecp_keypair_init(session->next_crypto->ecdh_privkey);
+ mbedtls_ecp_group_init(&grp);
+
+ rc = mbedtls_ecp_group_load(&grp, curve);
+ if (rc != 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ rc = mbedtls_ecp_gen_keypair(&grp, &session->next_crypto->ecdh_privkey->d,
+ &session->next_crypto->ecdh_privkey->Q, mbedtls_ctr_drbg_random,
+ &ssh_mbedtls_ctr_drbg);
+
+ if (rc != 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ client_pubkey = make_ecpoint_string(&grp,
+ &session->next_crypto->ecdh_privkey->Q);
+ if (client_pubkey == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ rc = ssh_buffer_add_ssh_string(session->out_buffer, client_pubkey);
+ if (rc < 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ session->next_crypto->ecdh_client_pubkey = client_pubkey;
+ client_pubkey = NULL;
+
+ rc = ssh_packet_send(session);
+
+out:
+ mbedtls_ecp_group_free(&grp);
+ ssh_string_free(client_pubkey);
+
+ return rc;
+}
+
+int ecdh_build_k(ssh_session session)
+{
+ mbedtls_ecp_group grp;
+ mbedtls_ecp_point pubkey;
+ int rc;
+ mbedtls_ecp_group_id curve;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == MBEDTLS_ECP_DP_NONE) {
+ return SSH_ERROR;
+ }
+
+ mbedtls_ecp_group_init(&grp);
+ mbedtls_ecp_point_init(&pubkey);
+
+ rc = mbedtls_ecp_group_load(&grp, curve);
+ if (rc != 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ if (session->server) {
+ rc = mbedtls_ecp_point_read_binary(&grp, &pubkey,
+ ssh_string_data(session->next_crypto->ecdh_client_pubkey),
+ ssh_string_len(session->next_crypto->ecdh_client_pubkey));
+ } else {
+ rc = mbedtls_ecp_point_read_binary(&grp, &pubkey,
+ ssh_string_data(session->next_crypto->ecdh_server_pubkey),
+ ssh_string_len(session->next_crypto->ecdh_server_pubkey));
+ }
+
+ if (rc != 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ session->next_crypto->k = malloc(sizeof(mbedtls_mpi));
+ if (session->next_crypto->k == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ mbedtls_mpi_init(session->next_crypto->k);
+
+ rc = mbedtls_ecdh_compute_shared(&grp, session->next_crypto->k, &pubkey,
+ &session->next_crypto->ecdh_privkey->d, mbedtls_ctr_drbg_random,
+ &ssh_mbedtls_ctr_drbg);
+ if (rc != 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+out:
+ mbedtls_ecp_keypair_free(session->next_crypto->ecdh_privkey);
+ SAFE_FREE(session->next_crypto->ecdh_privkey);
+ mbedtls_ecp_group_free(&grp);
+ mbedtls_ecp_point_free(&pubkey);
+ return rc;
+}
+
+#ifdef WITH_SERVER
+int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet)
+{
+ ssh_string q_c_string = NULL;
+ ssh_string q_s_string = NULL;
+ mbedtls_ecp_group grp;
+ ssh_key privkey = NULL;
+ ssh_string sig_blob = NULL;
+ ssh_string pubkey_blob = NULL;
+ int rc;
+ mbedtls_ecp_group_id curve;
+
+ curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
+ if (curve == MBEDTLS_ECP_DP_NONE) {
+ return SSH_ERROR;
+ }
+
+ q_c_string = ssh_buffer_get_ssh_string(packet);
+ if (q_c_string == NULL) {
+ ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet");
+ return SSH_ERROR;
+ }
+
+ session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
+ if (session->next_crypto->ecdh_privkey == NULL) {
+ ssh_set_error_oom(session);
+ return SSH_ERROR;
+ }
+
+ session->next_crypto->ecdh_client_pubkey = q_c_string;
+
+ mbedtls_ecp_group_init(&grp);
+ mbedtls_ecp_keypair_init(session->next_crypto->ecdh_privkey);
+
+ rc = mbedtls_ecp_group_load(&grp, curve);
+ if (rc != 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ rc = mbedtls_ecp_gen_keypair(&grp, &session->next_crypto->ecdh_privkey->d,
+ &session->next_crypto->ecdh_privkey->Q, mbedtls_ctr_drbg_random,
+ &ssh_mbedtls_ctr_drbg);
+ if (rc != 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ q_s_string = make_ecpoint_string(&grp, &session->next_crypto->ecdh_privkey->Q);
+ if (q_s_string == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ session->next_crypto->ecdh_server_pubkey = q_s_string;
+
+ /* build k and session_id */
+ rc = ecdh_build_k(session);
+ if (rc != SSH_OK) {
+ ssh_set_error(session, SSH_FATAL, "Cannot build k number");
+ goto out;
+ }
+
+ /* privkey is not allocated */
+ rc = ssh_get_key_params(session, &privkey);
+ if (rc == SSH_ERROR) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ rc = ssh_make_sessionid(session);
+ if (rc != SSH_OK) {
+ ssh_set_error(session, SSH_FATAL, "Could not create a session id");
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
+ if (sig_blob == NULL) {
+ ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
+ if (rc != SSH_OK) {
+ ssh_set_error(session, SSH_FATAL, "Could not export server public key");
+ ssh_string_free(sig_blob);
+ goto out;
+ }
+
+ rc = ssh_buffer_pack(session->out_buffer, "bSSS",
+ SSH2_MSG_KEXDH_REPLY,
+ pubkey_blob, /* host's pubkey */
+ q_s_string, /* ecdh public key */
+ sig_blob); /* signature blob */
+
+ ssh_string_free(sig_blob);
+ ssh_string_free(pubkey_blob);
+
+ if (rc != SSH_OK) {
+ ssh_set_error_oom(session);
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
+ rc = ssh_packet_send(session);
+ if (rc != SSH_OK) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
+ if (rc < 0) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
+ rc = ssh_packet_send(session);
+ SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
+
+out:
+ mbedtls_ecp_group_free(&grp);
+ return rc;
+}
+
+#endif /* WITH_SERVER */
+#endif
diff --git a/src/error.c b/src/error.c
index bd755c4..aa0f462 100644
--- a/src/error.c
+++ b/src/error.c
@@ -21,6 +21,8 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdarg.h>
#include "libssh/priv.h"
@@ -135,5 +137,3 @@ int ssh_get_error_code(void *error) {
}
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/external/bcrypt_pbkdf.c b/src/external/bcrypt_pbkdf.c
index 5586881..6fb35ff 100644
--- a/src/external/bcrypt_pbkdf.c
+++ b/src/external/bcrypt_pbkdf.c
@@ -19,6 +19,8 @@
#ifndef HAVE_BCRYPT_PBKDF
+#include "config.h"
+
#include "libssh/priv.h"
#include "libssh/wrapper.h"
#include <stdlib.h>
@@ -96,8 +98,8 @@ bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out)
}
/* zap */
- BURN_BUFFER(ciphertext, sizeof(ciphertext));
- BURN_BUFFER(cdata, sizeof(cdata));
+ explicit_bzero(ciphertext, sizeof(ciphertext));
+ explicit_bzero(cdata, sizeof(cdata));
ZERO_STRUCT(state);
}
@@ -173,7 +175,7 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, size_t saltl
}
/* zap */
- BURN_BUFFER(out, sizeof(out));
+ explicit_bzero(out, sizeof(out));
free(countsalt);
return 0;
diff --git a/src/external/chacha.c b/src/external/chacha.c
new file mode 100644
index 0000000..e47a632
--- /dev/null
+++ b/src/external/chacha.c
@@ -0,0 +1,218 @@
+/*
+chacha-merged.c version 20080118
+D. J. Bernstein
+Public domain.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include "libssh/chacha.h"
+
+typedef unsigned int uint32_t;
+
+typedef struct chacha_ctx chacha_ctx;
+
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((uint8_t)(v) & U8C(0xFF))
+#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF))
+
+#define ROTL32(v, n) \
+ (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define U8TO32_LITTLE(p) \
+ (((uint32_t)((p)[0]) ) | \
+ ((uint32_t)((p)[1]) << 8) | \
+ ((uint32_t)((p)[2]) << 16) | \
+ ((uint32_t)((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[16] = "expand 32-byte k";
+static const char tau[16] = "expand 16-byte k";
+
+void
+chacha_keysetup(chacha_ctx *x,const uint8_t *k,uint32_t 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 uint8_t *iv, const uint8_t *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 uint8_t *m,uint8_t *c,uint32_t bytes)
+{
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+ uint8_t *ctarget = NULL;
+ uint8_t tmp[64];
+ uint32_t 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/src/external/ed25519.c b/src/external/ed25519.c
index 2ae0ef4..b0d9b15 100644
--- a/src/external/ed25519.c
+++ b/src/external/ed25519.c
@@ -85,10 +85,10 @@ int crypto_sign_ed25519_keypair(unsigned char *pk,
SHA512CTX ctx;
unsigned char extsk[64];
int i;
- int rc;
+ int ok;
- rc = ssh_get_random(sk, 32, 0);
- if (rc < 0){
+ ok = ssh_get_random(sk, 32, 0);
+ if (!ok) {
return -1;
}
diff --git a/src/external/fe25519.c b/src/external/fe25519.c
index db31f65..2b0b673 100644
--- a/src/external/fe25519.c
+++ b/src/external/fe25519.c
@@ -4,6 +4,8 @@
* Copied from supercop-20130419/crypto_sign/ed25519/ref/fe25519.c
*/
+#include "config.h"
+
#define WINDOWSIZE 1 /* Should be 1,2, or 4 */
#define WINDOWMASK ((1<<WINDOWSIZE)-1)
diff --git a/src/external/ge25519.c b/src/external/ge25519.c
index b098cc5..ffeb1d5 100644
--- a/src/external/ge25519.c
+++ b/src/external/ge25519.c
@@ -6,6 +6,8 @@
* Copied from supercop-20130419/crypto_sign/ed25519/ref/ge25519.c
*/
+#include "config.h"
+
#include "libssh/fe25519.h"
#include "libssh/sc25519.h"
#include "libssh/ge25519.h"
diff --git a/src/external/poly1305.c b/src/external/poly1305.c
new file mode 100644
index 0000000..916dd62
--- /dev/null
+++ b/src/external/poly1305.c
@@ -0,0 +1,156 @@
+/*
+ * Public Domain poly1305 from Andrew Moon
+ * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "libssh/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,t1,t2,t3;
+ uint32_t h0,h1,h2,h3,h4;
+ uint32_t r0,r1,r2,r3,r4;
+ uint32_t s1,s2,s3,s4;
+ uint32_t b, nb;
+ size_t j;
+ uint64_t t[5];
+ uint64_t f0,f1,f2,f3;
+ uint32_t g0,g1,g2,g3,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 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
+ h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
+ h3 += ((((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 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
+ h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
+ h3 += ((((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/src/external/sc25519.c b/src/external/sc25519.c
index c7a02ee..5f198d5 100644
--- a/src/external/sc25519.c
+++ b/src/external/sc25519.c
@@ -4,6 +4,8 @@
* Copied from supercop-20130419/crypto_sign/ed25519/ref/sc25519.c
*/
+#include "config.h"
+
#include "libssh/priv.h"
#include "libssh/sc25519.h"
diff --git a/src/gcrypt_missing.c b/src/gcrypt_missing.c
index e07843b..8056231 100644
--- a/src/gcrypt_missing.c
+++ b/src/gcrypt_missing.c
@@ -21,6 +21,8 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <stdlib.h>
#include "libssh/priv.h"
@@ -70,7 +72,7 @@ char *ssh_gcry_bn2dec(bignum bn) {
num = bignum_new();
if (num == NULL) {
SAFE_FREE(ret);
- bignum_free(ten);
+ bignum_safe_free(ten);
return NULL;
}
@@ -89,13 +91,12 @@ char *ssh_gcry_bn2dec(bignum bn) {
ret[count2] = ret[count2 + count];
}
ret[count2] = 0;
- bignum_free(num);
- bignum_free(bndup);
- bignum_free(ten);
+ bignum_safe_free(num);
+ bignum_safe_free(bndup);
+ bignum_safe_free(ten);
}
return ret;
}
#endif
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/getpass.c b/src/getpass.c
index c36f263..68dd1d4 100644
--- a/src/getpass.c
+++ b/src/getpass.c
@@ -284,5 +284,3 @@ int ssh_getpass(const char *prompt,
}
#endif
-
-/* vim: set ts=4 sw=4 et cindent syntax=c.doxygen: */
diff --git a/src/gssapi.c b/src/gssapi.c
index 957eb57..8e62f6a 100644
--- a/src/gssapi.c
+++ b/src/gssapi.c
@@ -763,20 +763,27 @@ int ssh_gssapi_auth_mic(ssh_session session){
}
static gss_OID ssh_gssapi_oid_from_string(ssh_string oid_s){
- gss_OID ret = malloc(sizeof (gss_OID_desc));
+ gss_OID ret;
unsigned char *data = ssh_string_data(oid_s);
size_t len = ssh_string_len(oid_s);
- if(len > 256 || len <= 2){
+
+ ret = malloc(sizeof(gss_OID_desc));
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (len > 256 || len <= 2) {
SAFE_FREE(ret);
return NULL;
}
- if(data[0] != SSH_OID_TAG || data[1] != len - 2){
+ if (data[0] != SSH_OID_TAG || data[1] != len - 2) {
SAFE_FREE(ret);
return NULL;
}
ret->elements = malloc(len - 2);
memcpy(ret->elements, &data[2], len-2);
ret->length = len-2;
+
return ret;
}
@@ -792,18 +799,19 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
SSH_LOG(SSH_LOG_PACKET, "Received SSH_USERAUTH_GSSAPI_RESPONSE");
if (session->auth_state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT){
ssh_set_error(session, SSH_FATAL, "Invalid state in ssh_packet_userauth_gssapi_response");
- return SSH_PACKET_USED;
+ goto error;
}
+
oid_s = ssh_buffer_get_ssh_string(packet);
if (!oid_s){
ssh_set_error(session, SSH_FATAL, "Missing OID");
- return SSH_PACKET_USED;
+ goto error;
}
session->gssapi->client.oid = ssh_gssapi_oid_from_string(oid_s);
ssh_string_free(oid_s);
if (!session->gssapi->client.oid) {
ssh_set_error(session, SSH_FATAL, "Invalid OID");
- return SSH_PACKET_USED;
+ goto error;
}
session->gssapi->client.flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
@@ -825,11 +833,11 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
"Initializing gssapi context",
maj_stat,
min_stat);
- return SSH_PACKET_USED;
+ goto error;
}
if (output_token.length != 0){
hexa = ssh_get_hexa(output_token.value, output_token.length);
- SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa);
+ SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s", hexa);
SAFE_FREE(hexa);
ssh_buffer_pack(session->out_buffer,
"bdP",
@@ -840,6 +848,12 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN;
}
return SSH_PACKET_USED;
+
+error:
+ session->auth_state = SSH_AUTH_STATE_ERROR;
+ ssh_gssapi_free(session);
+ session->gssapi = NULL;
+ return SSH_PACKET_USED;
}
static int ssh_gssapi_send_mic(ssh_session session){
@@ -859,7 +873,8 @@ static int ssh_gssapi_send_mic(ssh_session session){
mic_buf.length = ssh_buffer_get_len(mic_buffer);
mic_buf.value = ssh_buffer_get(mic_buffer);
- maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT, &mic_buf, &mic_token_buf);
+ maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT,
+ &mic_buf, &mic_token_buf);
if (GSS_ERROR(maj_stat)){
ssh_buffer_free(mic_buffer);
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
@@ -892,16 +907,19 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
(void)type;
SSH_LOG(SSH_LOG_PACKET,"Received SSH_MSG_USERAUTH_GSSAPI_TOKEN");
- if (!session->gssapi || session->auth_state != SSH_AUTH_STATE_GSSAPI_TOKEN){
- ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_USERAUTH_GSSAPI_TOKEN in invalid state");
- return SSH_PACKET_USED;
+ if (!session->gssapi || session->auth_state != SSH_AUTH_STATE_GSSAPI_TOKEN) {
+ ssh_set_error(session, SSH_FATAL,
+ "Received SSH_MSG_USERAUTH_GSSAPI_TOKEN in invalid state");
+ goto error;
}
token = ssh_buffer_get_ssh_string(packet);
if (token == NULL){
- ssh_set_error(session, SSH_REQUEST_DENIED, "ssh_packet_userauth_gssapi_token: invalid packet");
- return SSH_PACKET_USED;
+ ssh_set_error(session, SSH_REQUEST_DENIED,
+ "ssh_packet_userauth_gssapi_token: invalid packet");
+ goto error;
}
+
hexa = ssh_get_hexa(ssh_string_data(token),ssh_string_len(token));
SSH_LOG(SSH_LOG_PACKET, "GSSAPI Token : %s",hexa);
SAFE_FREE(hexa);
@@ -926,12 +944,10 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
"Gssapi error",
maj_stat,
min_stat);
- ssh_gssapi_free(session);
- session->gssapi=NULL;
- return SSH_PACKET_USED;
+ goto error;
}
- if (output_token.length != 0){
+ if (output_token.length != 0) {
hexa = ssh_get_hexa(output_token.value, output_token.length);
SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa);
SAFE_FREE(hexa);
@@ -942,9 +958,17 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
(size_t)output_token.length, output_token.value);
ssh_packet_send(session);
}
- if(maj_stat == GSS_S_COMPLETE){
+
+ if (maj_stat == GSS_S_COMPLETE) {
session->auth_state = SSH_AUTH_STATE_NONE;
ssh_gssapi_send_mic(session);
}
+
+ return SSH_PACKET_USED;
+
+error:
+ session->auth_state = SSH_AUTH_STATE_ERROR;
+ ssh_gssapi_free(session);
+ session->gssapi = NULL;
return SSH_PACKET_USED;
}
diff --git a/src/gzip.c b/src/gzip.c
index 73cc331..349d53f 100644
--- a/src/gzip.c
+++ b/src/gzip.c
@@ -217,5 +217,3 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen){
ssh_buffer_free(dest);
return 0;
}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/init.c b/src/init.c
index 241b861..f942243 100644
--- a/src/init.c
+++ b/src/init.c
@@ -32,12 +32,94 @@
#include <winsock2.h>
#endif
+#define CONSTRUCTOR_ATTRIBUTE __attribute__((constructor))
+#define DESTRUCTOR_ATTRIBUTE __attribute__((destructor))
+
+/* Declare static mutex */
+static SSH_MUTEX ssh_init_mutex = SSH_MUTEX_STATIC_INIT;
+
+/* Counter for initializations */
+static int _ssh_initialized = 0;
+
+/* Cache the returned value */
+static int _ssh_init_ret = 0;
+
+void libssh_constructor(void) CONSTRUCTOR_ATTRIBUTE;
+void libssh_destructor(void) DESTRUCTOR_ATTRIBUTE;
+
+static int _ssh_init(unsigned constructor) {
+
+ int rc = 0;
+
+ if (!constructor) {
+ ssh_mutex_lock(&ssh_init_mutex);
+ }
+
+ _ssh_initialized++;
+
+ if (_ssh_initialized > 1) {
+ rc = _ssh_init_ret;
+ goto _ret;
+ }
+
+ rc = ssh_threads_init();
+ if (rc) {
+ goto _ret;
+ }
+
+ rc = ssh_crypto_init();
+ if (rc) {
+ goto _ret;
+ }
+
+ rc = ssh_dh_init();
+ if (rc) {
+ goto _ret;
+ }
+
+ rc = ssh_socket_init();
+ if (rc) {
+ goto _ret;
+ }
+
+_ret:
+ _ssh_init_ret = rc;
+
+ if (!constructor) {
+ ssh_mutex_unlock(&ssh_init_mutex);
+ }
+
+ return rc;
+}
+
+/**
+ * @brief Initialize global cryptographic data structures.
+ *
+ * This functions is automatically called when the library is loaded.
+ *
+ * @returns 0 on success, -1 if an error occured.
+ */
+void libssh_constructor(void)
+{
+
+ int rc;
+
+ rc = _ssh_init(1);
+
+ if (rc < 0) {
+ fprintf(stderr, "Error in auto_init()\n");
+ }
+
+ return;
+}
+
/**
* @defgroup libssh The libssh API
*
* The libssh library is implementing the SSH protocols and some of its
- * extensions. This group of functions is mostly used to implment a SSH client.
- * Some function are needed to implement a SSH server too.
+ * extensions. This group of functions is mostly used to implement an SSH
+ * client.
+ * Some function are needed to implement an SSH server too.
*
* @{
*/
@@ -45,41 +127,98 @@
/**
* @brief Initialize global cryptographic data structures.
*
- * This function should only be called once, at the beginning of the program, in
- * the main thread. It may be omitted if your program is not multithreaded.
+ * Since version 0.8.0, it is not necessary to call this function on systems
+ * which are fully supported with regards to threading (that is, system with
+ * pthreads available).
+ *
+ * If the library is already initialized, increments the _ssh_initialized
+ * counter and return the error code cached in _ssh_init_ret.
*
* @returns 0 on success, -1 if an error occured.
*/
int ssh_init(void) {
- if(ssh_threads_init())
- return -1;
- if(ssh_crypto_init())
- return -1;
- if(ssh_socket_init())
- return -1;
- return 0;
+ return _ssh_init(0);
}
+static int _ssh_finalize(unsigned destructor) {
+
+ if (!destructor) {
+ ssh_mutex_lock(&ssh_init_mutex);
+ }
+
+ if (_ssh_initialized == 1) {
+ _ssh_initialized = 0;
+
+ if (_ssh_init_ret < 0) {
+ goto _ret;
+ }
+
+ ssh_dh_finalize();
+ ssh_crypto_finalize();
+ ssh_socket_cleanup();
+ /* It is important to finalize threading after CRYPTO because
+ * it still depends on it */
+ ssh_threads_finalize();
+
+ }
+ else {
+ if (_ssh_initialized > 0) {
+ _ssh_initialized--;
+ }
+ }
+
+_ret:
+ if (!destructor) {
+ ssh_mutex_unlock(&ssh_init_mutex);
+ }
+ return 0;
+}
/**
* @brief Finalize and cleanup all libssh and cryptographic data structures.
*
- * This function should only be called once, at the end of the program!
+ * This function is automatically called when the library is unloaded.
*
* @returns 0 on succes, -1 if an error occured.
*
- @returns 0 otherwise
*/
-int ssh_finalize(void) {
- ssh_crypto_finalize();
- ssh_socket_cleanup();
- /* It is important to finalize threading after CRYPTO because
- * it still depends on it */
- ssh_threads_finalize();
+void libssh_destructor(void)
+{
+ int rc;
+
+ rc = _ssh_finalize(1);
+
+ if (rc < 0) {
+ fprintf(stderr, "Error in libssh_destructor()\n");
+ }
- return 0;
+ /* Detect if ssh_init() was called without matching ssh_finalize() */
+ if (_ssh_initialized > 0) {
+ fprintf(stderr,
+ "Warning: ssh still initialized; probably ssh_init() "
+ "was called more than once (init count: %d)\n",
+ _ssh_initialized);
+ }
}
-/** @} */
+/**
+ * @brief Finalize and cleanup all libssh and cryptographic data structures.
+ *
+ * Since version 0.8.0, it is not necessary to call this function, since it is
+ * automatically called when the library is unloaded.
+ *
+ * If ssh_init() is called explicitly, then ssh_finalize() must be called
+ * explicitly.
+ *
+ * When called, decrements the counter _ssh_initialized. If the counter reaches
+ * zero, then the libssh and cryptographic data structures are cleaned up.
+ *
+ * @returns 0 on succes, -1 if an error occured.
+ *
+ @returns 0 otherwise
+ */
+int ssh_finalize(void) {
+ return _ssh_finalize(0);
+}
-/* vim: set ts=4 sw=4 et cindent: */
+/** @} */
diff --git a/src/kex.c b/src/kex.c
index 21523fa..6ac59ec 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -36,12 +36,19 @@
#include "libssh/string.h"
#include "libssh/curve25519.h"
#include "libssh/knownhosts.h"
+#include "libssh/misc.h"
#ifdef HAVE_LIBGCRYPT
# define BLOWFISH "blowfish-cbc,"
# define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
# define DES "3des-cbc"
-# define DES_SUPPORTED "3des-cbc,des-cbc-ssh1"
+# define DES_SUPPORTED "3des-cbc"
+
+#elif defined HAVE_LIBMBEDCRYPTO
+# define BLOWFISH "blowfish-cbc,"
+# define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
+# define DES "3des-cbc"
+# define DES_SUPPORTED "3des-cbc"
#elif defined(HAVE_LIBCRYPTO)
@@ -62,7 +69,7 @@
# endif /* HAVE_OPENSSL_AES_H */
# define DES "3des-cbc"
-# define DES_SUPPORTED "3des-cbc,des-cbc-ssh1"
+# define DES_SUPPORTED "3des-cbc"
#endif /* HAVE_LIBCRYPTO */
#ifdef WITH_ZLIB
@@ -72,7 +79,7 @@
#endif
#ifdef HAVE_CURVE25519
-#define CURVE25519 "curve25519-sha256@libssh.org,"
+#define CURVE25519 "curve25519-sha256,curve25519-sha256@libssh.org,"
#else
#define CURVE25519 ""
#endif
@@ -81,10 +88,16 @@
#define ECDH "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
#define HOSTKEYS "ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss"
#else
+#ifdef HAVE_DSA
#define HOSTKEYS "ssh-ed25519,ssh-rsa,ssh-dss"
+#else
+#define HOSTKEYS "ssh-ed25519,ssh-rsa"
+#endif
#define ECDH ""
#endif
+#define CHACHA20 "chacha20-poly1305@openssh.com,"
+
#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define KEX_METHODS_SIZE 10
@@ -107,8 +120,8 @@ static const char *default_methods[] = {
static const char *supported_methods[] = {
KEY_EXCHANGE,
HOSTKEYS,
- AES BLOWFISH DES_SUPPORTED,
- AES BLOWFISH DES_SUPPORTED,
+ CHACHA20 AES BLOWFISH DES_SUPPORTED,
+ CHACHA20 AES BLOWFISH DES_SUPPORTED,
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
ZLIB,
@@ -154,7 +167,7 @@ static char **tokenize(const char *chain){
ptr++;
}
/* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
- tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
+ tokens = calloc(n + 1, sizeof(char *)); /* +1 for the null */
if (tokens == NULL) {
SAFE_FREE(tmp);
return NULL;
@@ -198,7 +211,7 @@ char **ssh_space_tokenize(const char *chain){
ptr++;
}
/* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
- tokens = malloc(sizeof(char *) * (n + 1)); /* +1 for the null */
+ tokens = calloc(n + 1, sizeof(char *)); /* +1 for the null */
if (tokens == NULL) {
SAFE_FREE(tmp);
return NULL;
@@ -552,7 +565,8 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
* @returns a cstring containing a comma-separated list of hostkey methods.
* NULL if no method matches
*/
-static char *ssh_client_select_hostkeys(ssh_session session){
+static char *ssh_client_select_hostkeys(ssh_session session)
+{
char methods_buffer[128]={0};
static const char *preferred_hostkeys[] = {
"ssh-ed25519",
@@ -560,46 +574,70 @@ static char *ssh_client_select_hostkeys(ssh_session session){
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp256",
"ssh-rsa",
+#ifdef HAVE_DSA
"ssh-dss",
- "ssh-rsa1",
+#endif
NULL
};
- char **methods;
- int i,j;
- int needcoma=0;
-
- methods = ssh_knownhosts_algorithms(session);
- if (methods == NULL || methods[0] == NULL){
- SAFE_FREE(methods);
- return NULL;
- }
-
- for (i=0;preferred_hostkeys[i] != NULL; ++i){
- for (j=0; methods[j] != NULL; ++j){
- if(strcmp(preferred_hostkeys[i], methods[j]) == 0){
- if (ssh_verify_existing_algo(SSH_HOSTKEYS, methods[j])){
- if(needcoma)
- strncat(methods_buffer,",",sizeof(methods_buffer)-strlen(methods_buffer)-1);
- strncat(methods_buffer, methods[j], sizeof(methods_buffer)-strlen(methods_buffer)-1);
- needcoma = 1;
- }
- }
- }
- }
- for(i=0;methods[i]!= NULL; ++i){
- SAFE_FREE(methods[i]);
- }
- SAFE_FREE(methods);
-
- if(strlen(methods_buffer) > 0){
- SSH_LOG(SSH_LOG_DEBUG, "Changing host key method to \"%s\"", methods_buffer);
- return strdup(methods_buffer);
- } else {
- SSH_LOG(SSH_LOG_DEBUG, "No supported kex method for existing key in known_hosts file");
- return NULL;
- }
+ struct ssh_list *algo_list = NULL;
+ struct ssh_iterator *it = NULL;
+ size_t algo_count;
+ int needcomma = 0;
+ int i;
+ algo_list = ssh_known_hosts_get_algorithms(session);
+ if (algo_list == NULL) {
+ return NULL;
+ }
+
+ algo_count = ssh_list_count(algo_list);
+ if (algo_count == 0) {
+ ssh_list_free(algo_list);
+ return NULL;
+ }
+
+ for (i = 0; preferred_hostkeys[i] != NULL; ++i) {
+ for (it = ssh_list_get_iterator(algo_list);
+ it != NULL;
+ it = ssh_list_get_iterator(algo_list)) {
+ const char *algo = ssh_iterator_value(const char *, it);
+ int cmp;
+ int ok;
+
+ cmp = strcmp(preferred_hostkeys[i], algo);
+ if (cmp == 0) {
+ ok = ssh_verify_existing_algo(SSH_HOSTKEYS, algo);
+ if (ok) {
+ if (needcomma) {
+ strncat(methods_buffer,
+ ",",
+ sizeof(methods_buffer) - strlen(methods_buffer) - 1);
+ }
+ strncat(methods_buffer,
+ algo,
+ sizeof(methods_buffer) - strlen(methods_buffer) - 1);
+ needcomma = 1;
+ }
+ }
+
+ ssh_list_remove(algo_list, it);
+ }
+ }
+ ssh_list_free(algo_list);
+
+ if (strlen(methods_buffer) == 0) {
+ SSH_LOG(SSH_LOG_DEBUG,
+ "No supported kex method for existing key in known_hosts file");
+ return NULL;
+ }
+
+ SSH_LOG(SSH_LOG_DEBUG,
+ "Changing host key method to \"%s\"",
+ methods_buffer);
+
+ return strdup(methods_buffer);
}
+
/**
* @brief sets the key exchange parameters to be sent to the server,
* in function of the options and available methods.
@@ -607,9 +645,14 @@ static char *ssh_client_select_hostkeys(ssh_session session){
int ssh_set_client_kex(ssh_session session){
struct ssh_kex_struct *client= &session->next_crypto->client_kex;
const char *wanted;
+ int ok;
int i;
- ssh_get_random(client->cookie, 16, 0);
+ ok = ssh_get_random(client->cookie, 16, 0);
+ if (!ok) {
+ ssh_set_error(session, SSH_FATAL, "PRNG error");
+ return SSH_ERROR;
+ }
memset(client->methods, 0, KEX_METHODS_SIZE * sizeof(char **));
/* first check if we have specific host key methods */
@@ -624,6 +667,10 @@ int ssh_set_client_kex(ssh_session session){
if (wanted == NULL)
wanted = default_methods[i];
client->methods[i] = strdup(wanted);
+ if (client->methods[i] == NULL) {
+ ssh_set_error_oom(session);
+ return SSH_ERROR;
+ }
}
return SSH_OK;
@@ -660,8 +707,21 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP521;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
- }
-
+ } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256") == 0){
+ session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256;
+ }
+ SSH_LOG(SSH_LOG_INFO, "Negotiated %s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
+ session->next_crypto->kex_methods[SSH_KEX],
+ session->next_crypto->kex_methods[SSH_HOSTKEYS],
+ session->next_crypto->kex_methods[SSH_CRYPT_C_S],
+ session->next_crypto->kex_methods[SSH_CRYPT_S_C],
+ session->next_crypto->kex_methods[SSH_MAC_C_S],
+ session->next_crypto->kex_methods[SSH_MAC_S_C],
+ session->next_crypto->kex_methods[SSH_COMP_C_S],
+ session->next_crypto->kex_methods[SSH_COMP_S_C],
+ session->next_crypto->kex_methods[SSH_LANG_C_S],
+ session->next_crypto->kex_methods[SSH_LANG_S_C]
+ );
return SSH_OK;
}
diff --git a/src/kex1.c b/src/kex1.c
deleted file mode 100644
index f4aadd9..0000000
--- a/src/kex1.c
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * kex.c - key exchange
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- *
- * The SSH Library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at your
- * option) any later version.
- *
- * The SSH Library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the SSH Library; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/buffer.h"
-#include "libssh/crypto.h"
-#include "libssh/kex.h"
-#include "libssh/keys.h"
-#include "libssh/session.h"
-#include "libssh/ssh1.h"
-#include "libssh/wrapper.h"
-
-/* SSHv1 functions */
-
-/* makes a STRING contating 3 strings : ssh-rsa1,e and n */
-/* this is a public key in openssh's format */
-static ssh_string make_rsa1_string(ssh_string e, ssh_string n){
- ssh_buffer buffer = NULL;
- ssh_string rsa = NULL;
- ssh_string ret = NULL;
-
- buffer = ssh_buffer_new();
- rsa = ssh_string_from_char("ssh-rsa1");
- if (rsa == NULL) {
- goto error;
- }
-
- if (ssh_buffer_add_ssh_string(buffer, rsa) < 0) {
- goto error;
- }
- if (ssh_buffer_add_ssh_string(buffer, e) < 0) {
- goto error;
- }
- if (ssh_buffer_add_ssh_string(buffer, n) < 0) {
- goto error;
- }
-
- ret = ssh_string_new(ssh_buffer_get_len(buffer));
- if (ret == NULL) {
- goto error;
- }
-
- ssh_string_fill(ret, ssh_buffer_get(buffer), ssh_buffer_get_len(buffer));
-error:
- ssh_buffer_free(buffer);
- ssh_string_free(rsa);
-
- return ret;
-}
-
-static int build_session_id1(ssh_session session, ssh_string servern,
- ssh_string hostn) {
- MD5CTX md5 = NULL;
-
- md5 = md5_init();
- if (md5 == NULL) {
- return -1;
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("host modulus",ssh_string_data(hostn),ssh_string_len(hostn));
- ssh_print_hexa("server modulus",ssh_string_data(servern),ssh_string_len(servern));
-#endif
- md5_update(md5,ssh_string_data(hostn),ssh_string_len(hostn));
- md5_update(md5,ssh_string_data(servern),ssh_string_len(servern));
- md5_update(md5,session->next_crypto->server_kex.cookie,8);
- if(session->next_crypto->session_id != NULL)
- SAFE_FREE(session->next_crypto->session_id);
- session->next_crypto->session_id = malloc(MD5_DIGEST_LEN);
- if(session->next_crypto->session_id == NULL){
- ssh_set_error_oom(session);
- return SSH_ERROR;
- }
- md5_final(session->next_crypto->session_id,md5);
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_LEN);
-#endif
-
- return 0;
-}
-
-/* returns 1 if the modulus of k1 is < than the one of k2 */
-static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){
- bignum n1;
- bignum n2;
- int res;
-#ifdef HAVE_LIBGCRYPT
- gcry_sexp_t sexp;
- sexp=gcry_sexp_find_token(k1->rsa_pub,"n",0);
- n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
- gcry_sexp_release(sexp);
- sexp=gcry_sexp_find_token(k2->rsa_pub,"n",0);
- n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
- gcry_sexp_release(sexp);
-#elif defined HAVE_LIBCRYPTO
- n1=k1->rsa_pub->n;
- n2=k2->rsa_pub->n;
-#endif
- if(bignum_cmp(n1,n2)<0)
- res=1;
- else
- res=0;
-#ifdef HAVE_LIBGCRYPT
- bignum_free(n1);
- bignum_free(n2);
-#endif
- return res;
-
-}
-
-static ssh_string ssh_encrypt_rsa1(ssh_session session,
- ssh_string data,
- ssh_public_key key) {
- ssh_string str = NULL;
- size_t len = ssh_string_len(data);
- size_t size = 0;
-#ifdef HAVE_LIBGCRYPT
- const char *tmp = NULL;
- gcry_sexp_t ret_sexp;
- gcry_sexp_t data_sexp;
-
- if (gcry_sexp_build(&data_sexp, NULL, "(data(flags pkcs1)(value %b))",
- len, ssh_string_data(data))) {
- ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error");
- return NULL;
- }
- if (gcry_pk_encrypt(&ret_sexp, data_sexp, key->rsa_pub)) {
- gcry_sexp_release(data_sexp);
- ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error");
- return NULL;
- }
-
- gcry_sexp_release(data_sexp);
-
- data_sexp = gcry_sexp_find_token(ret_sexp, "a", 0);
- if (data_sexp == NULL) {
- ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error");
- gcry_sexp_release(ret_sexp);
- return NULL;
- }
- tmp = gcry_sexp_nth_data(data_sexp, 1, &size);
- if (*tmp == 0) {
- size--;
- tmp++;
- }
-
- str = ssh_string_new(size);
- if (str == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- gcry_sexp_release(data_sexp);
- gcry_sexp_release(ret_sexp);
- return NULL;
- }
- ssh_string_fill(str, tmp, size);
-
- gcry_sexp_release(data_sexp);
- gcry_sexp_release(ret_sexp);
-#elif defined HAVE_LIBCRYPTO
- size = RSA_size(key->rsa_pub);
-
- str = ssh_string_new(size);
- if (str == NULL) {
- ssh_set_error(session, SSH_FATAL, "Not enough space");
- return NULL;
- }
-
- if (RSA_public_encrypt(len, ssh_string_data(data), ssh_string_data(str), key->rsa_pub,
- RSA_PKCS1_PADDING) < 0) {
- ssh_string_free(str);
- return NULL;
- }
-#endif
-
- return str;
-}
-
-#define ABS(A) ( (A)<0 ? -(A):(A) )
-static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey,
- ssh_public_key hostkey, int slen, int hlen) {
- unsigned char buffer[32] = {0};
- int i;
- ssh_string data1 = NULL;
- ssh_string data2 = NULL;
- if(session->next_crypto->encryptkey != NULL)
- SAFE_FREE(session->next_crypto->encryptkey);
- if(session->next_crypto->decryptkey != NULL)
- SAFE_FREE(session->next_crypto->decryptkey);
- if(session->next_crypto->encryptIV != NULL)
- SAFE_FREE(session->next_crypto->encryptIV);
- if(session->next_crypto->decryptIV != NULL)
- SAFE_FREE(session->next_crypto->decryptIV);
- session->next_crypto->encryptkey = malloc(32);
- session->next_crypto->decryptkey = malloc(32);
- session->next_crypto->encryptIV = malloc(32);
- session->next_crypto->decryptIV = malloc(32);
- if(session->next_crypto->encryptkey == NULL ||
- session->next_crypto->decryptkey == NULL ||
- session->next_crypto->encryptIV == NULL ||
- session->next_crypto->decryptIV == NULL){
- ssh_set_error_oom(session);
- return NULL;
- }
- /* first, generate a session key */
- ssh_get_random(session->next_crypto->encryptkey, 32, 1);
- memcpy(buffer, session->next_crypto->encryptkey, 32);
- memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey, 32);
- memset(session->next_crypto->encryptIV, 0, 32);
- memset(session->next_crypto->decryptIV, 0, 32);
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("session key",buffer,32);
-#endif
-
- /* xor session key with session_id */
- for (i = 0; i < 16; i++) {
- buffer[i] ^= session->next_crypto->session_id[i];
- }
- data1 = ssh_string_new(32);
- if (data1 == NULL) {
- return NULL;
- }
- ssh_string_fill(data1, buffer, 32);
- if (ABS(hlen - slen) < 128){
- SSH_LOG(SSH_LOG_FUNCTIONS,
- "Difference between server modulus and host modulus is only %d. "
- "It's illegal and may not work",
- ABS(hlen - slen));
- }
-
- if (modulus_smaller(srvkey, hostkey)) {
- data2 = ssh_encrypt_rsa1(session, data1, srvkey);
- ssh_string_free(data1);
- data1 = NULL;
- if (data2 == NULL) {
- return NULL;
- }
- data1 = ssh_encrypt_rsa1(session, data2, hostkey);
- ssh_string_free(data2);
- if (data1 == NULL) {
- return NULL;
- }
- } else {
- data2 = ssh_encrypt_rsa1(session, data1, hostkey);
- ssh_string_free(data1);
- data1 = NULL;
- if (data2 == NULL) {
- return NULL;
- }
- data1 = ssh_encrypt_rsa1(session, data2, srvkey);
- ssh_string_free(data2);
- if (data1 == NULL) {
- return NULL;
- }
- }
-
- return data1;
-}
-
-/* 2 SSH_SMSG_PUBLIC_KEY
- *
- * 8 bytes anti_spoofing_cookie
- * 32-bit int server_key_bits
- * mp-int server_key_public_exponent
- * mp-int server_key_public_modulus
- * 32-bit int host_key_bits
- * mp-int host_key_public_exponent
- * mp-int host_key_public_modulus
- * 32-bit int protocol_flags
- * 32-bit int supported_ciphers_mask
- * 32-bit int supported_authentications_mask
- */
-/**
- * @brief Wait for a SSH_SMSG_PUBLIC_KEY and does the key exchange
- */
-SSH_PACKET_CALLBACK(ssh_packet_publickey1){
- ssh_string server_exp = NULL;
- ssh_string server_mod = NULL;
- ssh_string host_exp = NULL;
- ssh_string host_mod = NULL;
- ssh_string serverkey = NULL;
- ssh_string hostkey = NULL;
- ssh_public_key srv = NULL;
- ssh_public_key host = NULL;
- uint32_t server_bits;
- uint32_t host_bits;
- uint32_t protocol_flags;
- uint32_t supported_ciphers_mask;
- uint32_t supported_authentications_mask;
- ssh_string enc_session = NULL;
- uint16_t bits;
- int ko;
- uint32_t support_3DES = 0;
- uint32_t support_DES = 0;
-
- (void)type;
- (void)user;
- SSH_LOG(SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY");
- if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
- ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
- goto error;
- }
- if (ssh_buffer_get_data(packet, session->next_crypto->server_kex.cookie, 8) != 8) {
- ssh_set_error(session, SSH_FATAL, "Can't get cookie in buffer");
- goto error;
- }
-
- ssh_buffer_get_u32(packet, &server_bits);
- server_exp = ssh_buffer_get_mpint(packet);
- if (server_exp == NULL) {
- goto error;
- }
- server_mod = ssh_buffer_get_mpint(packet);
- if (server_mod == NULL) {
- goto error;
- }
- ssh_buffer_get_u32(packet, &host_bits);
- host_exp = ssh_buffer_get_mpint(packet);
- if (host_exp == NULL) {
- goto error;
- }
- host_mod = ssh_buffer_get_mpint(packet);
- if (host_mod == NULL) {
- goto error;
- }
- ssh_buffer_get_u32(packet, &protocol_flags);
- ssh_buffer_get_u32(packet, &supported_ciphers_mask);
- ko = ssh_buffer_get_u32(packet, &supported_authentications_mask);
-
- if ((ko != sizeof(uint32_t)) || !host_mod || !host_exp
- || !server_mod || !server_exp) {
- SSH_LOG(SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet");
- ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet");
- goto error;
- }
-
- server_bits = ntohl(server_bits);
- host_bits = ntohl(host_bits);
- protocol_flags = ntohl(protocol_flags);
- supported_ciphers_mask = ntohl(supported_ciphers_mask);
- supported_authentications_mask = ntohl(supported_authentications_mask);
- SSH_LOG(SSH_LOG_PROTOCOL,
- "Server bits: %d; Host bits: %d; Protocol flags: %.8lx; "
- "Cipher mask: %.8lx; Auth mask: %.8lx",
- server_bits,
- host_bits,
- (unsigned long int) protocol_flags,
- (unsigned long int) supported_ciphers_mask,
- (unsigned long int) supported_authentications_mask);
-
- serverkey = make_rsa1_string(server_exp, server_mod);
- if (serverkey == NULL) {
- goto error;
- }
- hostkey = make_rsa1_string(host_exp,host_mod);
- if (hostkey == NULL) {
- goto error;
- }
- if (build_session_id1(session, server_mod, host_mod) < 0) {
- goto error;
- }
-
- srv = publickey_from_string(session, serverkey);
- if (srv == NULL) {
- goto error;
- }
- host = publickey_from_string(session, hostkey);
- if (host == NULL) {
- goto error;
- }
-
- session->next_crypto->server_pubkey = ssh_string_copy(hostkey);
- if (session->next_crypto->server_pubkey == NULL) {
- goto error;
- }
- session->next_crypto->server_pubkey_type = "ssh-rsa1";
-
- /* now, we must choose an encryption algo */
- /* hardcode 3des */
- //
- support_3DES = (supported_ciphers_mask & (1<<SSH_CIPHER_3DES));
- support_DES = (supported_ciphers_mask & (1<<SSH_CIPHER_DES));
- if(!support_3DES && !support_DES){
- ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES");
- goto error;
- }
- SSH_LOG(SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY");
-
- if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) {
- goto error;
- }
- if (ssh_buffer_add_u8(session->out_buffer, support_3DES ? SSH_CIPHER_3DES : SSH_CIPHER_DES) < 0) {
- goto error;
- }
- if (ssh_buffer_add_data(session->out_buffer, session->next_crypto->server_kex.cookie, 8) < 0) {
- goto error;
- }
-
- enc_session = encrypt_session_key(session, srv, host, server_bits, host_bits);
- if (enc_session == NULL) {
- goto error;
- }
-
- bits = ssh_string_len(enc_session) * 8 - 7;
- SSH_LOG(SSH_LOG_PROTOCOL, "%d bits, %" PRIdS " bytes encrypted session",
- bits, ssh_string_len(enc_session));
- bits = htons(bits);
- /* the encrypted mpint */
- if (ssh_buffer_add_data(session->out_buffer, &bits, sizeof(uint16_t)) < 0) {
- goto error;
- }
- if (ssh_buffer_add_data(session->out_buffer, ssh_string_data(enc_session),
- ssh_string_len(enc_session)) < 0) {
- goto error;
- }
- /* the protocol flags */
- if (ssh_buffer_add_u32(session->out_buffer, 0) < 0) {
- goto error;
- }
- session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED;
- if (ssh_packet_send(session) == SSH_ERROR) {
- goto error;
- }
-
- /* we can set encryption */
- if(crypt_set_algorithms(session, support_3DES ? SSH_3DES : SSH_DES)){
- goto error;
- }
-
- session->current_crypto = session->next_crypto;
- session->next_crypto = NULL;
- goto end;
-error:
- session->session_state=SSH_SESSION_STATE_ERROR;
-end:
-
- ssh_string_free(host_mod);
- ssh_string_free(host_exp);
- ssh_string_free(server_mod);
- ssh_string_free(server_exp);
- ssh_string_free(serverkey);
- ssh_string_free(hostkey);
- ssh_string_free(enc_session);
-
- publickey_free(srv);
- publickey_free(host);
-
- return SSH_PACKET_USED;
-}
-
-int ssh_get_kex1(ssh_session session) {
- SSH_LOG(SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY");
-
- /* Here the callback is called */
- while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){
- ssh_handle_packets(session, SSH_TIMEOUT_USER);
- }
- if (session->session_state==SSH_SESSION_STATE_ERROR) {
- return SSH_ERROR;
- }
- SSH_LOG(SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS");
- /* Waiting for SSH_SMSG_SUCCESS */
- while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
- ssh_handle_packets(session, SSH_TIMEOUT_USER);
- }
- if(session->session_state==SSH_SESSION_STATE_ERROR) {
- return SSH_ERROR;
- }
- SSH_LOG(SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS");
-
- return SSH_OK;
-}
diff --git a/src/known_hosts.c b/src/known_hosts.c
index 2f66cc2..aedad17 100644
--- a/src/known_hosts.c
+++ b/src/known_hosts.c
@@ -32,6 +32,7 @@
#include "libssh/session.h"
#include "libssh/buffer.h"
#include "libssh/misc.h"
+#include "libssh/dh.h"
#include "libssh/pki.h"
#include "libssh/options.h"
#include "libssh/knownhosts.h"
@@ -58,18 +59,6 @@
* @{
*/
-static int alldigits(const char *s) {
- while (*s) {
- if (isdigit(*s)) {
- s++;
- } else {
- return 0;
- }
- }
-
- return 1;
-}
-
/**
* @internal
*
@@ -102,7 +91,7 @@ static void tokens_free(char **tokens) {
* @param[out] found_type A pointer to a string to be set with the found key
* type.
*
- * @returns The found_type type of key (ie "dsa","ssh-rsa1"). Don't
+ * @returns The found_type type of key (ie "dsa","ssh-rsa"). Don't
* free that value. NULL if no match was found or the file
* was not found.
*/
@@ -149,21 +138,9 @@ static char **ssh_get_knownhost_line(FILE **file, const char *filename,
}
*found_type = tokens[1];
- if (tokens[3]) {
- /* openssh rsa1 format has 4 tokens on the line. Recognize it
- by the fact that everything is all digits */
- if (tokens[4]) {
- /* that's never valid */
- tokens_free(tokens);
- continue;
- }
- if (alldigits(tokens[1]) && alldigits(tokens[2]) && alldigits(tokens[3])) {
- *found_type = "ssh-rsa1";
- } else {
- /* 3 tokens only, not four */
- tokens_free(tokens);
- continue;
- }
+ if (tokens[3] || tokens[4]) {
+ tokens_free(tokens);
+ continue;
}
return tokens;
@@ -188,75 +165,14 @@ static char **ssh_get_knownhost_line(FILE **file, const char *filename,
* on error.
*/
static int check_public_key(ssh_session session, char **tokens) {
- ssh_string pubkey = session->current_crypto->server_pubkey;
+ ssh_string pubkey_blob = NULL;
ssh_buffer pubkey_buffer;
char *pubkey_64;
+ int rc;
- /* ok we found some public key in known hosts file. now un-base64it */
- if (alldigits(tokens[1])) {
- /* openssh rsa1 format */
- bignum tmpbn;
- ssh_string tmpstring;
- unsigned int len;
- int i;
-
- pubkey_buffer = ssh_buffer_new();
- if (pubkey_buffer == NULL) {
- return -1;
- }
-
- tmpstring = ssh_string_from_char("ssh-rsa1");
- if (tmpstring == NULL) {
- ssh_buffer_free(pubkey_buffer);
- return -1;
- }
-
- if (ssh_buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) {
- ssh_buffer_free(pubkey_buffer);
- ssh_string_free(tmpstring);
- return -1;
- }
- ssh_string_free(tmpstring);
-
- for (i = 2; i < 4; i++) { /* e, then n */
- tmpbn = NULL;
- bignum_dec2bn(tokens[i], &tmpbn);
- if (tmpbn == NULL) {
- ssh_buffer_free(pubkey_buffer);
- return -1;
- }
- /* for some reason, ssh_make_bignum_string does not work
- because of the padding which it does --kv */
- /* tmpstring = ssh_make_bignum_string(tmpbn); */
- /* do it manually instead */
- len = bignum_num_bytes(tmpbn);
- tmpstring = malloc(4 + len);
- if (tmpstring == NULL) {
- ssh_buffer_free(pubkey_buffer);
- bignum_free(tmpbn);
- return -1;
- }
- /* TODO: fix the hardcoding */
- tmpstring->size = htonl(len);
-#ifdef HAVE_LIBGCRYPT
- bignum_bn2bin(tmpbn, len, ssh_string_data(tmpstring));
-#elif defined HAVE_LIBCRYPTO
- bignum_bn2bin(tmpbn, ssh_string_data(tmpstring));
-#endif
- bignum_free(tmpbn);
- if (ssh_buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) {
- ssh_buffer_free(pubkey_buffer);
- ssh_string_free(tmpstring);
- bignum_free(tmpbn);
- return -1;
- }
- ssh_string_free(tmpstring);
- }
- } else {
/* ssh-dss or ssh-rsa */
pubkey_64 = tokens[2];
pubkey_buffer = base64_to_bin(pubkey_64);
- }
if (pubkey_buffer == NULL) {
ssh_set_error(session, SSH_FATAL,
@@ -264,18 +180,27 @@ static int check_public_key(ssh_session session, char **tokens) {
return -1;
}
- if (ssh_buffer_get_len(pubkey_buffer) != ssh_string_len(pubkey)) {
+ rc = ssh_dh_get_current_server_publickey_blob(session, &pubkey_blob);
+ if (rc != 0) {
+ ssh_buffer_free(pubkey_buffer);
+ return -1;
+ }
+
+ if (ssh_buffer_get_len(pubkey_buffer) != ssh_string_len(pubkey_blob)) {
+ ssh_string_free(pubkey_blob);
ssh_buffer_free(pubkey_buffer);
return 0;
}
/* now test that they are identical */
- if (memcmp(ssh_buffer_get(pubkey_buffer), ssh_string_data(pubkey),
+ if (memcmp(ssh_buffer_get(pubkey_buffer), ssh_string_data(pubkey_blob),
ssh_buffer_get_len(pubkey_buffer)) != 0) {
+ ssh_string_free(pubkey_blob);
ssh_buffer_free(pubkey_buffer);
return 0;
}
+ ssh_string_free(pubkey_blob);
ssh_buffer_free(pubkey_buffer);
return 1;
}
@@ -376,32 +301,10 @@ static int match_hashed_host(const char *host, const char *sourcehash)
*/
/**
- * @brief Check if the server is known.
- *
- * Checks the user's known host file for a previous connection to the
- * current server.
- *
- * @param[in] session The SSH session to use.
+ * @brief This function is depcrecated
*
- * @returns SSH_SERVER_KNOWN_OK: The server is known and has not changed.\n
- * SSH_SERVER_KNOWN_CHANGED: The server key has changed. Either you
- * are under attack or the administrator
- * changed the key. You HAVE to warn the
- * user about a possible attack.\n
- * SSH_SERVER_FOUND_OTHER: The server gave use a key of a type while
- * we had an other type recorded. It is a
- * possible attack.\n
- * SSH_SERVER_NOT_KNOWN: The server is unknown. User should
- * confirm the MD5 is correct.\n
- * SSH_SERVER_FILE_NOT_FOUND: The known host file does not exist. The
- * host is thus unknown. File will be
- * created if host key is accepted.\n
- * SSH_SERVER_ERROR: Some error happened.
- *
- * @see ssh_get_pubkey_hash()
- *
- * @bug There is no current way to remove or modify an entry into the known
- * host table.
+ * @deprecated Please use ssh_session_is_known_server()
+ * @see ssh_session_is_known_server()
*/
int ssh_is_server_known(ssh_session session) {
FILE *file = NULL;
@@ -410,6 +313,8 @@ int ssh_is_server_known(ssh_session session) {
char *hostport;
const char *type;
int match;
+ int i=0;
+ char * files[3];
int ret = SSH_SERVER_NOT_KNOWN;
if (session->opts.knownhosts == NULL) {
@@ -444,14 +349,27 @@ int ssh_is_server_known(ssh_session session) {
return SSH_SERVER_ERROR;
}
+ /* set the list of known hosts */
+ i = 0;
+ if (session->opts.global_knownhosts != NULL){
+ files[i++]=session->opts.global_knownhosts;
+ }
+ files[i++] = session->opts.knownhosts;
+ files[i] = NULL;
+ i = 0;
+
do {
tokens = ssh_get_knownhost_line(&file,
- session->opts.knownhosts,
+ files[i],
&type);
- /* End of file, return the current state */
+ /* End of file, return the current state or use next file */
if (tokens == NULL) {
- break;
+ ++i;
+ if(files[i] == NULL)
+ break;
+ else
+ continue;
}
match = match_hashed_host(host, tokens[0]);
if (match == 0){
@@ -464,12 +382,21 @@ int ssh_is_server_known(ssh_session session) {
match = match_hashed_host(hostport, tokens[0]);
}
if (match) {
+ ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
+ const char *pubkey_type = NULL;
+
+ if (ssh_key_type(pubkey) == SSH_KEYTYPE_ECDSA) {
+ pubkey_type = ssh_pki_key_ecdsa_name(pubkey);
+ } else {
+ pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey));
+ }
+
/* We got a match. Now check the key type */
- if (strcmp(session->current_crypto->server_pubkey_type, type) != 0) {
+ if (strcmp(pubkey_type, type) != 0) {
SSH_LOG(SSH_LOG_PACKET,
"ssh_is_server_known: server type [%s] doesn't match the "
"type [%s] in known_hosts file",
- session->current_crypto->server_pubkey_type,
+ pubkey_type,
type);
/* Different type. We don't override the known_changed error which is
* more important */
@@ -524,8 +451,7 @@ int ssh_is_server_known(ssh_session session) {
* @return string on success, NULL on error.
*/
char * ssh_dump_knownhost(ssh_session session) {
- ssh_string pubkey_s;
- ssh_key key;
+ ssh_key server_pubkey = NULL;
char *host;
char *hostport;
size_t len = 4096;
@@ -557,55 +483,34 @@ char * ssh_dump_knownhost(ssh_session session) {
return NULL;
}
- pubkey_s = session->current_crypto->server_pubkey;
- if (pubkey_s == NULL){
+ server_pubkey = ssh_dh_get_current_server_publickey(session);
+ if (server_pubkey == NULL){
ssh_set_error(session, SSH_FATAL, "No public key present");
SAFE_FREE(host);
return NULL;
}
- rc = ssh_pki_import_pubkey_blob(pubkey_s, &key);
- if (rc < 0) {
- SAFE_FREE(host);
- return NULL;
- }
-
buffer = calloc (1, 4096);
if (!buffer) {
- ssh_key_free(key);
SAFE_FREE(host);
return NULL;
}
- if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) {
- /* openssh uses a different format for ssh-rsa1 keys.
- Be compatible --kv */
- rc = ssh_pki_export_pubkey_rsa1(key, host, buffer, len);
- ssh_key_free(key);
+ rc = ssh_pki_export_pubkey_base64(server_pubkey, &b64_key);
+ if (rc < 0) {
+ SAFE_FREE(buffer);
SAFE_FREE(host);
- if (rc < 0) {
- SAFE_FREE(buffer);
- return NULL;
- }
- } else {
- rc = ssh_pki_export_pubkey_base64(key, &b64_key);
- if (rc < 0) {
- ssh_key_free(key);
- SAFE_FREE(buffer);
- SAFE_FREE(host);
- return NULL;
- }
+ return NULL;
+ }
- snprintf(buffer, len,
- "%s %s %s\n",
- host,
- key->type_c,
- b64_key);
+ snprintf(buffer, len,
+ "%s %s %s\n",
+ host,
+ server_pubkey->type_c,
+ b64_key);
- ssh_key_free(key);
- SAFE_FREE(host);
- SAFE_FREE(b64_key);
- }
+ SAFE_FREE(host);
+ SAFE_FREE(b64_key);
return buffer;
}
@@ -676,100 +581,4 @@ int ssh_write_knownhost(ssh_session session) {
#define KNOWNHOSTS_MAXTYPES 10
-/**
- * @internal
- * @brief Check which kind of host keys should be preferred for connection
- * by reading the known_hosts file.
- *
- * @param[in] session The SSH session to use.
- *
- * @returns array of supported key types
- * NULL on error
- */
-char **ssh_knownhosts_algorithms(ssh_session session) {
- FILE *file = NULL;
- char **tokens;
- char *host;
- char *hostport;
- const char *type;
- int match;
- char **array;
- int i=0, j;
-
- if (session->opts.knownhosts == NULL) {
- if (ssh_options_apply(session) < 0) {
- ssh_set_error(session, SSH_REQUEST_DENIED,
- "Can't find a known_hosts file");
- return NULL;
- }
- }
-
- if (session->opts.host == NULL) {
- return NULL;
- }
-
- host = ssh_lowercase(session->opts.host);
- hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
- array = malloc(sizeof(char *) * KNOWNHOSTS_MAXTYPES);
-
- if (host == NULL || hostport == NULL || array == NULL) {
- ssh_set_error_oom(session);
- SAFE_FREE(host);
- SAFE_FREE(hostport);
- SAFE_FREE(array);
- return NULL;
- }
-
- do {
- tokens = ssh_get_knownhost_line(&file,
- session->opts.knownhosts, &type);
-
- /* End of file, return the current state */
- if (tokens == NULL) {
- break;
- }
- match = match_hashed_host(host, tokens[0]);
- if (match == 0){
- match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
- }
- if (match == 0) {
- match = match_hostname(host, tokens[0], strlen(tokens[0]));
- }
- if (match == 0) {
- match = match_hashed_host(hostport, tokens[0]);
- }
- if (match) {
- /* We got a match. Now check the key type */
- SSH_LOG(SSH_LOG_DEBUG, "server %s:%d has %s in known_hosts",
- host, session->opts.port, type);
- /* don't copy more than once */
- for(j=0;j<i && match;++j){
- if(strcmp(array[j], type)==0)
- match=0;
- }
- if (match){
- array[i] = strdup(type);
- i++;
- if(i>= KNOWNHOSTS_MAXTYPES-1){
- tokens_free(tokens);
- break;
- }
- }
- }
- tokens_free(tokens);
- } while (1);
-
- array[i]=NULL;
- SAFE_FREE(host);
- SAFE_FREE(hostport);
- if (file != NULL) {
- fclose(file);
- }
-
- /* Return the current state at end of file */
- return array;
-}
-
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/knownhosts.c b/src/knownhosts.c
new file mode 100644
index 0000000..8c17d5e
--- /dev/null
+++ b/src/knownhosts.c
@@ -0,0 +1,886 @@
+/*
+ * known_hosts: Host and public key verification.
+ *
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2003-2009 by Aris Adamantiadis
+ * Copyright (c) 2009-2017 by Andreas Schneider <asn@cryptomilk.org>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#endif
+
+#include "libssh/priv.h"
+#include "libssh/dh.h"
+#include "libssh/session.h"
+#include "libssh/options.h"
+#include "libssh/misc.h"
+#include "libssh/pki.h"
+#include "libssh/dh.h"
+#include "libssh/knownhosts.h"
+
+static int hash_hostname(const char *name,
+ unsigned char *salt,
+ unsigned int salt_size,
+ unsigned char **hash,
+ unsigned int *hash_size)
+{
+ HMACCTX mac_ctx;
+
+ mac_ctx = hmac_init(salt, salt_size, SSH_HMAC_SHA1);
+ if (mac_ctx == NULL) {
+ return SSH_ERROR;
+ }
+
+ hmac_update(mac_ctx, name, strlen(name));
+ hmac_final(mac_ctx, *hash, hash_size);
+
+ return SSH_OK;
+}
+
+static int match_hashed_hostname(const char *host, const char *hashed_host)
+{
+ char *hashed;
+ char *b64_hash;
+ ssh_buffer salt = NULL;
+ ssh_buffer hash = NULL;
+ unsigned char hashed_buf[256] = {0};
+ unsigned char *hashed_buf_ptr = hashed_buf;
+ unsigned int hashed_buf_size = sizeof(hashed_buf);
+ int cmp;
+ int rc;
+ int match = 0;
+
+ cmp = strncmp(hashed_host, "|1|", 3);
+ if (cmp != 0) {
+ return 0;
+ }
+
+ hashed = strdup(hashed_host + 3);
+ if (hashed == NULL) {
+ return 0;
+ }
+
+ b64_hash = strchr(hashed, '|');
+ if (b64_hash == NULL) {
+ goto error;
+ }
+ *b64_hash = '\0';
+ b64_hash++;
+
+ salt = base64_to_bin(hashed);
+ if (salt == NULL) {
+ goto error;
+ }
+
+ hash = base64_to_bin(b64_hash);
+ if (hash == NULL) {
+ goto error;
+ }
+
+ rc = hash_hostname(host,
+ ssh_buffer_get(salt),
+ ssh_buffer_get_len(salt),
+ &hashed_buf_ptr,
+ &hashed_buf_size);
+ if (rc != SSH_OK) {
+ goto error;
+ }
+
+ if (hashed_buf_size != ssh_buffer_get_len(hash)) {
+ goto error;
+ }
+
+ cmp = memcmp(hashed_buf, ssh_buffer_get(hash), hashed_buf_size);
+ if (cmp == 0) {
+ match = 1;
+ }
+
+error:
+ free(hashed);
+ ssh_buffer_free(salt);
+ ssh_buffer_free(hash);
+
+ return match;
+}
+
+/**
+ * @brief Free an allocated ssh_knownhosts_entry.
+ *
+ * Use SSH_KNOWNHOSTS_ENTRY_FREE() to set the pointer to NULL.
+ *
+ * @param[in] entry The entry to free.
+ */
+void ssh_knownhosts_entry_free(struct ssh_knownhosts_entry *entry)
+{
+ if (entry == NULL) {
+ return;
+ }
+
+ SAFE_FREE(entry->hostname);
+ SAFE_FREE(entry->unparsed);
+ ssh_key_free(entry->publickey);
+ SAFE_FREE(entry->comment);
+ SAFE_FREE(entry);
+}
+
+static int known_hosts_read_line(FILE *fp,
+ char *buf,
+ size_t buf_size,
+ size_t *buf_len,
+ size_t *lineno)
+{
+ while (fgets(buf, buf_size, fp) != NULL) {
+ size_t len;
+ if (buf[0] == '\0') {
+ continue;
+ }
+
+ *lineno += 1;
+ len = strlen(buf);
+ if (buf_len != NULL) {
+ *buf_len = len;
+ }
+ if (buf[len - 1] == '\n' || feof(fp)) {
+ return 0;
+ } else {
+ errno = E2BIG;
+ return -1;
+ }
+ }
+
+ return -1;
+}
+
+static int ssh_known_hosts_read_entries(const char *match,
+ const char *filename,
+ struct ssh_list **entries)
+{
+ struct ssh_list *entry_list;
+ char line[8192];
+ size_t lineno = 0;
+ size_t len = 0;
+ FILE *fp;
+ int rc;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return SSH_ERROR;
+ }
+
+ entry_list = ssh_list_new();
+ if (entry_list == NULL) {
+ fclose(fp);
+ return SSH_ERROR;
+ }
+
+ for (rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno);
+ rc == 0;
+ rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno)) {
+ struct ssh_knownhosts_entry *entry = NULL;
+ char *p;
+
+ if (line[len] != '\n') {
+ len = strcspn(line, "\n");
+ }
+ line[len] = '\0';
+
+ /* Skip leading spaces */
+ for (p = line; isspace((int)p[0]); p++);
+
+ /* Skip comments and empty lines */
+ if (p[0] == '\0' || p[0] == '#') {
+ continue;
+ }
+
+ rc = ssh_known_hosts_parse_line(match,
+ line,
+ &entry);
+ if (rc == SSH_AGAIN) {
+ continue;
+ } else if (rc != SSH_OK) {
+ goto error;
+ }
+ ssh_list_append(entry_list, entry);
+ }
+
+ *entries = entry_list;
+
+ fclose(fp);
+ return SSH_OK;
+error:
+ ssh_list_free(entry_list);
+ fclose(fp);
+ return SSH_ERROR;
+}
+
+static char *ssh_session_get_host_port(ssh_session session)
+{
+ char *host_port;
+ char *host;
+
+ if (session->opts.host == NULL) {
+ ssh_set_error(session,
+ SSH_FATAL,
+ "Can't verify server inn known hosts if the host we "
+ "should connect to has not been set");
+
+ return NULL;
+ }
+
+ host = ssh_lowercase(session->opts.host);
+ if (host == NULL) {
+ ssh_set_error_oom(session);
+ return NULL;
+ }
+
+ if (session->opts.port == 0 || session->opts.port == 22) {
+ host_port = host;
+ } else {
+ host_port = ssh_hostport(host, session->opts.port);
+ SAFE_FREE(host);
+ if (host_port == NULL) {
+ ssh_set_error_oom(session);
+ return NULL;
+ }
+ }
+
+ return host_port;
+}
+
+/**
+ * @internal
+ * @brief Check which host keys should be preferred for the session.
+ *
+ * This checks the known_hosts file to find out which algorithms should be
+ * preferred for the connection we are going to establish.
+ *
+ * @param[in] session The ssh session to use.
+ *
+ * @return A list of supported key types, NULL on error.
+ */
+struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
+{
+ struct ssh_list *entry_list = NULL;
+ struct ssh_iterator *it = NULL;
+ char *host_port = NULL;
+ size_t count;
+ struct ssh_list *list = NULL;
+ int list_error = 0;
+ int rc;
+
+ if (session->opts.knownhosts == NULL) {
+ if (ssh_options_apply(session) < 0) {
+ ssh_set_error(session,
+ SSH_REQUEST_DENIED,
+ "Can't find a known_hosts file");
+
+ return NULL;
+ }
+ }
+
+ host_port = ssh_session_get_host_port(session);
+ if (host_port == NULL) {
+ return NULL;
+ }
+
+ list = ssh_list_new();
+ if (list == NULL) {
+ SAFE_FREE(host_port);
+ return NULL;
+ }
+
+ rc = ssh_known_hosts_read_entries(host_port,
+ session->opts.knownhosts,
+ &entry_list);
+ SAFE_FREE(host_port);
+ if (rc != 0) {
+ ssh_list_free(list);
+ return NULL;
+ }
+
+ count = ssh_list_count(entry_list);
+ if (count == 0) {
+ ssh_list_free(list);
+ ssh_list_free(entry_list);
+ return NULL;
+ }
+
+ for (it = ssh_list_get_iterator(entry_list);
+ it != NULL;
+ it = ssh_list_get_iterator(entry_list)) {
+ struct ssh_knownhosts_entry *entry = NULL;
+ enum ssh_keytypes_e key_type;
+ const char *algo = NULL;
+
+ entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
+ key_type = ssh_key_type(entry->publickey);
+ algo = ssh_key_type_to_char(key_type);
+
+ rc = ssh_list_append(list, algo);
+ if (rc != SSH_OK) {
+ list_error = 1;
+ }
+
+ ssh_knownhosts_entry_free(entry);
+ ssh_list_remove(entry_list, it);
+ }
+ ssh_list_free(entry_list);
+ if (list_error) {
+ goto error;
+ }
+
+ return list;
+error:
+ ssh_list_free(list);
+ return NULL;
+}
+
+/**
+ * @brief Parse a line from a known_hosts entry into a structure
+ *
+ * This parses an known_hosts entry into a structure with the key in a libssh
+ * consumeable form. You can use the PKI key function to further work with it.
+ *
+ * @param[in] hostname The hostname to match the line to
+ *
+ * @param[in] line The line to compare and parse if we have a hostname
+ * match.
+ *
+ * @param[in] entry A pointer to store the the allocated known_hosts
+ * entry structure. The user needs to free the memory
+ * using SSH_KNOWNHOSTS_ENTRY_FREE().
+ *
+ * @return SSH_OK on success, SSH_ERROR otherwise.
+ */
+int ssh_known_hosts_parse_line(const char *hostname,
+ const char *line,
+ struct ssh_knownhosts_entry **entry)
+{
+ struct ssh_knownhosts_entry *e = NULL;
+ char *known_host = NULL;
+ char *p;
+ enum ssh_keytypes_e key_type;
+ int match = 0;
+ int rc = SSH_OK;
+
+ known_host = strdup(line);
+ if (known_host == NULL) {
+ return SSH_ERROR;
+ }
+
+ /* match pattern for hostname or hashed hostname */
+ p = strtok(known_host, " ");
+ if (p == NULL ) {
+ free(known_host);
+ return SSH_ERROR;
+ }
+
+ e = calloc(1, sizeof(struct ssh_knownhosts_entry));
+ if (e == NULL) {
+ free(known_host);
+ return SSH_ERROR;
+ }
+
+ if (hostname != NULL) {
+ char *match_pattern = NULL;
+ char *q;
+
+ /* Hashed */
+ if (p[0] == '|') {
+ match = match_hashed_hostname(hostname, p);
+ }
+
+ for (q = strtok(p, ",");
+ q != NULL;
+ q = strtok(NULL, ",")) {
+ int cmp;
+
+ cmp = match_hostname(hostname, q, strlen(q));
+ if (cmp == 1) {
+ match = 1;
+ break;
+ }
+ }
+ SAFE_FREE(match_pattern);
+
+ if (match == 0) {
+ rc = SSH_AGAIN;
+ goto out;
+ }
+
+ e->hostname = strdup(hostname);
+ if (e->hostname == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+ }
+
+ /* Restart parsing */
+ SAFE_FREE(known_host);
+ known_host = strdup(line);
+ if (known_host == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ p = strtok(known_host, " ");
+ if (p == NULL ) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ e->unparsed = strdup(p);
+ if (e->unparsed == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ /* pubkey type */
+ p = strtok(NULL, " ");
+ if (p == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ key_type = ssh_key_type_from_name(p);
+ if (key_type == SSH_KEYTYPE_UNKNOWN) {
+ SSH_LOG(SSH_LOG_WARN, "key type '%s' unknown!", p);
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ /* public key */
+ p = strtok(NULL, " ");
+ if (p == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+
+ rc = ssh_pki_import_pubkey_base64(p,
+ key_type,
+ &e->publickey);
+ if (rc != SSH_OK) {
+ SSH_LOG(SSH_LOG_WARN,
+ "Failed to parse %s key for entry: %s!",
+ ssh_key_type_to_char(key_type),
+ e->unparsed);
+ goto out;
+ }
+
+ /* comment */
+ p = strtok(NULL, " ");
+ if (p != NULL) {
+ p = strstr(line, p);
+ if (p != NULL) {
+ e->comment = strdup(p);
+ if (e->comment == NULL) {
+ rc = SSH_ERROR;
+ goto out;
+ }
+ }
+ }
+
+ *entry = e;
+ SAFE_FREE(known_host);
+
+ return SSH_OK;
+out:
+ SAFE_FREE(known_host);
+ ssh_knownhosts_entry_free(e);
+ return rc;
+}
+
+/**
+ * @brief Check if the set hostname and port matches an entry in known_hosts.
+ *
+ * This check if the set hostname and port has an entry in the known_hosts file.
+ * You need to set at least the hostname using ssh_options_set().
+ *
+ * @param[in] session The session with with the values set to check.
+ *
+ * @return A @ssh_known_hosts_e return value.
+ */
+enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
+{
+ struct ssh_list *entry_list = NULL;
+ struct ssh_iterator *it = NULL;
+ char *host_port = NULL;
+ int rc;
+
+ if (session->opts.knownhosts == NULL) {
+ if (ssh_options_apply(session) < 0) {
+ ssh_set_error(session,
+ SSH_REQUEST_DENIED,
+ "Can't find a known_hosts file");
+
+ return SSH_KNOWN_HOSTS_NOT_FOUND;
+ }
+ }
+
+ host_port = ssh_session_get_host_port(session);
+ if (host_port == NULL) {
+ return SSH_KNOWN_HOSTS_ERROR;
+ }
+
+ rc = ssh_known_hosts_read_entries(host_port,
+ session->opts.knownhosts,
+ &entry_list);
+ SAFE_FREE(host_port);
+ if (rc != 0) {
+ return SSH_KNOWN_HOSTS_UNKNOWN;
+ }
+
+ if (ssh_list_count(entry_list) == 0) {
+ ssh_list_free(entry_list);
+ return SSH_KNOWN_HOSTS_UNKNOWN;
+ }
+
+ for (it = ssh_list_get_iterator(entry_list);
+ it != NULL;
+ it = ssh_list_get_iterator(entry_list)) {
+ struct ssh_knownhosts_entry *entry = NULL;
+
+ entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
+ ssh_knownhosts_entry_free(entry);
+ ssh_list_remove(entry_list, it);
+ }
+ ssh_list_free(entry_list);
+
+ return SSH_KNOWN_HOSTS_OK;
+}
+
+/**
+ * @brief Export the current session information to a known_hosts string.
+ *
+ * This exports the current information of a session which is connected so a
+ * ssh server into an entry line which can be added to a known_hosts file.
+ *
+ * @param[in] session The session with information to export.
+ *
+ * @param[in] pentry_string A pointer to a string to store the alloocated
+ * line of the entry. The user must free it using
+ * ssh_string_free_char().
+ *
+ * @return SSH_OK on succcess, SSH_ERROR otherwise.
+ */
+int ssh_session_export_known_hosts_entry(ssh_session session,
+ char **pentry_string)
+{
+ ssh_key server_pubkey = NULL;
+ char *host = NULL;
+ char entry_buf[4096] = {0};
+ char *b64_key = NULL;
+ int rc;
+
+ if (pentry_string == NULL) {
+ ssh_set_error_invalid(session);
+ return SSH_ERROR;
+ }
+
+ if (session->opts.host == NULL) {
+ ssh_set_error(session, SSH_FATAL,
+ "Can't create known_hosts entry - hostname unknown");
+ return SSH_ERROR;
+ }
+
+ host = ssh_session_get_host_port(session);
+ if (host == NULL) {
+ return SSH_ERROR;
+ }
+
+ if (session->current_crypto == NULL) {
+ ssh_set_error(session, SSH_FATAL,
+ "No current crypto context, please connnect first");
+ SAFE_FREE(host);
+ return SSH_ERROR;
+ }
+
+ server_pubkey = ssh_dh_get_current_server_publickey(session);
+ if (server_pubkey == NULL){
+ ssh_set_error(session, SSH_FATAL, "No public key present");
+ SAFE_FREE(host);
+ return SSH_ERROR;
+ }
+
+ rc = ssh_pki_export_pubkey_base64(server_pubkey, &b64_key);
+ if (rc < 0) {
+ SAFE_FREE(host);
+ return SSH_ERROR;
+ }
+
+ snprintf(entry_buf, sizeof(entry_buf),
+ "%s %s %s\n",
+ host,
+ server_pubkey->type_c,
+ b64_key);
+
+ SAFE_FREE(host);
+ SAFE_FREE(b64_key);
+
+ *pentry_string = strdup(entry_buf);
+ if (*pentry_string == NULL) {
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
+}
+
+/**
+ * @brief Add the current connected server to the known_hosts file.
+ *
+ * This adds the currently connected server to the known_hosts file by
+ * appending a new line at the end.
+ *
+ * @param[in] session The session to use to write the entry.
+ *
+ * @return SSH_OK on success, SSH_ERROR otherwise.
+ */
+int ssh_session_update_known_hosts(ssh_session session)
+{
+ FILE *fp = NULL;
+ char *entry = NULL;
+ char *dir = NULL;
+ size_t nwritten;
+ size_t len;
+ int rc;
+
+ if (session->opts.knownhosts == NULL) {
+ rc = ssh_options_apply(session);
+ if (rc != SSH_OK) {
+ ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file");
+ return SSH_ERROR;
+ }
+ }
+
+ /* Check if directory exists and create it if not */
+ dir = ssh_dirname(session->opts.knownhosts);
+ if (dir == NULL) {
+ ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
+ return SSH_ERROR;
+ }
+
+ rc = ssh_file_readaccess_ok(dir);
+ if (rc == 0) {
+ rc = ssh_mkdir(dir, 0700);
+ } else {
+ rc = 0;
+ }
+ SAFE_FREE(dir);
+ if (rc != 0) {
+ ssh_set_error(session, SSH_FATAL,
+ "Cannot create %s directory.", dir);
+ return SSH_ERROR;
+ }
+
+ fp = fopen(session->opts.knownhosts, "a");
+ if (fp == NULL) {
+ ssh_set_error(session, SSH_FATAL,
+ "Couldn't open known_hosts file %s for appending: %s",
+ session->opts.knownhosts, strerror(errno));
+ return SSH_ERROR;
+ }
+
+ rc = ssh_session_export_known_hosts_entry(session, &entry);
+ if (rc != SSH_OK) {
+ fclose(fp);
+ return rc;
+ }
+
+ len = strlen(entry);
+ nwritten = fwrite(entry, sizeof(char), len, fp);
+ SAFE_FREE(entry);
+ if (nwritten != len || ferror(fp)) {
+ ssh_set_error(session, SSH_FATAL,
+ "Couldn't append to known_hosts file %s: %s",
+ session->opts.knownhosts, strerror(errno));
+ fclose(fp);
+ return SSH_ERROR;
+ }
+
+ fclose(fp);
+ return SSH_OK;
+}
+
+static enum ssh_known_hosts_e
+ssh_known_hosts_check_server_key(const char *hosts_entry,
+ const char *filename,
+ ssh_key server_key,
+ struct ssh_knownhosts_entry **pentry)
+{
+ struct ssh_list *entry_list = NULL;
+ struct ssh_iterator *it = NULL;
+ enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN;
+ int rc;
+
+ rc = ssh_known_hosts_read_entries(hosts_entry,
+ filename,
+ &entry_list);
+ if (rc != 0) {
+ return SSH_KNOWN_HOSTS_UNKNOWN;
+ }
+
+ it = ssh_list_get_iterator(entry_list);
+ if (it == NULL) {
+ ssh_list_free(entry_list);
+ return SSH_KNOWN_HOSTS_UNKNOWN;
+ }
+
+ for (;it != NULL; it = it->next) {
+ struct ssh_knownhosts_entry *entry = NULL;
+ int cmp;
+
+ entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
+
+ cmp = ssh_key_cmp(server_key, entry->publickey, SSH_KEY_CMP_PUBLIC);
+ if (cmp == 0) {
+ found = SSH_KNOWN_HOSTS_OK;
+ if (pentry != NULL) {
+ *pentry = entry;
+ ssh_list_remove(entry_list, it);
+ }
+ break;
+ }
+
+ if (ssh_key_type(server_key) == ssh_key_type(entry->publickey)) {
+ found = SSH_KNOWN_HOSTS_CHANGED;
+ continue;
+ }
+
+ if (found != SSH_KNOWN_HOSTS_CHANGED) {
+ found = SSH_KNOWN_HOSTS_OTHER;
+ }
+ }
+
+ for (it = ssh_list_get_iterator(entry_list);
+ it != NULL;
+ it = ssh_list_get_iterator(entry_list)) {
+ struct ssh_knownhosts_entry *entry = NULL;
+
+ entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
+ ssh_knownhosts_entry_free(entry);
+ ssh_list_remove(entry_list, it);
+ }
+ ssh_list_free(entry_list);
+
+ return found;
+}
+
+/**
+ * @brief Get the known_hosts entry for the current connected session.
+ *
+ * @param[in] session The session to validate.
+ *
+ * @param[in] pentry A pointer to store the allocated known hosts entry.
+ *
+ * @returns SSH_KNOWN_HOSTS_OK: The server is known and has not changed.\n
+ * SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you
+ * are under attack or the administrator
+ * changed the key. You HAVE to warn the
+ * user about a possible attack.\n
+ * SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while
+ * we had an other type recorded. It is a
+ * possible attack.\n
+ * SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should
+ * confirm the public key hash is correct.\n
+ * SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The
+ * host is thus unknown. File will be
+ * created if host key is accepted.\n
+ * SSH_KNOWN_HOSTS_ERROR: There had been an eror checking the host.
+ *
+ * @see ssh_knownhosts_entry_free()
+ */
+enum ssh_known_hosts_e
+ssh_session_get_known_hosts_entry(ssh_session session,
+ struct ssh_knownhosts_entry **pentry)
+{
+ ssh_key server_pubkey = NULL;
+ char *host_port = NULL;
+ enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN;
+
+ if (session->opts.knownhosts == NULL) {
+ if (ssh_options_apply(session) < 0) {
+ ssh_set_error(session,
+ SSH_REQUEST_DENIED,
+ "Can't find a known_hosts file");
+
+ return SSH_KNOWN_HOSTS_NOT_FOUND;
+ }
+ }
+
+ server_pubkey = ssh_dh_get_current_server_publickey(session);
+ if (server_pubkey == NULL) {
+ ssh_set_error(session,
+ SSH_FATAL,
+ "ssh_session_is_known_host called without a "
+ "server_key!");
+
+ return SSH_KNOWN_HOSTS_ERROR;
+ }
+
+ host_port = ssh_session_get_host_port(session);
+ if (host_port == NULL) {
+ return SSH_KNOWN_HOSTS_ERROR;
+ }
+
+ found = ssh_known_hosts_check_server_key(host_port,
+ session->opts.knownhosts,
+ server_pubkey,
+ pentry);
+ SAFE_FREE(host_port);
+
+ return found;
+}
+
+/**
+ * @brief Check if the servers public key for the connected session is known.
+ *
+ * This checks if we already know the public key of the server we want to
+ * connect to. This allows to detect if there is a MITM attach going on
+ * of if there have been changes on the server we don't know about.
+ *
+ * @param[in] session The SSH to validate.
+ *
+ * @returns SSH_KNOWN_HOSTS_OK: The server is known and has not changed.\n
+ * SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you
+ * are under attack or the administrator
+ * changed the key. You HAVE to warn the
+ * user about a possible attack.\n
+ * SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while
+ * we had an other type recorded. It is a
+ * possible attack.\n
+ * SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should
+ * confirm the public key hash is correct.\n
+ * SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The
+ * host is thus unknown. File will be
+ * created if host key is accepted.\n
+ * SSH_KNOWN_HOSTS_ERROR: There had been an eror checking the host.
+ */
+enum ssh_known_hosts_e ssh_session_is_known_server(ssh_session session)
+{
+ return ssh_session_get_known_hosts_entry(session, NULL);
+}
diff --git a/src/legacy.c b/src/legacy.c
index 3f09992..c35ec33 100644
--- a/src/legacy.c
+++ b/src/legacy.c
@@ -33,6 +33,7 @@
#include <libssh/session.h>
#include <libssh/server.h>
#include <libssh/buffer.h>
+#include <libssh/dh.h>
#include <libssh/pki.h>
#include "libssh/pki_priv.h"
#include <libssh/misc.h>
@@ -357,11 +358,13 @@ void publickey_free(ssh_public_key key) {
#endif
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
#ifdef HAVE_LIBGCRYPT
gcry_sexp_release(key->rsa_pub);
#elif defined HAVE_LIBCRYPTO
RSA_free(key->rsa_pub);
+#elif defined HAVE_LIBMBEDCRYPTO
+ mbedtls_pk_free(key->rsa_pub);
+ SAFE_FREE(key->rsa_pub);
#endif
break;
default:
@@ -463,6 +466,9 @@ void privatekey_free(ssh_private_key prv) {
#elif defined HAVE_LIBCRYPTO
DSA_free(prv->dsa_priv);
RSA_free(prv->rsa_priv);
+#elif defined HAVE_LIBMBEDCRYPTO
+ mbedtls_pk_free(prv->rsa_priv);
+ SAFE_FREE(prv->rsa_priv);
#endif
memset(prv, 0, sizeof(struct ssh_private_key_struct));
SAFE_FREE(prv);
@@ -695,12 +701,24 @@ int ssh_try_publickey_from_file(ssh_session session,
return 0;
}
-ssh_string ssh_get_pubkey(ssh_session session){
- if(session==NULL || session->current_crypto ==NULL ||
- session->current_crypto->server_pubkey==NULL)
- return NULL;
- else
- return ssh_string_copy(session->current_crypto->server_pubkey);
+ssh_string ssh_get_pubkey(ssh_session session)
+{
+ ssh_string pubkey_blob = NULL;
+ int rc;
+
+ if (session == NULL ||
+ session->current_crypto == NULL ||
+ session->current_crypto->server_pubkey == NULL) {
+ return NULL;
+ }
+
+ rc = ssh_dh_get_current_server_publickey_blob(session,
+ &pubkey_blob);
+ if (rc != 0) {
+ return NULL;
+ }
+
+ return pubkey_blob;
}
/****************************************************************************
diff --git a/src/libcrypto.c b/src/libcrypto.c
index 59c9956..b24a18f 100644
--- a/src/libcrypto.c
+++ b/src/libcrypto.c
@@ -70,6 +70,8 @@ struct ssh_mac_ctx_struct {
} ctx;
};
+static int libcrypto_initialized = 0;
+
void ssh_reseed(void){
#ifndef _WIN32
struct timeval tv;
@@ -78,6 +80,34 @@ void ssh_reseed(void){
#endif
}
+/**
+ * @brief Get random bytes
+ *
+ * Make sure to always check the return code of this function!
+ *
+ * @param[in] where The buffer to fill with random bytes
+ *
+ * @param[in] len The size of the buffer to fill.
+ *
+ * @param[in] strong Use a strong or private RNG source.
+ *
+ * @return 1 on success, 0 on error.
+ */
+int ssh_get_random(void *where, int len, int strong)
+{
+#ifdef HAVE_OPENSSL_RAND_PRIV_BYTES
+ if (strong) {
+ /* Returns -1 when not supported, 0 on error, 1 on success */
+ return !!RAND_priv_bytes(where, len);
+ }
+#else
+ (void)strong;
+#endif /* HAVE_RAND_PRIV_BYTES */
+
+ /* Returns -1 when not supported, 0 on error, 1 on success */
+ return !!RAND_bytes(where, len);
+}
+
SHACTX sha1_init(void)
{
int rc;
@@ -470,10 +500,6 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher) {
cipher->cipher = EVP_bf_cbc();
break;
/* ciphers not using EVP */
- case SSH_3DES_CBC_SSH1:
- case SSH_DES_CBC_SSH1:
- SSH_LOG(SSH_LOG_WARNING, "This cipher should not use evp_cipher_init");
- break;
case SSH_NO_CIPHER:
SSH_LOG(SSH_LOG_WARNING, "No valid ciphertype found");
break;
@@ -529,7 +555,10 @@ static void evp_cipher_encrypt(struct ssh_cipher_struct *cipher,
return;
}
if (outlen != (int)len){
- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate: output size %d for %zu in", outlen, len);
+ SSH_LOG(SSH_LOG_WARNING,
+ "EVP_EncryptUpdate: output size %d for %lu in",
+ outlen,
+ len);
return;
}
}
@@ -547,7 +576,10 @@ static void evp_cipher_decrypt(struct ssh_cipher_struct *cipher,
return;
}
if (outlen != (int)len){
- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptUpdate: output size %d for %zu in", outlen, len);
+ SSH_LOG(SSH_LOG_WARNING,
+ "EVP_DecryptUpdate: output size %d for %lu in",
+ outlen,
+ len);
return;
}
}
@@ -606,100 +638,11 @@ static void aes_ctr_encrypt(struct ssh_cipher_struct *cipher, void *in, void *ou
}
static void aes_ctr_cleanup(struct ssh_cipher_struct *cipher){
- BURN_BUFFER(cipher->aes_key, sizeof(*cipher->aes_key));
+ explicit_bzero(cipher->aes_key, sizeof(*cipher->aes_key));
SAFE_FREE(cipher->aes_key);
}
#endif /* HAVE_OPENSSL_EVP_AES_CTR */
-#ifdef HAS_DES
-
-typedef uint8_t des_iv_t[8];
-
-struct ssh_3des_key_schedule {
- DES_key_schedule keys[3];
- union {
- des_iv_t v[3];
- uint8_t *c;
- } ivs;
-};
-
-/* 3des cbc for SSH-1 has no suitable EVP construct and requires
- * a custom key setup
- */
-static int des3_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV){
- DES_cblock *keys = key;
-
- DES_set_odd_parity(&keys[0]);
- DES_set_odd_parity(&keys[1]);
- DES_set_odd_parity(&keys[2]);
-
- cipher->des3_key = malloc(sizeof (struct ssh_3des_key_schedule));
- if (cipher->des3_key == NULL){
- return SSH_ERROR;
- }
- DES_set_key_unchecked(&keys[0], &cipher->des3_key->keys[0]);
- DES_set_key_unchecked(&keys[1], &cipher->des3_key->keys[1]);
- DES_set_key_unchecked(&keys[2], &cipher->des3_key->keys[2]);
- memcpy(cipher->des3_key->ivs.v, IV, 24);
- return SSH_OK;
-}
-
-static void des3_1_encrypt(struct ssh_cipher_struct *cipher, void *in,
- void *out, unsigned long len) {
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Encrypt IV before", cipher->des3_key->ivs.c, 24);
-#endif
- DES_ncbc_encrypt(in, out, len, &cipher->des3_key->keys[0], &cipher->des3_key->ivs.v[0], 1);
- DES_ncbc_encrypt(out, in, len, &cipher->des3_key->keys[1], &cipher->des3_key->ivs.v[1], 0);
- DES_ncbc_encrypt(in, out, len, &cipher->des3_key->keys[2], &cipher->des3_key->ivs.v[2], 1);
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Encrypt IV after", cipher->des3_key->ivs.c, 24);
-#endif
-}
-
-static void des3_1_decrypt(struct ssh_cipher_struct *cipher, void *in,
- void *out, unsigned long len) {
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Decrypt IV before", cipher->des3_key->ivs.c, 24);
-#endif
-
- DES_ncbc_encrypt(in, out, len, &cipher->des3_key->keys[2], &cipher->des3_key->ivs.v[0], 0);
- DES_ncbc_encrypt(out, in, len, &cipher->des3_key->keys[1], &cipher->des3_key->ivs.v[1], 1);
- DES_ncbc_encrypt(in, out, len, &cipher->des3_key->keys[0], &cipher->des3_key->ivs.v[2], 0);
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Decrypt IV after", cipher->des3_key->ivs.c, 24);
-#endif
-}
-
-static int des1_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
- DES_set_odd_parity(key);
-
- cipher->des3_key = malloc(sizeof (struct ssh_3des_key_schedule));
- if (cipher->des3_key == NULL){
- return SSH_ERROR;
- }
- DES_set_key_unchecked(key, &cipher->des3_key->keys[0]);
- memcpy(cipher->des3_key->ivs.v, IV, 8);
- return SSH_OK;
-}
-
-static void des1_1_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
- unsigned long len){
- DES_ncbc_encrypt(in, out, len, &cipher->des3_key->keys[0], &cipher->des3_key->ivs.v[0], 1);
-}
-
-static void des1_1_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
- unsigned long len){
- DES_ncbc_encrypt(in,out,len, &cipher->des3_key->keys[0], &cipher->des3_key->ivs.v[0], 0);
-}
-
-static void des_cleanup(struct ssh_cipher_struct *cipher){
- BURN_BUFFER(cipher->des3_key, sizeof(*cipher->des3_key));
- SAFE_FREE(cipher->des3_key);
-}
-
-#endif /* HAS_DES */
/*
* The table of supported ciphers
@@ -837,39 +780,65 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
.decrypt = evp_cipher_decrypt,
.cleanup = evp_cipher_cleanup
},
+#endif /* HAS_DES */
{
- .name = "3des-cbc-ssh1",
- .blocksize = 8,
- .ciphertype = SSH_3DES_CBC_SSH1,
- .keysize = 192,
- .set_encrypt_key = des3_set_key,
- .set_decrypt_key = des3_set_key,
- .encrypt = des3_1_encrypt,
- .decrypt = des3_1_decrypt,
- .cleanup = des_cleanup
- },
- {
- .name = "des-cbc-ssh1",
- .blocksize = 8,
- .ciphertype = SSH_DES_CBC_SSH1,
- .keysize = 64,
- .set_encrypt_key = des1_set_key,
- .set_decrypt_key = des1_set_key,
- .encrypt = des1_1_encrypt,
- .decrypt = des1_1_decrypt,
- .cleanup = des_cleanup
+ .name = "chacha20-poly1305@openssh.com"
},
-#endif /* HAS_DES */
{
.name = NULL
}
};
-
struct ssh_cipher_struct *ssh_get_ciphertab(void)
{
return ssh_ciphertab;
}
-#endif /* LIBCRYPTO */
+/**
+ * @internal
+ * @brief Initialize libcrypto's subsystem
+ */
+int ssh_crypto_init(void)
+{
+ size_t i;
+
+ if (libcrypto_initialized) {
+ return SSH_OK;
+ }
+
+ OpenSSL_add_all_algorithms();
+
+ for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
+ int cmp;
+
+ cmp = strcmp(ssh_ciphertab[i].name, "chacha20-poly1305@openssh.com");
+ if (cmp == 0) {
+ memcpy(&ssh_ciphertab[i],
+ ssh_get_chacha20poly1305_cipher(),
+ sizeof(struct ssh_cipher_struct));
+ break;
+ }
+ }
+
+ libcrypto_initialized = 1;
+
+ return SSH_OK;
+}
+
+/**
+ * @internal
+ * @brief Finalize libcrypto's subsystem
+ */
+void ssh_crypto_finalize(void)
+{
+ if (!libcrypto_initialized) {
+ return;
+ }
+
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+ libcrypto_initialized = 0;
+}
+
+#endif /* LIBCRYPTO */
diff --git a/src/libgcrypt.c b/src/libgcrypt.c
index 0e85d5d..f004ffe 100644
--- a/src/libgcrypt.c
+++ b/src/libgcrypt.c
@@ -20,6 +20,8 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -38,6 +40,8 @@ struct ssh_mac_ctx_struct {
gcry_md_hd_t ctx;
};
+static int libgcrypt_initialized = 0;
+
static int alloc_key(struct ssh_cipher_struct *cipher) {
cipher->key = malloc(cipher->keylen);
if (cipher->key == NULL) {
@@ -48,7 +52,18 @@ static int alloc_key(struct ssh_cipher_struct *cipher) {
}
void ssh_reseed(void){
- }
+}
+
+int ssh_get_random(void *where, int len, int strong)
+{
+ /* variable not used in gcrypt */
+ (void) strong;
+
+ /* not using GCRY_VERY_STRONG_RANDOM which is a bit overkill */
+ gcry_randomize(where,len,GCRY_STRONG_RANDOM);
+
+ return 1;
+}
SHACTX sha1_init(void) {
SHACTX ctx = NULL;
@@ -392,28 +407,6 @@ static void aes_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
}
-static int des1_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV){
- if(!cipher->key){
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[0], key, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[0], IV, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- }
- return 0;
-}
-
static int des3_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
if (cipher->key == NULL) {
if (alloc_key(cipher) < 0) {
@@ -437,17 +430,6 @@ static int des3_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
return 0;
}
-
-static void des1_1_encrypt(struct ssh_cipher_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
-}
-
-static void des1_1_decrypt(struct ssh_cipher_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
-}
-
static void des3_encrypt(struct ssh_cipher_struct *cipher, void *in,
void *out, unsigned long len) {
gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
@@ -458,71 +440,6 @@ static void des3_decrypt(struct ssh_cipher_struct *cipher, void *in,
gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
}
-static int des3_1_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[0], key, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[0], IV, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
-
- if (gcry_cipher_open(&cipher->key[1], GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[1], (unsigned char *)key + 8, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[1], (unsigned char *)IV + 8, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
-
- if (gcry_cipher_open(&cipher->key[2], GCRY_CIPHER_DES,
- GCRY_CIPHER_MODE_CBC, 0)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setkey(cipher->key[2], (unsigned char *)key + 16, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- if (gcry_cipher_setiv(cipher->key[2], (unsigned char *)IV + 16, 8)) {
- SAFE_FREE(cipher->key);
- return -1;
- }
- }
-
- return 0;
-}
-
-static void des3_1_encrypt(struct ssh_cipher_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
- gcry_cipher_decrypt(cipher->key[1], in, len, out, len);
- gcry_cipher_encrypt(cipher->key[2], out, len, in, len);
-}
-
-static void des3_1_decrypt(struct ssh_cipher_struct *cipher, void *in,
- void *out, unsigned long len) {
- gcry_cipher_decrypt(cipher->key[2], out, len, in, len);
- gcry_cipher_encrypt(cipher->key[1], in, len, out, len);
- gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
-}
-
/* the table of supported ciphers */
static struct ssh_cipher_struct ssh_ciphertab[] = {
{
@@ -614,26 +531,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
.decrypt = des3_decrypt
},
{
- .name = "3des-cbc-ssh1",
- .blocksize = 8,
- .keylen = sizeof(gcry_cipher_hd_t) * 3,
- .key = NULL,
- .keysize = 192,
- .set_encrypt_key = des3_1_set_key,
- .set_decrypt_key = des3_1_set_key,
- .encrypt = des3_1_encrypt,
- .decrypt = des3_1_decrypt
- },
- {
- .name = "des-cbc-ssh1",
- .blocksize = 8,
- .keylen = sizeof(gcry_cipher_hd_t),
- .key = NULL,
- .keysize = 64,
- .set_encrypt_key = des1_set_key,
- .set_decrypt_key = des1_set_key,
- .encrypt = des1_1_encrypt,
- .decrypt = des1_1_decrypt
+ .name = "chacha20-poly1305@openssh.com"
},
{
.name = NULL,
@@ -703,4 +601,63 @@ fail:
return result;
}
+
+/**
+ * @internal
+ *
+ * @brief Initialize libgcrypt's subsystem
+ */
+int ssh_crypto_init(void)
+{
+ size_t i;
+
+ if (libgcrypt_initialized) {
+ return SSH_OK;
+ }
+
+ gcry_check_version(NULL);
+
+ /* While the secure memory is not set up */
+ gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+
+ if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P, 0)) {
+ gcry_control(GCRYCTL_INIT_SECMEM, 4096);
+ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
+ }
+
+ /* Re-enable warning */
+ gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
+
+ for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
+ int cmp;
+ cmp = strcmp(ssh_ciphertab[i].name, "chacha20-poly1305@openssh.com");
+ if (cmp == 0) {
+ memcpy(&ssh_ciphertab[i],
+ ssh_get_chacha20poly1305_cipher(),
+ sizeof(struct ssh_cipher_struct));
+ break;
+ }
+ }
+
+ libgcrypt_initialized = 1;
+
+ return SSH_OK;
+}
+
+/**
+ * @internal
+ *
+ * @brief Finalize libgcrypt's subsystem
+ */
+void ssh_crypto_finalize(void)
+{
+ if (!libgcrypt_initialized) {
+ return;
+ }
+
+ gcry_control(GCRYCTL_TERM_SECMEM);
+
+ libgcrypt_initialized = 0;
+}
+
#endif
diff --git a/src/libmbedcrypto.c b/src/libmbedcrypto.c
new file mode 100644
index 0000000..10a3527
--- /dev/null
+++ b/src/libmbedcrypto.c
@@ -0,0 +1,1014 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "libssh/wrapper.h"
+#include "libssh/crypto.h"
+#include "libssh/priv.h"
+
+#ifdef HAVE_LIBMBEDCRYPTO
+#include <mbedtls/md.h>
+
+struct ssh_mac_ctx_struct {
+ enum ssh_mac_e mac_type;
+ mbedtls_md_context_t ctx;
+};
+static int libmbedcrypto_initialized = 0;
+
+void ssh_reseed(void)
+{
+ mbedtls_ctr_drbg_reseed(&ssh_mbedtls_ctr_drbg, NULL, 0);
+}
+
+int ssh_get_random(void *where, int len, int strong)
+{
+ return ssh_mbedtls_random(where, len, strong);
+}
+
+SHACTX sha1_init(void)
+{
+ SHACTX ctx = NULL;
+ int rc;
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+
+ if (md_info == NULL) {
+ return NULL;
+ }
+
+ ctx = malloc(sizeof(mbedtls_md_context_t));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ mbedtls_md_init(ctx);
+
+ rc = mbedtls_md_setup(ctx, md_info, 0);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void sha1_update(SHACTX c, const void *data, unsigned long len)
+{
+ mbedtls_md_update(c, data, len);
+}
+
+void sha1_final(unsigned char *md, SHACTX c)
+{
+ mbedtls_md_finish(c, md);
+ mbedtls_md_free(c);
+ SAFE_FREE(c);
+}
+
+void sha1(unsigned char *digest, int len, unsigned char *hash)
+{
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+ if (md_info != NULL) {
+ mbedtls_md(md_info, digest, len, hash);
+ }
+}
+
+static mbedtls_md_type_t nid_to_md_algo(int nid)
+{
+ switch (nid) {
+ case NID_mbedtls_nistp256:
+ return MBEDTLS_MD_SHA256;
+ case NID_mbedtls_nistp384:
+ return MBEDTLS_MD_SHA384;
+ case NID_mbedtls_nistp521:
+ return MBEDTLS_MD_SHA512;
+ }
+ return MBEDTLS_MD_NONE;
+}
+
+void evp(int nid, unsigned char *digest, int len,
+ unsigned char *hash, unsigned int *hlen)
+{
+ mbedtls_md_type_t algo = nid_to_md_algo(nid);
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(algo);
+
+
+ if (md_info != NULL) {
+ *hlen = mbedtls_md_get_size(md_info);
+ mbedtls_md(md_info, digest, len, hash);
+ }
+}
+
+EVPCTX evp_init(int nid)
+{
+ EVPCTX ctx = NULL;
+ int rc;
+ mbedtls_md_type_t algo = nid_to_md_algo(nid);
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(algo);
+
+ if (md_info == NULL) {
+ return NULL;
+ }
+
+ ctx = malloc(sizeof(mbedtls_md_context_t));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ mbedtls_md_init(ctx);
+
+ rc = mbedtls_md_setup(ctx, md_info, 0);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void evp_update(EVPCTX ctx, const void *data, unsigned long len)
+{
+ mbedtls_md_update(ctx, data, len);
+}
+
+void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
+{
+ *mdlen = mbedtls_md_get_size(ctx->md_info);
+ mbedtls_md_hmac_finish(ctx, md);
+ mbedtls_md_free(ctx);
+ SAFE_FREE(ctx);
+}
+
+SHA256CTX sha256_init(void)
+{
+ SHA256CTX ctx = NULL;
+ int rc;
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+
+ if (md_info == NULL) {
+ return NULL;
+ }
+
+ ctx = malloc(sizeof(mbedtls_md_context_t));
+ if(ctx == NULL) {
+ return NULL;
+ }
+
+ mbedtls_md_init(ctx);
+
+ rc = mbedtls_md_setup(ctx, md_info, 0);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void sha256_update(SHA256CTX c, const void *data, unsigned long len)
+{
+ mbedtls_md_update(c, data, len);
+}
+
+void sha256_final(unsigned char *md, SHA256CTX c)
+{
+ mbedtls_md_finish(c, md);
+ mbedtls_md_free(c);
+ SAFE_FREE(c);
+}
+
+void sha256(unsigned char *digest, int len, unsigned char *hash)
+{
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+ if (md_info != NULL) {
+ mbedtls_md(md_info, digest, len, hash);
+ }
+}
+
+SHA384CTX sha384_init(void)
+{
+ SHA384CTX ctx = NULL;
+ int rc;
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
+
+ if (md_info == NULL) {
+ return NULL;
+ }
+
+ ctx = malloc(sizeof(mbedtls_md_context_t));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ mbedtls_md_init(ctx);
+
+ rc = mbedtls_md_setup(ctx, md_info, 0);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void sha384_update(SHA384CTX c, const void *data, unsigned long len)
+{
+ mbedtls_md_update(c, data, len);
+}
+
+void sha384_final(unsigned char *md, SHA384CTX c)
+{
+ mbedtls_md_finish(c, md);
+ mbedtls_md_free(c);
+ SAFE_FREE(c);
+}
+
+void sha384(unsigned char *digest, int len, unsigned char *hash)
+{
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
+ if (md_info != NULL) {
+ mbedtls_md(md_info, digest, len, hash);
+ }
+}
+
+SHA512CTX sha512_init(void)
+{
+ SHA512CTX ctx = NULL;
+ int rc;
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
+ if (md_info == NULL) {
+ return NULL;
+ }
+
+ ctx = malloc(sizeof(mbedtls_md_context_t));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ mbedtls_md_init(ctx);
+
+ rc = mbedtls_md_setup(ctx, md_info, 0);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void sha512_update(SHA512CTX c, const void *data, unsigned long len)
+{
+ mbedtls_md_update(c, data, len);
+}
+
+void sha512_final(unsigned char *md, SHA512CTX c)
+{
+ mbedtls_md_finish(c, md);
+ mbedtls_md_free(c);
+ SAFE_FREE(c);
+}
+
+void sha512(unsigned char *digest, int len, unsigned char *hash)
+{
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
+ if (md_info != NULL) {
+ mbedtls_md(md_info, digest, len, hash);
+ }
+}
+
+MD5CTX md5_init(void)
+{
+ MD5CTX ctx = NULL;
+ int rc;
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
+ if (md_info == NULL) {
+ return NULL;
+ }
+
+ ctx = malloc(sizeof(mbedtls_md_context_t));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ mbedtls_md_init(ctx);
+
+ rc = mbedtls_md_setup(ctx, md_info, 0);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ rc = mbedtls_md_starts(ctx);
+ if (rc != 0) {
+ SAFE_FREE(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+void md5_update(MD5CTX c, const void *data, unsigned long len) {
+ mbedtls_md_update(c, data, len);
+}
+
+void md5_final(unsigned char *md, MD5CTX c)
+{
+ mbedtls_md_finish(c, md);
+ mbedtls_md_free(c);
+ SAFE_FREE(c);
+}
+
+ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type)
+{
+ ssh_mac_ctx ctx = malloc(sizeof (struct ssh_mac_ctx_struct));
+ const mbedtls_md_info_t *md_info;
+ int rc;
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ ctx->mac_type=type;
+ switch(type) {
+ case SSH_MAC_SHA1:
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+ break;
+ case SSH_MAC_SHA256:
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+ break;
+ case SSH_MAC_SHA384:
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
+ break;
+ case SSH_MAC_SHA512:
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
+ break;
+ default:
+ goto error;
+ }
+
+ if (md_info == NULL) {
+ goto error;
+ }
+
+ mbedtls_md_init(&ctx->ctx);
+
+ rc = mbedtls_md_setup(&ctx->ctx, md_info, 0);
+ if (rc != 0) {
+ goto error;
+ }
+
+ rc = mbedtls_md_starts(&ctx->ctx);
+ if (rc != 0) {
+ goto error;
+ }
+
+ return ctx;
+
+error:
+ SAFE_FREE(ctx);
+ return NULL;
+}
+
+void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len)
+{
+ mbedtls_md_update(&ctx->ctx, data, len);
+}
+
+void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx)
+{
+ mbedtls_md_finish(&ctx->ctx, md);
+ mbedtls_md_free(&ctx->ctx);
+ SAFE_FREE(ctx);
+}
+
+HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type)
+{
+ HMACCTX ctx = NULL;
+ const mbedtls_md_info_t *md_info = NULL;
+ int rc;
+
+ ctx = malloc(sizeof(mbedtls_md_context_t));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ switch (type) {
+ case SSH_HMAC_SHA1:
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
+ break;
+ case SSH_HMAC_SHA256:
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
+ break;
+ case SSH_HMAC_SHA384:
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
+ break;
+ case SSH_HMAC_SHA512:
+ md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
+ break;
+ default:
+ goto error;
+ }
+
+ mbedtls_md_init(ctx);
+
+ if (md_info == NULL) {
+ goto error;
+ }
+
+ rc = mbedtls_md_setup(ctx, md_info, 1);
+ if (rc != 0) {
+ goto error;
+ }
+
+ rc = mbedtls_md_hmac_starts(ctx, key, len);
+ if (rc != 0) {
+ goto error;
+ }
+
+ return ctx;
+
+error:
+ mbedtls_md_free(ctx);
+ SAFE_FREE(ctx);
+ return NULL;
+}
+
+void hmac_update(HMACCTX c, const void *data, unsigned long len)
+{
+ mbedtls_md_hmac_update(c, data, len);
+}
+
+void hmac_final(HMACCTX c, unsigned char *hashmacbuf, unsigned int *len)
+{
+ *len = mbedtls_md_get_size(c->md_info);
+ mbedtls_md_hmac_finish(c, hashmacbuf);
+ mbedtls_md_free(c);
+ SAFE_FREE(c);
+}
+
+static int cipher_set_encrypt_key(struct ssh_cipher_struct *cipher, void *key,
+ void *IV)
+{
+
+ const mbedtls_cipher_info_t *cipher_info = NULL;
+ int rc;
+
+ mbedtls_cipher_init(&cipher->encrypt_ctx);
+ cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+ rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, key,
+ cipher_info->key_bitlen,
+ MBEDTLS_ENCRYPT);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_reset(&cipher->encrypt_ctx);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+ goto error;
+ }
+
+ return SSH_OK;
+error:
+ mbedtls_cipher_free(&cipher->encrypt_ctx);
+ return SSH_ERROR;
+}
+
+static int cipher_set_encrypt_key_cbc(struct ssh_cipher_struct *cipher, void *key,
+ void *IV)
+{
+
+ const mbedtls_cipher_info_t *cipher_info = NULL;
+ int rc;
+
+ mbedtls_cipher_init(&cipher->encrypt_ctx);
+ cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+ rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, key,
+ cipher_info->key_bitlen,
+ MBEDTLS_ENCRYPT);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+ goto error;
+ }
+
+ /* libssh only encypts and decrypts packets that are multiples of a block
+ * size, and no padding is used */
+ rc = mbedtls_cipher_set_padding_mode(&cipher->encrypt_ctx,
+ MBEDTLS_PADDING_NONE);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_reset(&cipher->encrypt_ctx);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+ goto error;
+ }
+
+ return SSH_OK;
+error:
+ mbedtls_cipher_free(&cipher->encrypt_ctx);
+ return SSH_ERROR;
+}
+
+static int cipher_set_decrypt_key(struct ssh_cipher_struct *cipher, void *key,
+ void *IV)
+{
+ const mbedtls_cipher_info_t *cipher_info = NULL;
+ int rc;
+
+ mbedtls_cipher_init(&cipher->decrypt_ctx);
+ cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+ rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, key,
+ cipher_info->key_bitlen,
+ MBEDTLS_DECRYPT);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+ goto error;
+ }
+
+ mbedtls_cipher_reset(&cipher->decrypt_ctx);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+ goto error;
+ }
+
+ return SSH_OK;
+error:
+ mbedtls_cipher_free(&cipher->decrypt_ctx);
+ return SSH_ERROR;
+}
+
+static int cipher_set_decrypt_key_cbc(struct ssh_cipher_struct *cipher, void *key,
+ void *IV)
+{
+ const mbedtls_cipher_info_t *cipher_info;
+ int rc;
+
+ mbedtls_cipher_init(&cipher->decrypt_ctx);
+ cipher_info = mbedtls_cipher_info_from_type(cipher->type);
+
+ rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, key,
+ cipher_info->key_bitlen,
+ MBEDTLS_DECRYPT);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
+ goto error;
+ }
+
+ rc = mbedtls_cipher_set_padding_mode(&cipher->decrypt_ctx,
+ MBEDTLS_PADDING_NONE);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed");
+ goto error;
+ }
+
+ mbedtls_cipher_reset(&cipher->decrypt_ctx);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
+ goto error;
+ }
+
+ return SSH_OK;
+error:
+ mbedtls_cipher_free(&cipher->decrypt_ctx);
+ return SSH_ERROR;
+}
+
+static void cipher_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
+ unsigned long len)
+{
+ size_t outlen = 0;
+ size_t total_len = 0;
+ int rc = 0;
+ rc = mbedtls_cipher_update(&cipher->encrypt_ctx, in, len, out, &outlen);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during encryption");
+ return;
+ }
+
+ total_len += outlen;
+
+ if (total_len == len) {
+ return;
+ }
+
+ rc = mbedtls_cipher_finish(&cipher->encrypt_ctx, (unsigned char *) out + outlen,
+ &outlen);
+
+ total_len += outlen;
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_finish failed during encryption");
+ return;
+ }
+
+ if (total_len != len) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
+ outlen, len);
+ return;
+ }
+
+}
+
+static void cipher_encrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void *out,
+ unsigned long len)
+{
+ size_t outlen = 0;
+ int rc = 0;
+ rc = mbedtls_cipher_update(&cipher->encrypt_ctx, in, len, out, &outlen);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during encryption");
+ return;
+ }
+
+ if (outlen != len) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
+ outlen, len);
+ return;
+ }
+
+}
+
+static void cipher_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
+ unsigned long len)
+{
+ size_t outlen = 0;
+ int rc = 0;
+ size_t total_len = 0;
+
+ rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption");
+ return;
+ }
+
+ total_len += outlen;
+
+ if (total_len == len) {
+ return;
+ }
+
+ rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, (unsigned char *) out +
+ outlen, &outlen);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption");
+ return;
+ }
+
+ total_len += outlen;
+
+ if (total_len != len) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
+ outlen, len);
+ return;
+ }
+
+}
+
+static void cipher_decrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void *out,
+ unsigned long len)
+{
+ size_t outlen = 0;
+ int rc = 0;
+ rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption");
+ return;
+ }
+
+ /* MbedTLS caches the last block when decrypting with cbc.
+ * By calling finish the block is flushed to out, however the unprocessed
+ * data counter is not reset.
+ * Calling mbedtls_cipher_reset resets the unprocessed data counter.
+ */
+ if (outlen == 0) {
+ rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, out, &outlen);
+ } else if (outlen == len) {
+ return;
+ } else {
+ rc = mbedtls_cipher_finish(&cipher->decrypt_ctx, (unsigned char *) out +
+ outlen , &outlen);
+ }
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_finish failed during decryption");
+ return;
+ }
+
+ rc = mbedtls_cipher_reset(&cipher->decrypt_ctx);
+
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption");
+ return;
+ }
+
+ if (outlen != len) {
+ SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu",
+ outlen, len);
+ return;
+ }
+
+}
+
+static void cipher_cleanup(struct ssh_cipher_struct *cipher)
+{
+ mbedtls_cipher_free(&cipher->encrypt_ctx);
+ mbedtls_cipher_free(&cipher->decrypt_ctx);
+}
+
+static struct ssh_cipher_struct ssh_ciphertab[] = {
+ {
+ .name = "blowfish-cbc",
+ .blocksize = 8,
+ .keysize = 128,
+ .type = MBEDTLS_CIPHER_BLOWFISH_CBC,
+ .set_encrypt_key = cipher_set_encrypt_key_cbc,
+ .set_decrypt_key = cipher_set_decrypt_key_cbc,
+ .encrypt = cipher_encrypt_cbc,
+ .decrypt = cipher_decrypt_cbc,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "aes128-ctr",
+ .blocksize = 16,
+ .keysize = 128,
+ .type = MBEDTLS_CIPHER_AES_128_CTR,
+ .set_encrypt_key = cipher_set_encrypt_key,
+ .set_decrypt_key = cipher_set_decrypt_key,
+ .encrypt = cipher_encrypt,
+ .decrypt = cipher_decrypt,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "aes192-ctr",
+ .blocksize = 16,
+ .keysize = 192,
+ .type = MBEDTLS_CIPHER_AES_192_CTR,
+ .set_encrypt_key = cipher_set_encrypt_key,
+ .set_decrypt_key = cipher_set_decrypt_key,
+ .encrypt = cipher_encrypt,
+ .decrypt = cipher_decrypt,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "aes256-ctr",
+ .blocksize = 16,
+ .keysize = 256,
+ .type = MBEDTLS_CIPHER_AES_256_CTR,
+ .set_encrypt_key = cipher_set_encrypt_key,
+ .set_decrypt_key = cipher_set_decrypt_key,
+ .encrypt = cipher_encrypt,
+ .decrypt = cipher_decrypt,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "aes128-cbc",
+ .blocksize = 16,
+ .keysize = 128,
+ .type = MBEDTLS_CIPHER_AES_128_CBC,
+ .set_encrypt_key = cipher_set_encrypt_key_cbc,
+ .set_decrypt_key = cipher_set_decrypt_key_cbc,
+ .encrypt = cipher_encrypt_cbc,
+ .decrypt = cipher_decrypt_cbc,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "aes192-cbc",
+ .blocksize = 16,
+ .keysize = 192,
+ .type = MBEDTLS_CIPHER_AES_192_CBC,
+ .set_encrypt_key = cipher_set_encrypt_key_cbc,
+ .set_decrypt_key = cipher_set_decrypt_key_cbc,
+ .encrypt = cipher_encrypt_cbc,
+ .decrypt = cipher_decrypt_cbc,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "aes256-cbc",
+ .blocksize = 16,
+ .keysize = 256,
+ .type = MBEDTLS_CIPHER_AES_256_CBC,
+ .set_encrypt_key = cipher_set_encrypt_key_cbc,
+ .set_decrypt_key = cipher_set_decrypt_key_cbc,
+ .encrypt = cipher_encrypt_cbc,
+ .decrypt = cipher_decrypt_cbc,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "3des-cbc",
+ .blocksize = 8,
+ .keysize = 192,
+ .type = MBEDTLS_CIPHER_DES_EDE3_CBC,
+ .set_encrypt_key = cipher_set_encrypt_key_cbc,
+ .set_decrypt_key = cipher_set_decrypt_key_cbc,
+ .encrypt = cipher_encrypt_cbc,
+ .decrypt = cipher_decrypt_cbc,
+ .cleanup = cipher_cleanup
+ },
+ {
+ .name = "chacha20-poly1305@openssh.com"
+ },
+ {
+ .name = NULL,
+ .blocksize = 0,
+ .keysize = 0,
+ .set_encrypt_key = NULL,
+ .set_decrypt_key = NULL,
+ .encrypt = NULL,
+ .decrypt = NULL,
+ .cleanup = NULL
+ }
+};
+
+struct ssh_cipher_struct *ssh_get_ciphertab(void)
+{
+ return ssh_ciphertab;
+}
+
+int ssh_crypto_init(void)
+{
+ size_t i;
+ int rc;
+
+ if (libmbedcrypto_initialized) {
+ return SSH_OK;
+ }
+
+ mbedtls_entropy_init(&ssh_mbedtls_entropy);
+ mbedtls_ctr_drbg_init(&ssh_mbedtls_ctr_drbg);
+
+ rc = mbedtls_ctr_drbg_seed(&ssh_mbedtls_ctr_drbg, mbedtls_entropy_func,
+ &ssh_mbedtls_entropy, NULL, 0);
+ if (rc != 0) {
+ mbedtls_ctr_drbg_free(&ssh_mbedtls_ctr_drbg);
+ }
+
+ for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
+ int cmp;
+
+ cmp = strcmp(ssh_ciphertab[i].name, "chacha20-poly1305@openssh.com");
+ if (cmp == 0) {
+ memcpy(&ssh_ciphertab[i],
+ ssh_get_chacha20poly1305_cipher(),
+ sizeof(struct ssh_cipher_struct));
+ break;
+ }
+ }
+
+ libmbedcrypto_initialized = 1;
+
+ return SSH_OK;
+}
+
+int ssh_mbedtls_random(void *where, int len, int strong)
+{
+ int rc = 0;
+ if (strong) {
+ mbedtls_ctr_drbg_set_prediction_resistance(&ssh_mbedtls_ctr_drbg,
+ MBEDTLS_CTR_DRBG_PR_ON);
+ rc = mbedtls_ctr_drbg_random(&ssh_mbedtls_ctr_drbg, where, len);
+ mbedtls_ctr_drbg_set_prediction_resistance(&ssh_mbedtls_ctr_drbg,
+ MBEDTLS_CTR_DRBG_PR_OFF);
+ } else {
+ rc = mbedtls_ctr_drbg_random(&ssh_mbedtls_ctr_drbg, where, len);
+ }
+
+ return !rc;
+}
+
+void ssh_crypto_finalize(void)
+{
+ if (!libmbedcrypto_initialized) {
+ return;
+ }
+
+ mbedtls_ctr_drbg_free(&ssh_mbedtls_ctr_drbg);
+ mbedtls_entropy_free(&ssh_mbedtls_entropy);
+
+ libmbedcrypto_initialized = 0;
+}
+
+#endif /* HAVE_LIBMBEDCRYPTO */
diff --git a/src/libssh.map b/src/libssh.map
new file mode 100644
index 0000000..be92252
--- /dev/null
+++ b/src/libssh.map
@@ -0,0 +1,420 @@
+# This map file was created with abimap-0.3.0
+
+LIBSSH_4_5_0 # Released
+{
+ global:
+ _ssh_log;
+ buffer_free;
+ buffer_get;
+ buffer_get_len;
+ buffer_new;
+ channel_accept_x11;
+ channel_change_pty_size;
+ channel_close;
+ channel_forward_accept;
+ channel_forward_cancel;
+ channel_forward_listen;
+ channel_free;
+ channel_get_exit_status;
+ channel_get_session;
+ channel_is_closed;
+ channel_is_eof;
+ channel_is_open;
+ channel_new;
+ channel_open_forward;
+ channel_open_session;
+ channel_poll;
+ channel_read;
+ channel_read_buffer;
+ channel_read_nonblocking;
+ channel_request_env;
+ channel_request_exec;
+ channel_request_pty;
+ channel_request_pty_size;
+ channel_request_send_signal;
+ channel_request_sftp;
+ channel_request_shell;
+ channel_request_subsystem;
+ channel_request_x11;
+ channel_select;
+ channel_send_eof;
+ channel_set_blocking;
+ channel_write;
+ channel_write_stderr;
+ privatekey_free;
+ privatekey_from_file;
+ publickey_free;
+ publickey_from_file;
+ publickey_from_privatekey;
+ publickey_to_string;
+ sftp_async_read;
+ sftp_async_read_begin;
+ sftp_attributes_free;
+ sftp_canonicalize_path;
+ sftp_chmod;
+ sftp_chown;
+ sftp_client_message_free;
+ sftp_client_message_get_data;
+ sftp_client_message_get_filename;
+ sftp_client_message_get_flags;
+ sftp_client_message_get_type;
+ sftp_client_message_set_filename;
+ sftp_close;
+ sftp_closedir;
+ sftp_dir_eof;
+ sftp_extension_supported;
+ sftp_extensions_get_count;
+ sftp_extensions_get_data;
+ sftp_extensions_get_name;
+ sftp_file_set_blocking;
+ sftp_file_set_nonblocking;
+ sftp_free;
+ sftp_fstat;
+ sftp_fstatvfs;
+ sftp_fsync;
+ sftp_get_client_message;
+ sftp_get_error;
+ sftp_handle;
+ sftp_handle_alloc;
+ sftp_handle_remove;
+ sftp_init;
+ sftp_lstat;
+ sftp_mkdir;
+ sftp_new;
+ sftp_new_channel;
+ sftp_open;
+ sftp_opendir;
+ sftp_read;
+ sftp_readdir;
+ sftp_readlink;
+ sftp_rename;
+ sftp_reply_attr;
+ sftp_reply_data;
+ sftp_reply_handle;
+ sftp_reply_name;
+ sftp_reply_names;
+ sftp_reply_names_add;
+ sftp_reply_status;
+ sftp_rewind;
+ sftp_rmdir;
+ sftp_seek;
+ sftp_seek64;
+ sftp_send_client_message;
+ sftp_server_init;
+ sftp_server_new;
+ sftp_server_version;
+ sftp_setstat;
+ sftp_stat;
+ sftp_statvfs;
+ sftp_statvfs_free;
+ sftp_symlink;
+ sftp_tell;
+ sftp_tell64;
+ sftp_unlink;
+ sftp_utimes;
+ sftp_write;
+ ssh_accept;
+ ssh_add_channel_callbacks;
+ ssh_auth_list;
+ ssh_basename;
+ ssh_bind_accept;
+ ssh_bind_accept_fd;
+ ssh_bind_fd_toaccept;
+ ssh_bind_free;
+ ssh_bind_get_fd;
+ ssh_bind_listen;
+ ssh_bind_new;
+ ssh_bind_options_set;
+ ssh_bind_set_blocking;
+ ssh_bind_set_callbacks;
+ ssh_bind_set_fd;
+ ssh_blocking_flush;
+ ssh_buffer_add_data;
+ ssh_buffer_free;
+ ssh_buffer_get;
+ ssh_buffer_get_data;
+ ssh_buffer_get_len;
+ ssh_buffer_new;
+ ssh_buffer_reinit;
+ ssh_channel_accept_forward;
+ ssh_channel_accept_x11;
+ ssh_channel_cancel_forward;
+ ssh_channel_change_pty_size;
+ ssh_channel_close;
+ ssh_channel_free;
+ ssh_channel_get_exit_status;
+ ssh_channel_get_session;
+ ssh_channel_is_closed;
+ ssh_channel_is_eof;
+ ssh_channel_is_open;
+ ssh_channel_listen_forward;
+ ssh_channel_new;
+ ssh_channel_open_auth_agent;
+ ssh_channel_open_forward;
+ ssh_channel_open_reverse_forward;
+ ssh_channel_open_session;
+ ssh_channel_open_x11;
+ ssh_channel_poll;
+ ssh_channel_poll_timeout;
+ ssh_channel_read;
+ ssh_channel_read_nonblocking;
+ ssh_channel_read_timeout;
+ ssh_channel_request_auth_agent;
+ ssh_channel_request_env;
+ ssh_channel_request_exec;
+ ssh_channel_request_pty;
+ ssh_channel_request_pty_size;
+ ssh_channel_request_send_break;
+ ssh_channel_request_send_exit_signal;
+ ssh_channel_request_send_exit_status;
+ ssh_channel_request_send_signal;
+ ssh_channel_request_sftp;
+ ssh_channel_request_shell;
+ ssh_channel_request_subsystem;
+ ssh_channel_request_x11;
+ ssh_channel_select;
+ ssh_channel_send_eof;
+ ssh_channel_set_blocking;
+ ssh_channel_set_counter;
+ ssh_channel_window_size;
+ ssh_channel_write;
+ ssh_channel_write_stderr;
+ ssh_clean_pubkey_hash;
+ ssh_connect;
+ ssh_connector_free;
+ ssh_connector_new;
+ ssh_connector_set_in_channel;
+ ssh_connector_set_in_fd;
+ ssh_connector_set_out_channel;
+ ssh_connector_set_out_fd;
+ ssh_copyright;
+ ssh_dirname;
+ ssh_disconnect;
+ ssh_dump_knownhost;
+ ssh_event_add_connector;
+ ssh_event_add_fd;
+ ssh_event_add_session;
+ ssh_event_dopoll;
+ ssh_event_free;
+ ssh_event_new;
+ ssh_event_remove_connector;
+ ssh_event_remove_fd;
+ ssh_event_remove_session;
+ ssh_execute_message_callbacks;
+ ssh_finalize;
+ ssh_forward_accept;
+ ssh_forward_cancel;
+ ssh_forward_listen;
+ ssh_free;
+ ssh_get_cipher_in;
+ ssh_get_cipher_out;
+ ssh_get_clientbanner;
+ ssh_get_disconnect_message;
+ ssh_get_error;
+ ssh_get_error_code;
+ ssh_get_fd;
+ ssh_get_hexa;
+ ssh_get_hmac_in;
+ ssh_get_hmac_out;
+ ssh_get_issue_banner;
+ ssh_get_kex_algo;
+ ssh_get_log_callback;
+ ssh_get_log_level;
+ ssh_get_log_userdata;
+ ssh_get_openssh_version;
+ ssh_get_poll_flags;
+ ssh_get_pubkey;
+ ssh_get_pubkey_hash;
+ ssh_get_publickey;
+ ssh_get_publickey_hash;
+ ssh_get_random;
+ ssh_get_server_publickey;
+ ssh_get_serverbanner;
+ ssh_get_status;
+ ssh_get_version;
+ ssh_getpass;
+ ssh_gssapi_get_creds;
+ ssh_gssapi_set_creds;
+ ssh_handle_key_exchange;
+ ssh_init;
+ ssh_is_blocking;
+ ssh_is_connected;
+ ssh_is_server_known;
+ ssh_key_cmp;
+ ssh_key_free;
+ ssh_key_is_private;
+ ssh_key_is_public;
+ ssh_key_new;
+ ssh_key_type;
+ ssh_key_type_from_name;
+ ssh_key_type_to_char;
+ ssh_known_hosts_parse_line;
+ ssh_knownhosts_entry_free;
+ ssh_log;
+ ssh_message_auth_interactive_request;
+ ssh_message_auth_kbdint_is_response;
+ ssh_message_auth_password;
+ ssh_message_auth_pubkey;
+ ssh_message_auth_publickey;
+ ssh_message_auth_publickey_state;
+ ssh_message_auth_reply_pk_ok;
+ ssh_message_auth_reply_pk_ok_simple;
+ ssh_message_auth_reply_success;
+ ssh_message_auth_set_methods;
+ ssh_message_auth_user;
+ ssh_message_channel_request_channel;
+ ssh_message_channel_request_command;
+ ssh_message_channel_request_env_name;
+ ssh_message_channel_request_env_value;
+ ssh_message_channel_request_open_destination;
+ ssh_message_channel_request_open_destination_port;
+ ssh_message_channel_request_open_originator;
+ ssh_message_channel_request_open_originator_port;
+ ssh_message_channel_request_open_reply_accept;
+ ssh_message_channel_request_pty_height;
+ ssh_message_channel_request_pty_pxheight;
+ ssh_message_channel_request_pty_pxwidth;
+ ssh_message_channel_request_pty_term;
+ ssh_message_channel_request_pty_width;
+ ssh_message_channel_request_reply_success;
+ ssh_message_channel_request_subsystem;
+ ssh_message_channel_request_x11_auth_cookie;
+ ssh_message_channel_request_x11_auth_protocol;
+ ssh_message_channel_request_x11_screen_number;
+ ssh_message_channel_request_x11_single_connection;
+ ssh_message_free;
+ ssh_message_get;
+ ssh_message_global_request_address;
+ ssh_message_global_request_port;
+ ssh_message_global_request_reply_success;
+ ssh_message_reply_default;
+ ssh_message_retrieve;
+ ssh_message_service_reply_success;
+ ssh_message_service_service;
+ ssh_message_subtype;
+ ssh_message_type;
+ ssh_mkdir;
+ ssh_new;
+ ssh_options_copy;
+ ssh_options_get;
+ ssh_options_get_port;
+ ssh_options_getopt;
+ ssh_options_parse_config;
+ ssh_options_set;
+ ssh_pcap_file_close;
+ ssh_pcap_file_free;
+ ssh_pcap_file_new;
+ ssh_pcap_file_open;
+ ssh_pki_copy_cert_to_privkey;
+ ssh_pki_export_privkey_file;
+ ssh_pki_export_privkey_to_pubkey;
+ ssh_pki_export_pubkey_base64;
+ ssh_pki_export_pubkey_file;
+ ssh_pki_generate;
+ ssh_pki_import_cert_base64;
+ ssh_pki_import_cert_file;
+ ssh_pki_import_privkey_base64;
+ ssh_pki_import_privkey_file;
+ ssh_pki_import_pubkey_base64;
+ ssh_pki_import_pubkey_file;
+ ssh_pki_key_ecdsa_name;
+ ssh_print_hexa;
+ ssh_privatekey_type;
+ ssh_publickey_to_file;
+ ssh_remove_channel_callbacks;
+ ssh_scp_accept_request;
+ ssh_scp_close;
+ ssh_scp_deny_request;
+ ssh_scp_free;
+ ssh_scp_init;
+ ssh_scp_leave_directory;
+ ssh_scp_new;
+ ssh_scp_pull_request;
+ ssh_scp_push_directory;
+ ssh_scp_push_file;
+ ssh_scp_push_file64;
+ ssh_scp_read;
+ ssh_scp_request_get_filename;
+ ssh_scp_request_get_permissions;
+ ssh_scp_request_get_size;
+ ssh_scp_request_get_size64;
+ ssh_scp_request_get_warning;
+ ssh_scp_write;
+ ssh_select;
+ ssh_send_debug;
+ ssh_send_ignore;
+ ssh_send_keepalive;
+ ssh_server_init_kex;
+ ssh_service_request;
+ ssh_session_export_known_hosts_entry;
+ ssh_session_has_known_hosts_entry;
+ ssh_session_is_known_server;
+ ssh_session_update_known_hosts;
+ ssh_set_agent_channel;
+ ssh_set_agent_socket;
+ ssh_set_auth_methods;
+ ssh_set_blocking;
+ ssh_set_callbacks;
+ ssh_set_channel_callbacks;
+ ssh_set_counters;
+ ssh_set_fd_except;
+ ssh_set_fd_toread;
+ ssh_set_fd_towrite;
+ ssh_set_log_callback;
+ ssh_set_log_level;
+ ssh_set_log_userdata;
+ ssh_set_message_callback;
+ ssh_set_pcap_file;
+ ssh_set_server_callbacks;
+ ssh_silent_disconnect;
+ ssh_string_burn;
+ ssh_string_copy;
+ ssh_string_data;
+ ssh_string_fill;
+ ssh_string_free;
+ ssh_string_free_char;
+ ssh_string_from_char;
+ ssh_string_get_char;
+ ssh_string_len;
+ ssh_string_new;
+ ssh_string_to_char;
+ ssh_threads_get_noop;
+ ssh_threads_get_pthread;
+ ssh_threads_set_callbacks;
+ ssh_try_publickey_from_file;
+ ssh_userauth_agent;
+ ssh_userauth_agent_pubkey;
+ ssh_userauth_autopubkey;
+ ssh_userauth_gssapi;
+ ssh_userauth_kbdint;
+ ssh_userauth_kbdint_getanswer;
+ ssh_userauth_kbdint_getinstruction;
+ ssh_userauth_kbdint_getname;
+ ssh_userauth_kbdint_getnanswers;
+ ssh_userauth_kbdint_getnprompts;
+ ssh_userauth_kbdint_getprompt;
+ ssh_userauth_kbdint_setanswer;
+ ssh_userauth_list;
+ ssh_userauth_none;
+ ssh_userauth_offer_pubkey;
+ ssh_userauth_password;
+ ssh_userauth_privatekey_file;
+ ssh_userauth_pubkey;
+ ssh_userauth_publickey;
+ ssh_userauth_publickey_auto;
+ ssh_userauth_try_publickey;
+ ssh_version;
+ ssh_write_knownhost;
+ string_burn;
+ string_copy;
+ string_data;
+ string_fill;
+ string_free;
+ string_from_char;
+ string_len;
+ string_new;
+ string_to_char;
+ local:
+ *;
+} ;
+
diff --git a/src/log.c b/src/log.c
index 36e8777..39635cc 100644
--- a/src/log.c
+++ b/src/log.c
@@ -38,9 +38,9 @@
#include "libssh/misc.h"
#include "libssh/session.h"
-LIBSSH_THREAD int ssh_log_level;
-LIBSSH_THREAD ssh_logging_callback ssh_log_cb;
-LIBSSH_THREAD void *ssh_log_userdata;
+static LIBSSH_THREAD int ssh_log_level;
+static LIBSSH_THREAD ssh_logging_callback ssh_log_cb;
+static LIBSSH_THREAD void *ssh_log_userdata;
/**
* @defgroup libssh_log The SSH logging functions.
@@ -240,5 +240,3 @@ int ssh_set_log_userdata(void *data)
}
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/match.c b/src/match.c
index 36cc922..ab94341 100644
--- a/src/match.c
+++ b/src/match.c
@@ -35,8 +35,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config.h"
+
#include <ctype.h>
-#include <string.h>
#include <sys/types.h>
#include "libssh/priv.h"
@@ -186,5 +187,3 @@ static int match_pattern_list(const char *string, const char *pattern,
int match_hostname(const char *host, const char *pattern, unsigned int len) {
return match_pattern_list(host, pattern, len, 1);
}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/mbedcrypto_missing.c b/src/mbedcrypto_missing.c
new file mode 100644
index 0000000..44ac7dd
--- /dev/null
+++ b/src/mbedcrypto_missing.c
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "libssh/priv.h"
+#include "libssh/libmbedcrypto.h"
+
+#ifdef HAVE_LIBMBEDCRYPTO
+bignum ssh_mbedcry_bn_new(void)
+{
+ bignum bn;
+
+ bn = malloc(sizeof(mbedtls_mpi));
+ if (bn) {
+ mbedtls_mpi_init(bn);
+ }
+
+ return bn;
+}
+
+void ssh_mbedcry_bn_free(bignum bn)
+{
+ mbedtls_mpi_free(bn);
+ SAFE_FREE(bn);
+}
+
+char *ssh_mbedcry_bn2num(bignum num, int radix)
+{
+ char *buf = NULL;
+ size_t olen;
+ int rc;
+
+ rc = mbedtls_mpi_write_string(num, radix, buf, 0, &olen);
+ if (rc != 0) {
+ return NULL;
+ }
+
+ buf = malloc(olen);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ rc = mbedtls_mpi_write_string(num, radix, buf, olen, &olen);
+ if (rc != 0) {
+ SAFE_FREE(buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom)
+{
+ size_t len;
+ int rc;
+ int i;
+
+ if (bits <= 0) {
+ return 0;
+ }
+
+ len = bits / 8 + 1;
+ rc = mbedtls_mpi_fill_random(rnd, len, mbedtls_ctr_drbg_random,
+ &ssh_mbedtls_ctr_drbg);
+ if (rc != 0) {
+ return 0;
+ }
+
+ for (i = len * 8 - 1; i >= bits; i--) {
+ rc = mbedtls_mpi_set_bit(rnd, i, 0);
+ if (rc != 0) {
+ return 0;
+ }
+ }
+
+ if (top == 0) {
+ rc = mbedtls_mpi_set_bit(rnd, bits - 1, 0);
+ }
+
+ if (top == 1) {
+ if (bits < 2) {
+ return 0;
+ }
+
+ rc = mbedtls_mpi_set_bit(rnd, bits - 2, 0);
+ if (rc != 0) {
+ return 0;
+ }
+ }
+
+ if (bottom) {
+ rc = mbedtls_mpi_set_bit(rnd, 0, 1);
+ if (rc != 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int ssh_mbedcry_is_bit_set(bignum num, size_t pos)
+{
+ int bit;
+ bit = mbedtls_mpi_get_bit(num, pos);
+ return bit;
+}
+#endif
diff --git a/src/messages.c b/src/messages.c
index 4e4141e..6fe87f7 100644
--- a/src/messages.c
+++ b/src/messages.c
@@ -554,7 +554,8 @@ void ssh_message_free(ssh_message msg){
case SSH_REQUEST_AUTH:
SAFE_FREE(msg->auth_request.username);
if (msg->auth_request.password) {
- BURN_STRING(msg->auth_request.password);
+ explicit_bzero(msg->auth_request.password,
+ strlen(msg->auth_request.password));
SAFE_FREE(msg->auth_request.password);
}
ssh_key_free(msg->auth_request.pubkey);
@@ -973,7 +974,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
uint32_t n;
for (n = 0; n < session->kbdint->nanswers; n++) {
- BURN_STRING(session->kbdint->answers[n]);
+ explicit_bzero(session->kbdint->answers[n],
+ strlen(session->kbdint->answers[n]));
SAFE_FREE(session->kbdint->answers[n]);
}
SAFE_FREE(session->kbdint->answers);
@@ -1161,6 +1163,7 @@ int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_c
chan->remote_maxpacket = msg->channel_request_open.packet_size;
chan->remote_window = msg->channel_request_open.window;
chan->state = SSH_CHANNEL_STATE_OPEN;
+ chan->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
rc = ssh_buffer_pack(session->out_buffer,
"bdddd",
@@ -1467,5 +1470,3 @@ error:
#endif /* WITH_SERVER */
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/misc.c b/src/misc.c
index 5b260b1..76d9621 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -82,6 +82,12 @@
#define CRYPTO_STRING ""
#endif
+#ifdef HAVE_LIBMBEDCRYPTO
+#define MBED_STRING "/mbedtls"
+#else
+#define MBED_STRING ""
+#endif
+
#ifdef WITH_ZLIB
#define ZLIB_STRING "/zlib"
#else
@@ -349,7 +355,7 @@ char *ssh_hostport(const char *host, int port){
*/
const char *ssh_version(int req_version) {
if (req_version <= LIBSSH_VERSION_INT) {
- return SSH_STRINGIFY(LIBSSH_VERSION) GCRYPT_STRING CRYPTO_STRING
+ return SSH_STRINGIFY(LIBSSH_VERSION) GCRYPT_STRING CRYPTO_STRING MBED_STRING
ZLIB_STRING;
}
@@ -391,6 +397,25 @@ struct ssh_iterator *ssh_list_find(const struct ssh_list *list, void *value){
return NULL;
}
+/**
+ * @brief Get the number of elements in the list
+ *
+ * @param[in] list The list to count.
+ *
+ * @return The number of elements in the list.
+ */
+size_t ssh_list_count(const struct ssh_list *list)
+{
+ struct ssh_iterator *it = NULL;
+ int count = 0;
+
+ for (it = ssh_list_get_iterator(list); it != NULL ; it = it->next) {
+ count++;
+ }
+
+ return count;
+}
+
static struct ssh_iterator *ssh_iterator_new(const void *data){
struct ssh_iterator *iterator=malloc(sizeof(struct ssh_iterator));
if(!iterator)
@@ -681,6 +706,17 @@ char *ssh_path_expand_tilde(const char *d) {
return r;
}
+/** @internal
+ * @brief expands a string in function of session options
+ * @param[in] s Format string to expand. Known parameters:
+ * %d SSH configuration directory (~/.ssh)
+ * %h target host name
+ * %u local username
+ * %l local hostname
+ * %r remote username
+ * %p remote port
+ * @returns Expanded string.
+ */
char *ssh_path_expand_escape(ssh_session session, const char *s) {
char host[NI_MAXHOST];
char buf[MAX_BUF_SIZE];
@@ -785,14 +821,13 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
*
* @param session The session to analyze the banner from.
* @param server 0 means we are a client, 1 a server.
- * @param ssh1 The variable which is set if it is a SSHv1 server.
- * @param ssh2 The variable which is set if it is a SSHv2 server.
*
* @return 0 on success, < 0 on error.
*
* @see ssh_get_issue_banner()
*/
-int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
+int ssh_analyze_banner(ssh_session session, int server)
+{
const char *banner;
const char *openssh;
@@ -825,20 +860,15 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
SSH_LOG(SSH_LOG_RARE, "Analyzing banner: %s", banner);
switch (banner[4]) {
+ case '2':
+ break;
case '1':
- *ssh1 = 1;
if (strlen(banner) > 6) {
if (banner[6] == '9') {
- *ssh2 = 1;
- } else {
- *ssh2 = 0;
+ break;
}
}
- break;
- case '2':
- *ssh1 = 0;
- *ssh2 = 1;
- break;
+ FALL_THROUGH;
default:
ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
return -1;
@@ -971,7 +1001,7 @@ int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) {
* -2 means user-defined timeout as available in
* session->timeout, session->timeout_usec.
*/
- fprintf(stderr, "ssh_timeout_elapsed called with -2. this needs to "
+ SSH_LOG(SSH_LOG_WARN, "ssh_timeout_elapsed called with -2. this needs to "
"be fixed. please set a breakpoint on %s:%d and "
"fix the caller\n", __FILE__, __LINE__);
return 0;
@@ -1035,6 +1065,21 @@ int ssh_match_group(const char *group, const char *object)
return 0;
}
-/** @} */
+#if !defined(HAVE_EXPLICIT_BZERO)
+void explicit_bzero(void *s, size_t n)
+{
+#if defined(HAVE_MEMSET_S)
+ memset_s(s, n, '\0', n);
+#elif defined(HAVE_SECURE_ZERO_MEMORY)
+ SecureZeroMemory(s, n);
+#else
+ memset(s, '\0', n);
+#if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
+ /* See http://llvm.org/bugs/show_bug.cgi?id=15495 */
+ __asm__ volatile("" : : "g"(s) : "memory");
+#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
+#endif
+}
+#endif /* !HAVE_EXPLICIT_BZERO */
-/* vim: set ts=4 sw=4 et cindent: */
+/** @} */
diff --git a/src/options.c b/src/options.c
index 9346b6d..87c5bb4 100644
--- a/src/options.c
+++ b/src/options.c
@@ -151,8 +151,6 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
new->opts.port = src->opts.port;
new->opts.timeout = src->opts.timeout;
new->opts.timeout_usec = src->opts.timeout_usec;
- new->opts.ssh2 = src->opts.ssh2;
- new->opts.ssh1 = src->opts.ssh1;
new->opts.compressionlevel = src->opts.compressionlevel;
new->common.log_verbosity = src->common.log_verbosity;
new->common.callbacks = src->common.callbacks;
@@ -235,15 +233,27 @@ int ssh_options_set_algo(ssh_session session,
* ~/.ssh/known_hosts.\n
* \n
* The known hosts file is used to certify remote hosts
- * are genuine. It may include "%s" which will be
+ * are genuine. It may include "%d" which will be
* replaced by the user home directory.
*
- * - SSH_OPTIONS_IDENTITY:
- * Set the identity file name (const char *,format string).\n
+ * - SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
+ * Set the global known hosts file name (const char *,format string).\n
+ * \n
+ * If the value is NULL, the directory is set to the
+ * default global known hosts file, normally
+ * /etc/ssh/ssh_known_hosts.\n
+ * \n
+ * The known hosts file is used to certify remote hosts
+ * are genuine.
+ *
+ * - SSH_OPTIONS_ADD_IDENTITY (or SSH_OPTIONS_IDENTITY):
+ * Add a new identity file (const char *, format string) to
+ * the identity list.\n
* \n
* By default identity, id_dsa and id_rsa are checked.\n
* \n
- * The identity file used authenticate with public key.
+ * The identity used to authenticate with public key will be
+ * prepended to the list.
* It may include "%s" which will be replaced by the
* user home directory.
*
@@ -255,12 +265,10 @@ int ssh_options_set_algo(ssh_session session,
* (long).
*
* - SSH_OPTIONS_SSH1:
- * Allow or deny the connection to SSH1 servers
- * (int, 0 is false).
+ * Deprecated
*
* - SSH_OPTIONS_SSH2:
- * Allow or deny the connection to SSH2 servers
- * (int, 0 is false).
+ * Unused
*
* - SSH_OPTIONS_LOG_VERBOSITY:
* Set the session logging verbosity (int).\n
@@ -374,6 +382,32 @@ int ssh_options_set_algo(ssh_session session,
* Set it to specify that GSSAPI should delegate credentials
* to the server (int, 0 = false).
*
+ * - SSH_OPTIONS_PASSWORD_AUTH
+ * Set it if password authentication should be used
+ * in ssh_userauth_auto_pubkey(). (int, 0=false).
+ * Currently without effect (ssh_userauth_auto_pubkey doesn't use
+ * password authentication).
+ *
+ * - SSH_OPTIONS_PUBKEY_AUTH
+ * Set it if pubkey authentication should be used
+ * in ssh_userauth_auto_pubkey(). (int, 0=false).
+ *
+ * - SSH_OPTIONS_KBDINT_AUTH
+ * Set it if keyboard-interactive authentication should be used
+ * in ssh_userauth_auto_pubkey(). (int, 0=false).
+ * Currently without effect (ssh_userauth_auto_pubkey doesn't use
+ * keyboard-interactive authentication).
+ *
+ * - SSH_OPTIONS_GSSAPI_AUTH
+ * Set it if gssapi authentication should be used
+ * in ssh_userauth_auto_pubkey(). (int, 0=false).
+ * Currently without effect (ssh_userauth_auto_pubkey doesn't use
+ * gssapi authentication).
+ *
+ * - SSH_OPTIONS_NODELAY
+ * Set it to disable Nagle's Algorithm (TCP_NODELAY) on the
+ * session socket. (int, 0=false)
+ *
* @param value The value to set. This is a generic pointer and the
* datatype which is used should be set according to the
* type set.
@@ -385,6 +419,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
const char *v;
char *p, *q;
long int i;
+ unsigned int u;
int rc;
if (session == NULL) {
@@ -574,21 +609,28 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
}
}
break;
- case SSH_OPTIONS_TIMEOUT:
- if (value == NULL) {
+ case SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
+ v = value;
+ SAFE_FREE(session->opts.global_knownhosts);
+ if (v == NULL) {
+ session->opts.global_knownhosts =
+ strdup("/etc/ssh/ssh_known_hosts");
+ if (session->opts.global_knownhosts == NULL) {
+ ssh_set_error_oom(session);
+ return -1;
+ }
+ } else if (v[0] == '\0') {
ssh_set_error_invalid(session);
return -1;
} else {
- long *x = (long *) value;
- if (*x < 0) {
- ssh_set_error_invalid(session);
+ session->opts.global_knownhosts = strdup(v);
+ if (session->opts.global_knownhosts == NULL) {
+ ssh_set_error_oom(session);
return -1;
}
-
- session->opts.timeout = *x & 0xffffffff;
}
break;
- case SSH_OPTIONS_TIMEOUT_USEC:
+ case SSH_OPTIONS_TIMEOUT:
if (value == NULL) {
ssh_set_error_invalid(session);
return -1;
@@ -599,36 +641,26 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
return -1;
}
- session->opts.timeout_usec = *x & 0xffffffff;
+ session->opts.timeout = *x & 0xffffffff;
}
break;
- case SSH_OPTIONS_SSH1:
+ case SSH_OPTIONS_TIMEOUT_USEC:
if (value == NULL) {
ssh_set_error_invalid(session);
return -1;
} else {
- int *x = (int *) value;
+ long *x = (long *) value;
if (*x < 0) {
ssh_set_error_invalid(session);
return -1;
}
- session->opts.ssh1 = *x;
+ session->opts.timeout_usec = *x & 0xffffffff;
}
break;
+ case SSH_OPTIONS_SSH1:
+ break;
case SSH_OPTIONS_SSH2:
- if (value == NULL) {
- ssh_set_error_invalid(session);
- return -1;
- } else {
- int *x = (int *) value;
- if (*x < 0) {
- ssh_set_error_invalid(session);
- return -1;
- }
-
- session->opts.ssh2 = *x & 0xffff;
- }
break;
case SSH_OPTIONS_LOG_VERBOSITY:
if (value == NULL) {
@@ -858,7 +890,39 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
session->opts.gss_delegate_creds = (x & 0xff);
}
break;
-
+ case SSH_OPTIONS_PASSWORD_AUTH:
+ case SSH_OPTIONS_PUBKEY_AUTH:
+ case SSH_OPTIONS_KBDINT_AUTH:
+ case SSH_OPTIONS_GSSAPI_AUTH:
+ u = 0;
+ if (value == NULL) {
+ ssh_set_error_invalid(session);
+ return -1;
+ } else {
+ int x = *(int *)value;
+ u = type == SSH_OPTIONS_PASSWORD_AUTH ?
+ SSH_OPT_FLAG_PASSWORD_AUTH:
+ type == SSH_OPTIONS_PUBKEY_AUTH ?
+ SSH_OPT_FLAG_PUBKEY_AUTH:
+ type == SSH_OPTIONS_KBDINT_AUTH ?
+ SSH_OPT_FLAG_KBDINT_AUTH:
+ SSH_OPT_FLAG_GSSAPI_AUTH;
+ if (x != 0){
+ session->opts.flags |= u;
+ } else {
+ session->opts.flags &= ~u;
+ }
+ }
+ break;
+ case SSH_OPTIONS_NODELAY:
+ if (value == NULL) {
+ ssh_set_error_invalid(session);
+ return -1;
+ } else {
+ int *x = (int *) value;
+ session->opts.nodelay = (*x & 0xff) > 0 ? 1 : 0;
+ }
+ break;
default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
return -1;
@@ -918,24 +982,9 @@ int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
* ~/.ssh/config file.
*
* - SSH_OPTIONS_IDENTITY:
- * Set the identity file name (const char *,format string).\n
- * \n
- * By default identity, id_dsa and id_rsa are checked.\n
- * \n
- * The identity file used authenticate with public key.
- * It may include "%s" which will be replaced by the
- * user home directory.
- *
- * - SSH_OPTIONS_ADD_IDENTITY:
- * Add a new identity file (const char *,format string) to
- * the identity list.\n
+ * Get the first identity file name (const char *).\n
* \n
- * By default identity, id_dsa and id_rsa are checked.\n
- * \n
- * The identity used authenticate with public key will be
- * prepended to the list.
- * It may include "%s" which will be replaced by the
- * user home directory.
+ * By default identity, id_dsa and id_rsa are checked.
*
* - SSH_OPTIONS_PROXYCOMMAND:
* Get the proxycommand necessary to log into the
@@ -1036,12 +1085,6 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
int compress = 0;
int cont = 1;
int current = 0;
-#ifdef WITH_SSH1
- int ssh1 = 1;
-#else
- int ssh1 = 0;
-#endif
- int ssh2 = 1;
#ifdef _MSC_VER
/* Not supported with a Microsoft compiler */
return -1;
@@ -1077,12 +1120,8 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
compress++;
break;
case '2':
- ssh2 = 1;
- ssh1 = 0;
break;
case '1':
- ssh2 = 0;
- ssh1 = 1;
break;
default:
{
@@ -1184,9 +1223,6 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
ssh_options_set(session, SSH_OPTIONS_PORT_STR, port);
}
- ssh_options_set(session, SSH_OPTIONS_SSH1, &ssh1);
- ssh_options_set(session, SSH_OPTIONS_SSH2, &ssh2);
-
if (!cont) {
return SSH_ERROR;
}
@@ -1428,8 +1464,15 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
key_type = ssh_key_type(key);
switch (key_type) {
case SSH_KEYTYPE_DSS:
+#ifdef HAVE_DSA
bind_key_loc = &sshbind->dsa;
bind_key_path_loc = &sshbind->dsakey;
+#else
+ ssh_set_error(sshbind,
+ SSH_FATAL,
+ "DSS key used and libssh compiled "
+ "without DSA support");
+#endif
break;
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
@@ -1443,7 +1486,6 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
#endif
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
bind_key_loc = &sshbind->rsa;
bind_key_path_loc = &sshbind->rsakey;
break;
@@ -1485,7 +1527,14 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
key_type = ssh_key_type(key);
switch (key_type) {
case SSH_KEYTYPE_DSS:
+#ifdef HAVE_DSA
bind_key_loc = &sshbind->dsa;
+#else
+ ssh_set_error(sshbind,
+ SSH_FATAL,
+ "DSA key used and libssh compiled "
+ "without DSA support");
+#endif
break;
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
@@ -1498,7 +1547,6 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
#endif
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
bind_key_loc = &sshbind->rsa;
break;
case SSH_KEYTYPE_ED25519:
@@ -1624,5 +1672,3 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
#endif
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/packet.c b/src/packet.c
index 6e84dc8..16f9614 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -144,20 +144,26 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
ssh_session session= (ssh_session) user;
unsigned int blocksize = (session->current_crypto ?
session->current_crypto->in_cipher->blocksize : 8);
- unsigned char mac[DIGEST_MAX_LEN] = {0};
- char buffer[16] = {0};
+ unsigned int lenfield_blocksize = (session->current_crypto ?
+ session->current_crypto->in_cipher->lenfield_blocksize : 8);
size_t current_macsize = 0;
- const uint8_t *packet;
+ uint8_t *ptr = NULL;
int to_be_read;
int rc;
- uint32_t len, compsize, payloadsize;
+ uint8_t *cleartext_packet = NULL;
+ uint8_t *packet_second_block = NULL;
+ uint8_t *mac = NULL;
+ size_t packet_remaining;
+ uint32_t packet_len, compsize, payloadsize;
uint8_t padding;
size_t processed = 0; /* number of byte processed from the callback */
if(session->current_crypto != NULL) {
current_macsize = hmac_digest_len(session->current_crypto->in_hmac);
}
-
+ if (lenfield_blocksize == 0) {
+ lenfield_blocksize = blocksize;
+ }
if (data == NULL) {
goto error;
}
@@ -165,14 +171,30 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
if (session->session_state == SSH_SESSION_STATE_ERROR) {
goto error;
}
-
+#ifdef DEBUG_PACKET
+ SSH_LOG(SSH_LOG_PACKET,
+ "rcv packet cb (len=%zu, state=%s)",
+ receivedlen,
+ session->packet_state == PACKET_STATE_INIT ?
+ "INIT" :
+ session->packet_state == PACKET_STATE_SIZEREAD ?
+ "SIZE_READ" :
+ session->packet_state == PACKET_STATE_PROCESSING ?
+ "PROCESSING" : "unknown");
+#endif
switch(session->packet_state) {
case PACKET_STATE_INIT:
- if (receivedlen < blocksize) {
+ if (receivedlen < lenfield_blocksize) {
/*
* We didn't receive enough data to read at least one
* block size, give up
*/
+#ifdef DEBUG_PACKET
+ SSH_LOG(SSH_LOG_PACKET,
+ "Waiting for more data (%zu < %u)",
+ receivedlen,
+ lenfield_blocksize);
+#endif
return 0;
}
@@ -190,24 +212,21 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
}
}
- memcpy(buffer, data, blocksize);
- processed += blocksize;
- len = ssh_packet_decrypt_len(session, buffer);
-
- rc = ssh_buffer_add_data(session->in_buffer, buffer, blocksize);
- if (rc < 0) {
+ ptr = ssh_buffer_allocate(session->in_buffer, lenfield_blocksize);
+ if (ptr == NULL) {
goto error;
}
+ processed += lenfield_blocksize;
+ packet_len = ssh_packet_decrypt_len(session, ptr, (uint8_t *)data);
- if (len > MAX_PACKET_LEN) {
+ if (packet_len > MAX_PACKET_LEN) {
ssh_set_error(session,
SSH_FATAL,
"read_packet(): Packet len too high(%u %.4x)",
- len, len);
+ packet_len, packet_len);
goto error;
}
-
- to_be_read = len - blocksize + sizeof(uint32_t);
+ to_be_read = packet_len - lenfield_blocksize + sizeof(uint32_t);
if (to_be_read < 0) {
/* remote sshd sends invalid sizes? */
ssh_set_error(session,
@@ -217,59 +236,52 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
goto error;
}
- /* Saves the status of the current operations */
- session->in_packet.len = len;
+ session->in_packet.len = packet_len;
session->packet_state = PACKET_STATE_SIZEREAD;
FALL_THROUGH;
case PACKET_STATE_SIZEREAD:
- len = session->in_packet.len;
- to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
+ packet_len = session->in_packet.len;
+ processed = lenfield_blocksize;
+ to_be_read = packet_len + sizeof(uint32_t) + current_macsize;
/* if to_be_read is zero, the whole packet was blocksize bytes. */
if (to_be_read != 0) {
- if (receivedlen - processed < (unsigned int)to_be_read) {
+ if (receivedlen < (unsigned int)to_be_read) {
/* give up, not enough data in buffer */
- SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len);
- return processed;
+ SSH_LOG(SSH_LOG_PACKET,
+ "packet: partial packet (read len) "
+ "[len=%d, receivedlen=%d, to_be_read=%d]",
+ packet_len,
+ (int)receivedlen,
+ to_be_read);
+ return 0;
}
- packet = ((uint8_t*)data) + processed;
-#if 0
- ssh_socket_read(session->socket,
- packet,
- to_be_read - current_macsize);
-#endif
-
- rc = ssh_buffer_add_data(session->in_buffer,
- packet,
- to_be_read - current_macsize);
- if (rc < 0) {
- goto error;
- }
- processed += to_be_read - current_macsize;
+ packet_second_block = (uint8_t*)data + lenfield_blocksize;
+ processed = to_be_read - current_macsize;
}
+ /* remaining encrypted bytes from the packet, MAC not included */
+ packet_remaining =
+ packet_len - (lenfield_blocksize - sizeof(uint32_t));
+ cleartext_packet = ssh_buffer_allocate(session->in_buffer,
+ packet_remaining);
if (session->current_crypto) {
/*
- * Decrypt the rest of the packet (blocksize bytes already
+ * Decrypt the rest of the packet (lenfield_blocksize bytes already
* have been decrypted)
*/
- uint32_t buffer_len = ssh_buffer_get_len(session->in_buffer);
-
- /* The following check avoids decrypting zero bytes */
- if (buffer_len > blocksize) {
- uint8_t *payload = ((uint8_t*)ssh_buffer_get(session->in_buffer) + blocksize);
- uint32_t plen = buffer_len - blocksize;
-
- rc = ssh_packet_decrypt(session, payload, plen);
+ if (packet_remaining > 0) {
+ rc = ssh_packet_decrypt(session,
+ cleartext_packet,
+ (uint8_t *)data,
+ lenfield_blocksize,
+ processed - lenfield_blocksize);
if (rc < 0) {
- ssh_set_error(session, SSH_FATAL, "Decrypt error");
+ ssh_set_error(session, SSH_FATAL, "Decryption error");
goto error;
}
}
-
- /* copy the last part from the incoming buffer */
- packet = ((uint8_t *)data) + processed;
- memcpy(mac, packet, current_macsize);
+ mac = packet_second_block + packet_remaining;
rc = ssh_packet_hmac_verify(session, session->in_buffer, mac, session->current_crypto->in_hmac);
if (rc < 0) {
@@ -277,6 +289,8 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
goto error;
}
processed += current_macsize;
+ } else {
+ memcpy(cleartext_packet, packet_second_block, packet_remaining);
}
/* skip the size field which has been processed before */
@@ -326,7 +340,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
ssh_packet_parse_type(session);
SSH_LOG(SSH_LOG_PACKET,
"packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
- session->in_packet.type, len, padding, compsize, payloadsize);
+ session->in_packet.type, packet_len, padding, compsize, payloadsize);
/* Execute callbacks */
ssh_packet_process(session, session->in_packet.type);
@@ -337,9 +351,9 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
"Processing %" PRIdS " bytes left in socket buffer",
receivedlen-processed);
- packet = ((uint8_t*)data) + processed;
+ ptr = ((uint8_t*)data) + processed;
- rc = ssh_packet_socket_callback(packet, receivedlen - processed,user);
+ rc = ssh_packet_socket_callback(ptr, receivedlen - processed,user);
processed += rc;
}
@@ -356,7 +370,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
error:
session->session_state= SSH_SESSION_STATE_ERROR;
-
+ SSH_LOG(SSH_LOG_PACKET,"Packet: processed %" PRIdS " bytes", processed);
return processed;
}
@@ -408,12 +422,6 @@ void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callback
* @brief sets the default packet handlers
*/
void ssh_packet_set_default_callbacks(ssh_session session){
-#ifdef WITH_SSH1
- if(session->version==1){
- ssh_packet_set_default_callbacks1(session);
- return;
- }
-#endif
session->default_packet_callbacks.start=1;
session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers)/sizeof(ssh_packet_callback);
session->default_packet_callbacks.user=session;
@@ -539,6 +547,8 @@ static int ssh_packet_write(ssh_session session) {
static int packet_send2(ssh_session session) {
unsigned int blocksize = (session->current_crypto ?
session->current_crypto->out_cipher->blocksize : 8);
+ unsigned int lenfield_blocksize = (session->current_crypto ?
+ session->current_crypto->out_cipher->lenfield_blocksize : 0);
enum ssh_hmac_e hmac_type = (session->current_crypto ?
session->current_crypto->out_hmac : session->next_crypto->out_hmac);
uint32_t currentlen = ssh_buffer_get_len(session->out_buffer);
@@ -547,8 +557,7 @@ static int packet_send2(ssh_session session) {
int rc = SSH_ERROR;
uint32_t finallen,payloadsize,compsize;
uint8_t padding;
-
- uint8_t header[sizeof(padding) + sizeof(finallen)] = { 0 };
+ ssh_buffer header_buffer = ssh_buffer_new();
payloadsize = currentlen;
#ifdef WITH_ZLIB
@@ -562,20 +571,36 @@ static int packet_send2(ssh_session session) {
}
#endif /* WITH_ZLIB */
compsize = currentlen;
- padding = (blocksize - ((currentlen +5) % blocksize));
+ /* compressed payload + packet len (4) + padding len (1) */
+ /* totallen - lenfield_blocksize must be equal to 0 (mod blocksize) */
+ padding = (blocksize - ((blocksize - lenfield_blocksize + currentlen + 5) % blocksize));
if(padding < 4) {
padding += blocksize;
}
- if (session->current_crypto) {
- ssh_get_random(padstring, padding, 0);
+ if (session->current_crypto != NULL) {
+ int ok;
+
+ ok = ssh_get_random(padstring, padding, 0);
+ if (!ok) {
+ ssh_set_error(session, SSH_FATAL, "PRNG error");
+ goto error;
+ }
}
- finallen = htonl(currentlen + padding + 1);
+ if (header_buffer == NULL){
+ ssh_set_error_oom(session);
+ goto error;
+ }
+ finallen = currentlen + padding + 1;
+ rc = ssh_buffer_pack(header_buffer, "db", finallen, padding);
+ if (rc == SSH_ERROR){
+ goto error;
+ }
- memcpy(&header[0], &finallen, sizeof(finallen));
- header[sizeof(finallen)] = padding;
- rc = ssh_buffer_prepend_data(session->out_buffer, &header, sizeof(header));
+ rc = ssh_buffer_prepend_data(session->out_buffer,
+ ssh_buffer_get(header_buffer),
+ ssh_buffer_get_len(header_buffer));
if (rc < 0) {
goto error;
}
@@ -584,10 +609,12 @@ static int packet_send2(ssh_session session) {
goto error;
}
#ifdef WITH_PCAP
- if(session->pcap_ctx){
- ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
- ssh_buffer_get(session->out_buffer),ssh_buffer_get_len(session->out_buffer)
- ,ssh_buffer_get_len(session->out_buffer));
+ if (session->pcap_ctx) {
+ ssh_pcap_context_write(session->pcap_ctx,
+ SSH_PCAP_DIR_OUT,
+ ssh_buffer_get(session->out_buffer),
+ ssh_buffer_get_len(session->out_buffer),
+ ssh_buffer_get_len(session->out_buffer));
}
#endif
hmac = ssh_packet_encrypt(session, ssh_buffer_get(session->out_buffer),
@@ -608,21 +635,18 @@ static int packet_send2(ssh_session session) {
SSH_LOG(SSH_LOG_PACKET,
"packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]",
- ntohl(finallen), padding, compsize, payloadsize);
+ finallen, padding, compsize, payloadsize);
if (ssh_buffer_reinit(session->out_buffer) < 0) {
rc = SSH_ERROR;
}
error:
-
+ if (header_buffer != NULL) {
+ ssh_buffer_free(header_buffer);
+ }
return rc; /* SSH_OK, AGAIN or ERROR */
}
int ssh_packet_send(ssh_session session) {
-#ifdef WITH_SSH1
- if (session->version == 1) {
- return ssh_packet_send1(session);
- }
-#endif
- return packet_send2(session);
+ return packet_send2(session);
}
diff --git a/src/packet1.c b/src/packet1.c
deleted file mode 100644
index ff33ca1..0000000
--- a/src/packet1.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2010 by Aris Adamantiadis
- *
- * The SSH Library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at your
- * option) any later version.
- *
- * The SSH Library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the SSH Library; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-
-#ifndef _WIN32
-#include <netinet/in.h>
-#endif /* _WIN32 */
-
-#include "libssh/priv.h"
-#include "libssh/ssh1.h"
-#include "libssh/crc32.h"
-#include "libssh/packet.h"
-#include "libssh/session.h"
-#include "libssh/buffer.h"
-#include "libssh/socket.h"
-#include "libssh/kex.h"
-#include "libssh/crypto.h"
-
-#ifdef WITH_SSH1
-
-static ssh_packet_callback default_packet_handlers1[]= {
- NULL, //SSH_MSG_NONE 0
- ssh_packet_disconnect1, //SSH_MSG_DISCONNECT 1
- ssh_packet_publickey1, //SSH_SMSG_PUBLIC_KEY 2
- NULL, //SSH_CMSG_SESSION_KEY 3
- NULL, //SSH_CMSG_USER 4
- NULL, //SSH_CMSG_AUTH_RHOSTS 5
- NULL, //SSH_CMSG_AUTH_RSA 6
- NULL, //SSH_SMSG_AUTH_RSA_CHALLENGE 7
- NULL, //SSH_CMSG_AUTH_RSA_RESPONSE 8
- NULL, //SSH_CMSG_AUTH_PASSWORD 9
- NULL, //SSH_CMSG_REQUEST_PTY 10
- NULL, //SSH_CMSG_WINDOW_SIZE 11
- NULL, //SSH_CMSG_EXEC_SHELL 12
- NULL, //SSH_CMSG_EXEC_CMD 13
- ssh_packet_smsg_success1, //SSH_SMSG_SUCCESS 14
- ssh_packet_smsg_failure1, //SSH_SMSG_FAILURE 15
- NULL, //SSH_CMSG_STDIN_DATA 16
- ssh_packet_data1, //SSH_SMSG_STDOUT_DATA 17
- ssh_packet_data1, //SSH_SMSG_STDERR_DATA 18
- NULL, //SSH_CMSG_EOF 19
- ssh_packet_exist_status1, //SSH_SMSG_EXITSTATUS 20
- NULL, //SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21
- NULL, //SSH_MSG_CHANNEL_OPEN_FAILURE 22
- NULL, //SSH_MSG_CHANNEL_DATA 23
- ssh_packet_close1, //SSH_MSG_CHANNEL_CLOSE 24
- NULL, //SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25
- NULL, //SSH_CMSG_X11_REQUEST_FORWARDING 26
- NULL, //SSH_SMSG_X11_OPEN 27
- NULL, //SSH_CMSG_PORT_FORWARD_REQUEST 28
- NULL, //SSH_MSG_PORT_OPEN 29
- NULL, //SSH_CMSG_AGENT_REQUEST_FORWARDING 30
- NULL, //SSH_SMSG_AGENT_OPEN 31
- ssh_packet_ignore_callback, //SSH_MSG_IGNORE 32
- NULL, //SSH_CMSG_EXIT_CONFIRMATION 33
- NULL, //SSH_CMSG_X11_REQUEST_FORWARDING 34
- NULL, //SSH_CMSG_AUTH_RHOSTS_RSA 35
- ssh_packet_ignore_callback, //SSH_MSG_DEBUG 36
-};
-
-/** @internal
- * @brief sets the default packet handlers
- */
-void ssh_packet_set_default_callbacks1(ssh_session session){
- session->default_packet_callbacks.start=0;
- session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers1)/sizeof(ssh_packet_callback);
- session->default_packet_callbacks.user=session;
- session->default_packet_callbacks.callbacks=default_packet_handlers1;
- ssh_packet_set_callbacks(session, &session->default_packet_callbacks);
-}
-
-
-/** @internal
- * @handles a data received event. It then calls the handlers for the different packet types
- * or and exception handler callback. Adapted for SSH-1 packets.
- * @param user pointer to current ssh_session
- * @param data pointer to the data received
- * @len length of data received. It might not be enough for a complete packet
- * @returns number of bytes read and processed.
- */
-
-int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user) {
- void *packet = NULL;
- int to_be_read;
- size_t processed=0;
- uint32_t padding;
- uint32_t crc;
- uint32_t len, buffer_len;
- ssh_session session=(ssh_session)user;
-
- switch (session->packet_state){
- case PACKET_STATE_INIT:
- memset(&session->in_packet, 0, sizeof(PACKET));
-
- if (session->in_buffer) {
- if (ssh_buffer_reinit(session->in_buffer) < 0) {
- goto error;
- }
- } else {
- session->in_buffer = ssh_buffer_new();
- if (session->in_buffer == NULL) {
- goto error;
- }
- }
- /* must have at least enough bytes for size */
- if(receivedlen < sizeof(uint32_t)){
- return 0;
- }
- memcpy(&len,data,sizeof(uint32_t));
- processed += sizeof(uint32_t);
-
- /* len is not encrypted */
- len = ntohl(len);
- if (len > MAX_PACKET_LEN) {
- ssh_set_error(session, SSH_FATAL,
- "read_packet(): Packet len too high (%u %.8x)", len, len);
- goto error;
- }
-
- SSH_LOG(SSH_LOG_PACKET, "Reading a %d bytes packet", len);
-
- session->in_packet.len = len;
- session->packet_state = PACKET_STATE_SIZEREAD;
- /* FALL THROUGH */
- case PACKET_STATE_SIZEREAD:
- len = session->in_packet.len;
- /* SSH-1 has a fixed padding lenght */
- padding = 8 - (len % 8);
- to_be_read = len + padding;
- if(to_be_read + processed > receivedlen){
- /* wait for rest of packet */
- return processed;
- }
- /* it is _not_ possible that to_be_read be < 8. */
- packet = (char *)data + processed;
-
- if (ssh_buffer_add_data(session->in_buffer,packet,to_be_read) < 0) {
- goto error;
- }
- processed += to_be_read;
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("read packet:", ssh_buffer_get(session->in_buffer),
- ssh_buffer_get_len(session->in_buffer));
-#endif
- if (session->current_crypto) {
- /*
- * We decrypt everything, missing the lenght part (which was
- * previously read, unencrypted, and is not part of the buffer
- */
- buffer_len = ssh_buffer_get_len(session->in_buffer);
- if (buffer_len > 0) {
- int rc;
- rc = ssh_packet_decrypt(session,
- ssh_buffer_get(session->in_buffer),
- buffer_len);
- if (rc < 0) {
- ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
- goto error;
- }
- }
- }
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("read packet decrypted:", ssh_buffer_get(session->in_buffer),
- ssh_buffer_get_len(session->in_buffer));
-#endif
- SSH_LOG(SSH_LOG_PACKET, "%d bytes padding", padding);
- if(((len + padding) != ssh_buffer_get_len(session->in_buffer)) ||
- ((len + padding) < sizeof(uint32_t))) {
- SSH_LOG(SSH_LOG_RARE, "no crc32 in packet");
- ssh_set_error(session, SSH_FATAL, "no crc32 in packet");
- goto error;
- }
-
- memcpy(&crc,
- (unsigned char *)ssh_buffer_get(session->in_buffer) + (len+padding) - sizeof(uint32_t),
- sizeof(uint32_t));
- ssh_buffer_pass_bytes_end(session->in_buffer, sizeof(uint32_t));
- crc = ntohl(crc);
- if (ssh_crc32(ssh_buffer_get(session->in_buffer),
- (len + padding) - sizeof(uint32_t)) != crc) {
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("crc32 on",ssh_buffer_get(session->in_buffer),
- len + padding - sizeof(uint32_t));
-#endif
- SSH_LOG(SSH_LOG_RARE, "Invalid crc32");
- ssh_set_error(session, SSH_FATAL,
- "Invalid crc32: expected %.8x, got %.8x",
- crc,
- ssh_crc32(ssh_buffer_get(session->in_buffer),
- len + padding - sizeof(uint32_t)));
- goto error;
- }
- /* pass the padding */
- ssh_buffer_pass_bytes(session->in_buffer, padding);
- SSH_LOG(SSH_LOG_PACKET, "The packet is valid");
-
-/* TODO FIXME
-#ifdef WITH_ZLIB
- if(session->current_crypto && session->current_crypto->do_compress_in){
- decompress_buffer(session,session->in_buffer);
- }
-#endif
-*/
- session->recv_seq++;
- /* We don't want to rewrite a new packet while still executing the packet callbacks */
- session->packet_state = PACKET_STATE_PROCESSING;
- ssh_packet_parse_type(session);
- /* execute callbacks */
- ssh_packet_process(session, session->in_packet.type);
- session->packet_state = PACKET_STATE_INIT;
- if(processed < receivedlen){
- int rc;
- /* Handle a potential packet left in socket buffer */
- SSH_LOG(SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer",
- receivedlen-processed);
- rc = ssh_packet_socket_callback1((char *)data + processed,
- receivedlen - processed,user);
- processed += rc;
- }
-
- return processed;
- case PACKET_STATE_PROCESSING:
- SSH_LOG(SSH_LOG_PACKET, "Nested packet processing. Delaying.");
- return 0;
- }
-
-error:
- session->session_state=SSH_SESSION_STATE_ERROR;
-
- return processed;
-}
-
-
-int ssh_packet_send1(ssh_session session) {
- unsigned int blocksize = (session->current_crypto ?
- session->current_crypto->out_cipher->blocksize : 8);
- uint32_t currentlen = ssh_buffer_get_len(session->out_buffer) + sizeof(uint32_t);
- char padstring[32] = {0};
- int rc = SSH_ERROR;
- uint32_t finallen;
- uint32_t crc;
- uint8_t padding;
-
- SSH_LOG(SSH_LOG_PACKET,"Sending a %d bytes long packet",currentlen);
-
-/* TODO FIXME
-#ifdef WITH_ZLIB
- if (session->current_crypto && session->current_crypto->do_compress_out) {
- if (compress_buffer(session, session->out_buffer) < 0) {
- goto error;
- }
- currentlen = ssh_buffer_get_len(session->out_buffer);
- }
-#endif
-*/
- padding = blocksize - (currentlen % blocksize);
- if (session->current_crypto) {
- ssh_get_random(padstring, padding, 0);
- } else {
- memset(padstring, 0, padding);
- }
-
- finallen = htonl(currentlen);
- SSH_LOG(SSH_LOG_PACKET,
- "%d bytes after comp + %d padding bytes = %d bytes packet",
- currentlen, padding, ntohl(finallen));
-
- if (ssh_buffer_prepend_data(session->out_buffer, &padstring, padding) < 0) {
- goto error;
- }
- if (ssh_buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
- goto error;
- }
-
- crc = ssh_crc32((char *)ssh_buffer_get(session->out_buffer) + sizeof(uint32_t),
- ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t));
-
- if (ssh_buffer_add_u32(session->out_buffer, ntohl(crc)) < 0) {
- goto error;
- }
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("Clear packet", ssh_buffer_get(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
-#endif
-
- /* session->out_buffer should have more than sizeof(uint32_t) bytes
- in it as required for ssh_packet_encrypt */
- ssh_packet_encrypt(session, (unsigned char *)ssh_buffer_get(session->out_buffer) + sizeof(uint32_t),
- ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t));
-
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("encrypted packet",ssh_buffer_get(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
-#endif
- rc=ssh_socket_write(session->socket, ssh_buffer_get(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
- if(rc== SSH_ERROR) {
- goto error;
- }
-
- session->send_seq++;
-
- if (ssh_buffer_reinit(session->out_buffer) < 0) {
- rc = SSH_ERROR;
- }
-error:
-
- return rc; /* SSH_OK, AGAIN or ERROR */
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_disconnect1){
- (void)packet;
- (void)user;
- (void)type;
- SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT");
- ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_DISCONNECT");
- ssh_socket_close(session->socket);
- session->alive = 0;
- session->session_state=SSH_SESSION_STATE_DISCONNECTED;
- return SSH_PACKET_USED;
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_smsg_success1){
- if(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
- session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
- return SSH_PACKET_USED;
- } else if(session->session_state==SSH_SESSION_STATE_AUTHENTICATING){
- ssh_auth1_handler(session,type);
- return SSH_PACKET_USED;
- } else {
- return ssh_packet_channel_success(session,type,packet,user);
- }
-}
-
-SSH_PACKET_CALLBACK(ssh_packet_smsg_failure1){
- if(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){
- session->session_state=SSH_SESSION_STATE_ERROR;
- ssh_set_error(session,SSH_FATAL,"Key exchange failed: received SSH_SMSG_FAILURE");
- return SSH_PACKET_USED;
- } else if(session->session_state==SSH_SESSION_STATE_AUTHENTICATING){
- ssh_auth1_handler(session,type);
- return SSH_PACKET_USED;
- } else {
- return ssh_packet_channel_failure(session,type,packet,user);
- }
-}
-
-
-#endif /* WITH_SSH1 */
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/packet_cb.c b/src/packet_cb.c
index 106c5d9..2c8d993 100644
--- a/src/packet_cb.c
+++ b/src/packet_cb.c
@@ -116,6 +116,7 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
break;
#endif
#ifdef HAVE_CURVE25519
+ case SSH_KEX_CURVE25519_SHA256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_reply(session, packet);
break;
@@ -154,7 +155,8 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
/* server things are done in server.c */
session->dh_handshake_state=DH_STATE_FINISHED;
} else {
- ssh_key key;
+ ssh_key server_key;
+
/* client */
rc = ssh_make_sessionid(session);
if (rc != SSH_OK) {
@@ -165,8 +167,9 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
* Set the cryptographic functions for the next crypto
* (it is needed for ssh_generate_session_keys for key lengths)
*/
- if (crypt_set_algorithms(session, SSH_3DES) /* knows nothing about DES*/ ) {
- goto error;
+ rc = crypt_set_algorithms_client(session);
+ if (rc < 0) {
+ goto error;
}
if (ssh_generate_session_keys(session) < 0) {
@@ -178,35 +181,30 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
session->next_crypto->dh_server_signature = NULL;
/* get the server public key */
- rc = ssh_pki_import_pubkey_blob(session->next_crypto->server_pubkey, &key);
- if (rc < 0) {
+ server_key = ssh_dh_get_next_server_publickey(session);
+ if (server_key == NULL) {
return SSH_ERROR;
}
/* check if public key from server matches user preferences */
if (session->opts.wanted_methods[SSH_HOSTKEYS]) {
if(!ssh_match_group(session->opts.wanted_methods[SSH_HOSTKEYS],
- key->type_c)) {
+ server_key->type_c)) {
ssh_set_error(session,
SSH_FATAL,
"Public key from server (%s) doesn't match user "
"preference (%s)",
- key->type_c,
+ server_key->type_c,
session->opts.wanted_methods[SSH_HOSTKEYS]);
- ssh_key_free(key);
return -1;
}
}
rc = ssh_pki_signature_verify_blob(session,
sig_blob,
- key,
+ server_key,
session->next_crypto->secret_hash,
session->next_crypto->digest_len);
- /* Set the server public key type for known host checking */
- session->next_crypto->server_pubkey_type = key->type_c;
-
- ssh_key_free(key);
ssh_string_burn(sig_blob);
ssh_string_free(sig_blob);
sig_blob = NULL;
diff --git a/src/packet_crypt.c b/src/packet_crypt.c
index 94fd10e..7306e4b 100644
--- a/src/packet_crypt.c
+++ b/src/packet_crypt.c
@@ -44,40 +44,81 @@
#include "libssh/crypto.h"
#include "libssh/buffer.h"
-uint32_t ssh_packet_decrypt_len(ssh_session session, char *crypted){
- uint32_t decrypted;
-
- if (session->current_crypto) {
- if (ssh_packet_decrypt(session, crypted,
- session->current_crypto->in_cipher->blocksize) < 0) {
- return 0;
+/** @internal
+ * @brief decrypt the packet length from a raw encrypted packet, and store the first decrypted
+ * blocksize.
+ * @returns native byte-ordered decrypted length of the upcoming packet
+ */
+uint32_t ssh_packet_decrypt_len(ssh_session session,
+ uint8_t *destination,
+ uint8_t *source)
+{
+ uint32_t decrypted;
+ int rc;
+
+ if (session->current_crypto != NULL) {
+ if (session->current_crypto->in_cipher->aead_decrypt_length != NULL) {
+ session->current_crypto->in_cipher->aead_decrypt_length(
+ session->current_crypto->in_cipher, source, destination,
+ session->current_crypto->in_cipher->lenfield_blocksize,
+ session->recv_seq);
+ } else {
+ rc = ssh_packet_decrypt(
+ session,
+ destination,
+ source,
+ 0,
+ session->current_crypto->in_cipher->blocksize);
+ if (rc < 0) {
+ return 0;
+ }
+ }
+ } else {
+ memcpy(destination, source, 8);
}
- }
- memcpy(&decrypted,crypted,sizeof(decrypted));
- return ntohl(decrypted);
-}
+ memcpy(&decrypted,destination,sizeof(decrypted));
-int ssh_packet_decrypt(ssh_session session, void *data,uint32_t len) {
- struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher;
- char *out = NULL;
+ return ntohl(decrypted);
+}
- assert(len);
+/** @internal
+ * @brief decrypts the content of an SSH packet.
+ * @param[source] source packet, including the encrypted length field
+ * @param[start] index in the packet that was not decrypted yet.
+ * @param[encrypted_size] size of the encrypted data to be decrypted after start.
+ */
+int ssh_packet_decrypt(ssh_session session,
+ uint8_t *destination,
+ uint8_t *source,
+ size_t start,
+ size_t encrypted_size)
+{
+ struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher;
+
+ if (encrypted_size <= 0) {
+ return SSH_ERROR;
+ }
- if(len % session->current_crypto->in_cipher->blocksize != 0){
- ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
- return SSH_ERROR;
- }
- out = malloc(len);
- if (out == NULL) {
- return -1;
- }
+ if (encrypted_size % session->current_crypto->in_cipher->blocksize != 0) {
+ ssh_set_error(session,
+ SSH_FATAL,
+ "Cryptographic functions must be used on multiple of "
+ "blocksize (received %" PRIdS ")",
+ encrypted_size);
+ return SSH_ERROR;
+ }
- crypto->decrypt(crypto,data,out,len);
+ if (crypto->aead_decrypt != NULL) {
+ return crypto->aead_decrypt(crypto,
+ source,
+ destination,
+ encrypted_size,
+ session->recv_seq);
+ } else {
+ crypto->decrypt(crypto, source + start, destination, encrypted_size);
+ }
- memcpy(data,out,len);
- BURN_BUFFER(out, len);
- SAFE_FREE(out);
- return 0;
+ return 0;
}
unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) {
@@ -93,7 +134,7 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len)
if (!session->current_crypto) {
return NULL; /* nothing to do here */
}
- if(len % session->current_crypto->in_cipher->blocksize != 0){
+ if((len - session->current_crypto->out_cipher->lenfield_blocksize) % session->current_crypto->out_cipher->blocksize != 0){
ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
return NULL;
}
@@ -106,35 +147,33 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len)
seq = ntohl(session->send_seq);
crypto = session->current_crypto->out_cipher;
- if (session->version == 2) {
- ctx = hmac_init(session->current_crypto->encryptMAC, hmac_digest_len(type), type);
- if (ctx == NULL) {
- SAFE_FREE(out);
- return NULL;
- }
- hmac_update(ctx,(unsigned char *)&seq,sizeof(uint32_t));
- hmac_update(ctx,data,len);
- hmac_final(ctx,session->current_crypto->hmacbuf,&finallen);
+ if (crypto->aead_encrypt != NULL) {
+ crypto->aead_encrypt(crypto, data, out, len,
+ session->current_crypto->hmacbuf, session->send_seq);
+ } else {
+ ctx = hmac_init(session->current_crypto->encryptMAC, hmac_digest_len(type), type);
+ if (ctx == NULL) {
+ SAFE_FREE(out);
+ return NULL;
+ }
+ hmac_update(ctx,(unsigned char *)&seq,sizeof(uint32_t));
+ hmac_update(ctx,data,len);
+ hmac_final(ctx,session->current_crypto->hmacbuf,&finallen);
+
#ifdef DEBUG_CRYPTO
- ssh_print_hexa("mac: ",data,hmac_digest_len(type));
- if (finallen != hmac_digest_len(type)) {
- printf("Final len is %d\n",finallen);
- }
- ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, hmac_digest_len(type));
+ ssh_print_hexa("mac: ",data,hmac_digest_len(type));
+ if (finallen != hmac_digest_len(type)) {
+ printf("Final len is %d\n",finallen);
+ }
+ ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, hmac_digest_len(type));
#endif
+ crypto->encrypt(crypto, data, out, len);
}
-
- crypto->encrypt(crypto, data, out, len);
-
memcpy(data, out, len);
- BURN_BUFFER(out, len);
+ explicit_bzero(out, len);
SAFE_FREE(out);
- if (session->version == 2) {
- return session->current_crypto->hmacbuf;
- }
-
- return NULL;
+ return session->current_crypto->hmacbuf;
}
/**
@@ -149,13 +188,21 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len)
* @return 0 if hmac and mac are equal, < 0 if not or an error
* occurred.
*/
-int ssh_packet_hmac_verify(ssh_session session, ssh_buffer buffer,
- unsigned char *mac, enum ssh_hmac_e type) {
+int ssh_packet_hmac_verify(ssh_session session,
+ ssh_buffer buffer,
+ uint8_t *mac,
+ enum ssh_hmac_e type)
+{
unsigned char hmacbuf[DIGEST_MAX_LEN] = {0};
HMACCTX ctx;
unsigned int len;
uint32_t seq;
+ /* AEAD type have no mac checking */
+ if (type == SSH_HMAC_AEAD_POLY1305) {
+ return SSH_OK;
+ }
+
ctx = hmac_init(session->current_crypto->decryptMAC, hmac_digest_len(type), type);
if (ctx == NULL) {
return -1;
@@ -178,5 +225,3 @@ int ssh_packet_hmac_verify(ssh_session session, ssh_buffer buffer,
return -1;
}
-
-/* vim: set ts=2 sw=2 et cindent: */
diff --git a/src/pcap.c b/src/pcap.c
index bfb237b..ffb074c 100644
--- a/src/pcap.c
+++ b/src/pcap.c
@@ -165,6 +165,12 @@ int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, uint32_t o
if(header == NULL)
return SSH_ERROR;
gettimeofday(&now,NULL);
+ err = ssh_buffer_allocate_size(header,
+ sizeof(uint32_t) * 4 +
+ ssh_buffer_get_len(packet));
+ if (err < 0) {
+ goto error;
+ }
err = ssh_buffer_add_u32(header,htonl(now.tv_sec));
if (err < 0) {
goto error;
@@ -209,6 +215,12 @@ int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename){
header=ssh_buffer_new();
if(header==NULL)
return SSH_ERROR;
+ err = ssh_buffer_allocate_size(header,
+ sizeof(uint32_t) * 5 +
+ sizeof(uint16_t) * 2);
+ if (err < 0) {
+ goto error;
+ }
err = ssh_buffer_add_u32(header,htonl(PCAP_MAGIC));
if (err < 0) {
goto error;
@@ -509,5 +521,3 @@ int ssh_set_pcap_file(ssh_session session, ssh_pcap_file pcapfile){
#endif
/** @} */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/pki.c b/src/pki.c
index 91f972b..b873173 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -138,9 +138,19 @@ void ssh_key_clean (ssh_key key){
#ifdef HAVE_OPENSSL_ECC
if(key->ecdsa) EC_KEY_free(key->ecdsa);
#endif /* HAVE_OPENSSL_ECC */
+#elif defined HAVE_LIBMBEDCRYPTO
+ if (key->rsa != NULL) {
+ mbedtls_pk_free(key->rsa);
+ SAFE_FREE(key->rsa);
+ }
+
+ if (key->ecdsa != NULL) {
+ mbedtls_ecdsa_free(key->ecdsa);
+ SAFE_FREE(key->ecdsa);
+ }
#endif
if (key->ed25519_privkey != NULL){
- BURN_BUFFER(key->ed25519_privkey, sizeof(ed25519_privkey));
+ explicit_bzero(key->ed25519_privkey, sizeof(ed25519_privkey));
SAFE_FREE(key->ed25519_privkey);
}
SAFE_FREE(key->ed25519_pubkey);
@@ -171,7 +181,9 @@ void ssh_key_free (ssh_key key){
/**
* @brief returns the type of a ssh key
* @param[in] key the ssh_key handle
- * @returns one of SSH_KEYTYPE_RSA,SSH_KEYTYPE_DSS,SSH_KEYTYPE_RSA1
+ * @returns one of SSH_KEYTYPE_RSA, SSH_KEYTYPE_DSS,
+ * SSH_KEYTYPE_ECDSA, SSH_KEYTYPE_ED25519,
+ * SSH_KEYTYPE_DSS_CERT01, SSH_KEYTYPE_RSA_CERT01
* @returns SSH_KEYTYPE_UNKNOWN if the type is unknown
*/
enum ssh_keytypes_e ssh_key_type(const ssh_key key){
@@ -194,8 +206,6 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
return "ssh-dss";
case SSH_KEYTYPE_RSA:
return "ssh-rsa";
- case SSH_KEYTYPE_RSA1:
- return "ssh-rsa1";
case SSH_KEYTYPE_ECDSA:
return "ssh-ecdsa";
case SSH_KEYTYPE_ED25519:
@@ -204,6 +214,7 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
return "ssh-dss-cert-v01@openssh.com";
case SSH_KEYTYPE_RSA_CERT01:
return "ssh-rsa-cert-v01@openssh.com";
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
return NULL;
}
@@ -224,14 +235,10 @@ enum ssh_keytypes_e ssh_key_type_from_name(const char *name) {
return SSH_KEYTYPE_UNKNOWN;
}
- if (strcmp(name, "rsa1") == 0) {
- return SSH_KEYTYPE_RSA1;
- } else if (strcmp(name, "rsa") == 0) {
+ if (strcmp(name, "rsa") == 0) {
return SSH_KEYTYPE_RSA;
} else if (strcmp(name, "dsa") == 0) {
return SSH_KEYTYPE_DSS;
- } else if (strcmp(name, "ssh-rsa1") == 0) {
- return SSH_KEYTYPE_RSA1;
} else if (strcmp(name, "ssh-rsa") == 0) {
return SSH_KEYTYPE_RSA;
} else if (strcmp(name, "ssh-dss") == 0) {
@@ -349,11 +356,12 @@ void ssh_signature_free(ssh_signature sig)
#endif
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
#ifdef HAVE_LIBGCRYPT
gcry_sexp_release(sig->rsa_sig);
#elif defined HAVE_LIBCRYPTO
SAFE_FREE(sig->rsa_sig);
+#elif defined HAVE_LIBMBEDCRYPTO
+ SAFE_FREE(sig->rsa_sig);
#endif
break;
case SSH_KEYTYPE_ECDSA:
@@ -361,6 +369,9 @@ void ssh_signature_free(ssh_signature sig)
gcry_sexp_release(sig->ecdsa_sig);
#elif defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ECC)
ECDSA_SIG_free(sig->ecdsa_sig);
+#elif defined HAVE_LIBMBEDCRYPTO
+ bignum_safe_free(sig->ecdsa_sig.r);
+ bignum_safe_free(sig->ecdsa_sig.s);
#endif
break;
case SSH_KEYTYPE_ED25519:
@@ -368,6 +379,7 @@ void ssh_signature_free(ssh_signature sig)
break;
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01:
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
break;
}
@@ -725,7 +737,6 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
}
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
{
ssh_string e;
ssh_string n;
@@ -756,8 +767,8 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
}
}
break;
- case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
+ case SSH_KEYTYPE_ECDSA:
{
ssh_string e;
ssh_string i;
@@ -815,6 +826,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
break;
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01:
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "Unknown public key protocol %d", type);
@@ -1016,6 +1028,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
enum ssh_keytypes_e type;
struct stat sb;
char *key_buf, *p;
+ size_t buflen, i;
const char *q;
FILE *file;
off_t size;
@@ -1067,19 +1080,29 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
return SSH_ERROR;
}
key_buf[size] = '\0';
+ buflen = strlen(key_buf);
q = p = key_buf;
- while (!isspace((int)*p)) p++;
- *p = '\0';
+ for (i = 0; i < buflen; i++) {
+ if (isspace((int)p[i])) {
+ p[i] = '\0';
+ break;
+ }
+ }
type = ssh_key_type_from_name(q);
if (type == SSH_KEYTYPE_UNKNOWN) {
SAFE_FREE(key_buf);
return SSH_ERROR;
}
- q = ++p;
- while (!isspace((int)*p)) p++;
- *p = '\0';
+
+ q = &p[i + 1];
+ for (; i < buflen; i++) {
+ if (isspace((int)p[i])) {
+ p[i] = '\0';
+ break;
+ }
+ }
rc = ssh_pki_import_pubkey_base64(q, type, pkey);
SAFE_FREE(key_buf);
@@ -1176,7 +1199,6 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
switch(type){
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
rc = pki_key_generate_rsa(key, parameter);
if(rc == SSH_ERROR)
goto error;
@@ -1186,8 +1208,8 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
if(rc == SSH_ERROR)
goto error;
break;
- case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
+ case SSH_KEYTYPE_ECDSA:
rc = pki_key_generate_ecdsa(key, parameter);
if (rc == SSH_ERROR) {
goto error;
@@ -1205,7 +1227,9 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
break;
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01:
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
+ default:
goto error;
}
@@ -1421,14 +1445,6 @@ int ssh_pki_copy_cert_to_privkey(const ssh_key certkey, ssh_key privkey) {
return SSH_OK;
}
-int ssh_pki_export_pubkey_rsa1(const ssh_key key,
- const char *host,
- char *rsa1,
- size_t rsa1_len)
-{
- return pki_export_pubkey_rsa1(key, host, rsa1, rsa1_len);
-}
-
int ssh_pki_export_signature_blob(const ssh_signature sig,
ssh_string *sig_blob)
{
@@ -1553,7 +1569,7 @@ int ssh_pki_signature_verify_blob(ssh_session session,
SSH_LOG(SSH_LOG_FUNCTIONS,
"Going to verify a %s type signature",
- key->type_c);
+ sig->type_c);
if (key->type == SSH_KEYTYPE_ECDSA) {
diff --git a/src/pki_container_openssh.c b/src/pki_container_openssh.c
index 551a7f0..53e1e7f 100644
--- a/src/pki_container_openssh.c
+++ b/src/pki_container_openssh.c
@@ -109,7 +109,7 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
}
memcpy(key->ed25519_privkey, ssh_string_data(privkey), ED25519_SK_LEN);
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN);
- memset(ssh_string_data(privkey), 0, ED25519_SK_LEN);
+ explicit_bzero(ssh_string_data(privkey), ED25519_SK_LEN);
SAFE_FREE(privkey);
SAFE_FREE(pubkey);
break;
@@ -119,11 +119,11 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_RSA:
/* n,e,d,iqmp,p,q */
- case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_ECDSA:
/* curve_name, group, privkey */
SSH_LOG(SSH_LOG_WARN, "Unsupported private key method %s", key->type_c);
goto fail;
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
SSH_LOG(SSH_LOG_WARN, "Unknown private key protocol %s", key->type_c);
goto fail;
@@ -256,7 +256,7 @@ static int pki_private_key_decrypt(ssh_string blob,
if (rc < 0){
return SSH_ERROR;
}
- BURN_BUFFER(passphrase_buffer, sizeof(passphrase_buffer));
+ explicit_bzero(passphrase_buffer, sizeof(passphrase_buffer));
cipher.set_decrypt_key(&cipher,
key_material,
@@ -547,7 +547,7 @@ static int pki_private_key_encrypt(ssh_buffer privkey_buffer,
ssh_buffer_get(privkey_buffer),
ssh_buffer_get_len(privkey_buffer));
ssh_cipher_clear(&cipher);
- BURN_BUFFER(passphrase_buffer, sizeof(passphrase_buffer));
+ explicit_bzero(passphrase_buffer, sizeof(passphrase_buffer));
return SSH_OK;
}
@@ -576,6 +576,7 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
int to_encrypt=0;
unsigned char *b64;
uint32_t str_len, len;
+ int ok;
int rc;
if (privkey == NULL) {
@@ -594,7 +595,11 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
if(buffer == NULL || pubkey_s == NULL){
goto error;
}
- ssh_get_random(&rnd, sizeof(rnd), 0);
+
+ ok = ssh_get_random(&rnd, sizeof(rnd), 0);
+ if (!ok) {
+ goto error;
+ }
privkey_buffer = ssh_buffer_new();
if (privkey_buffer == NULL) {
@@ -634,7 +639,13 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
ssh_buffer_free(kdf_buf);
goto error;
}
- ssh_get_random(ssh_string_data(salt),16, 0);
+
+ ok = ssh_get_random(ssh_string_data(salt), 16, 0);
+ if (!ok) {
+ ssh_buffer_free(kdf_buf);
+ goto error;
+ }
+
ssh_buffer_pack(kdf_buf, "Sd", salt, rounds);
kdf_options = ssh_string_new(ssh_buffer_get_len(kdf_buf));
if (kdf_options == NULL){
@@ -691,7 +702,7 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
"\n",
OPENSSH_HEADER_END,
"\n");
- BURN_BUFFER(b64, strlen((char *)b64));
+ explicit_bzero(b64, strlen((char *)b64));
SAFE_FREE(b64);
if (rc != SSH_OK){
@@ -713,7 +724,7 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
error:
if (privkey_buffer != NULL) {
void *bufptr = ssh_buffer_get(privkey_buffer);
- BURN_BUFFER(bufptr, ssh_buffer_get_len(privkey_buffer));
+ explicit_bzero(bufptr, ssh_buffer_get_len(privkey_buffer));
ssh_buffer_free(privkey_buffer);
}
SAFE_FREE(pubkey_s);
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index 70ac685..7494b16 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -25,6 +25,8 @@
#ifndef _PKI_CRYPTO_H
#define _PKI_CRYPTO_H
+#include "config.h"
+
#include "libssh/priv.h"
#include <openssl/pem.h>
@@ -451,11 +453,30 @@ int pki_key_generate_rsa(ssh_key key, int parameter){
int pki_key_generate_dss(ssh_key key, int parameter){
int rc;
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
+ key->dsa = DSA_new();
+ if (key->dsa == NULL) {
+ return SSH_ERROR;
+ }
+ rc = DSA_generate_parameters_ex(key->dsa,
+ parameter,
+ NULL, /* seed */
+ 0, /* seed_len */
+ NULL, /* counter_ret */
+ NULL, /* h_ret */
+ NULL); /* cb */
+ if (rc != 1) {
+ DSA_free(key->dsa);
+ key->dsa = NULL;
+ return SSH_ERROR;
+ }
+#else
key->dsa = DSA_generate_parameters(parameter, NULL, 0, NULL, NULL,
NULL, NULL);
if(key->dsa == NULL){
return SSH_ERROR;
}
+#endif
rc = DSA_generate_key(key->dsa);
if (rc != 1){
DSA_free(key->dsa);
@@ -616,11 +637,6 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
BIO *mem;
int rc;
- /* needed for openssl initialization */
- if (ssh_init() < 0) {
- return NULL;
- }
-
mem = BIO_new(BIO_s_mem());
if (mem == NULL) {
return NULL;
@@ -641,7 +657,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
} else {
rc = PEM_write_bio_DSAPrivateKey(mem,
key->dsa,
- NULL, /* cipher */
+ EVP_aes_128_cbc(),
NULL, /* kstr */
0, /* klen */
NULL, /* auth_fn */
@@ -666,7 +682,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
} else {
rc = PEM_write_bio_RSAPrivateKey(mem,
key->rsa,
- NULL, /* cipher */
+ EVP_aes_128_cbc(),
NULL, /* kstr */
0, /* klen */
NULL, /* auth_fn */
@@ -676,8 +692,8 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
goto err;
}
break;
- case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
+ case SSH_KEYTYPE_ECDSA:
if (passphrase == NULL) {
struct pem_get_password_struct pgp = { auth_fn, auth_data };
@@ -691,7 +707,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
} else {
rc = PEM_write_bio_ECPrivateKey(mem,
key->ecdsa,
- NULL, /* cipher */
+ EVP_aes_128_cbc(),
NULL, /* kstr */
0, /* klen */
NULL, /* auth_fn */
@@ -709,6 +725,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_UNKNOWN:
+ default:
BIO_free(mem);
SSH_LOG(SSH_LOG_WARN, "Unkown or invalid private key type %d", key->type);
return NULL;
@@ -746,11 +763,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
void *ecdsa = NULL;
#endif
- /* needed for openssl initialization */
- if (ssh_init() < 0) {
- return NULL;
- }
-
type = pki_privatekey_type_from_string(b64_key);
if (type == SSH_KEYTYPE_UNKNOWN) {
SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key.");
@@ -1158,37 +1170,6 @@ fail:
return NULL;
}
-int pki_export_pubkey_rsa1(const ssh_key key,
- const char *host,
- char *rsa1,
- size_t rsa1_len)
-{
- char *e;
- char *n;
- int rsa_size = RSA_size(key->rsa);
- const BIGNUM *be, *bn;
-
- RSA_get0_key(key->rsa, &bn, &be, NULL);
- e = bignum_bn2dec(be);
- if (e == NULL) {
- return SSH_ERROR;
- }
-
- n = bignum_bn2dec(bn);
- if (n == NULL) {
- OPENSSL_free(e);
- return SSH_ERROR;
- }
-
- snprintf(rsa1, rsa1_len,
- "%s %d %s %s\n",
- host, rsa_size << 3, e, n);
- OPENSSL_free(e);
- OPENSSL_free(n);
-
- return SSH_OK;
-}
-
/**
* @internal
*
@@ -1412,7 +1393,7 @@ static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey,
blob_orig = (char *) ssh_string_data(sig_blob);
/* front-pad the buffer with zeroes */
- BURN_BUFFER(blob_padded_data, pad_len);
+ explicit_bzero(blob_padded_data, pad_len);
/* fill the rest with the actual signature blob */
memcpy(blob_padded_data + pad_len, blob_orig, len);
diff --git a/src/pki_ed25519.c b/src/pki_ed25519.c
index 393948a..45362c4 100644
--- a/src/pki_ed25519.c
+++ b/src/pki_ed25519.c
@@ -21,6 +21,8 @@
* MA 02111-1307, USA.
*/
+#include "config.h"
+
#include "libssh/pki.h"
#include "libssh/pki_priv.h"
#include "libssh/ed25519.h"
@@ -130,8 +132,8 @@ int pki_ed25519_verify(const ssh_key pubkey,
hlen + ED25519_SIG_LEN,
*pubkey->ed25519_pubkey);
- BURN_BUFFER(buffer, hlen + ED25519_SIG_LEN);
- BURN_BUFFER(buffer2, hlen);
+ explicit_bzero(buffer, hlen + ED25519_SIG_LEN);
+ explicit_bzero(buffer2, hlen);
SAFE_FREE(buffer);
SAFE_FREE(buffer2);
if (rc == 0) {
@@ -201,24 +203,27 @@ int pki_ed25519_key_cmp(const ssh_key k1,
*/
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
{
- if (key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL) {
+ if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
- new->ed25519_privkey = malloc(ED25519_SK_LEN);
- if (new->ed25519_privkey == NULL) {
- return SSH_ERROR;
+ if (key->ed25519_privkey != NULL) {
+ new->ed25519_privkey = malloc(ED25519_SK_LEN);
+ if (new->ed25519_privkey == NULL) {
+ return SSH_ERROR;
+ }
+ memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN);
}
- new->ed25519_pubkey = malloc(ED25519_PK_LEN);
- if (new->ed25519_privkey == NULL || new->ed25519_pubkey == NULL){
- SAFE_FREE(new->ed25519_privkey);
- return SSH_ERROR;
+ if (key->ed25519_pubkey != NULL) {
+ new->ed25519_pubkey = malloc(ED25519_PK_LEN);
+ if (new->ed25519_pubkey == NULL) {
+ SAFE_FREE(new->ed25519_privkey);
+ return SSH_ERROR;
+ }
+ memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN);
}
- memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN);
- memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN);
-
return SSH_OK;
}
diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c
index 025ff1b..9f53321 100644
--- a/src/pki_gcrypt.c
+++ b/src/pki_gcrypt.c
@@ -314,7 +314,7 @@ static int privatekey_decrypt(int algo, int mode, unsigned int key_len,
if (gcry_cipher_open(&cipher, algo, mode, 0)
|| gcry_cipher_setkey(cipher, key, key_len)
|| gcry_cipher_setiv(cipher, iv, iv_len)
- || (tmp = malloc(ssh_buffer_get_len(data) * sizeof (char))) == NULL
+ || (tmp = calloc(ssh_buffer_get_len(data), sizeof(char))) == NULL
|| gcry_cipher_decrypt(cipher, tmp, ssh_buffer_get_len(data),
ssh_buffer_get(data), ssh_buffer_get_len(data))) {
gcry_cipher_close(cipher);
@@ -918,11 +918,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
enum ssh_keytypes_e type;
int valid;
- /* needed for gcrypt initialization */
- if (ssh_init() < 0) {
- return NULL;
- }
-
type = pki_privatekey_type_from_string(b64_key);
if (type == SSH_KEYTYPE_UNKNOWN) {
SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key.");
@@ -950,7 +945,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
}
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
if (passphrase == NULL) {
if (auth_fn) {
valid = b64decode_rsa_privatekey(b64_key, &rsa, auth_fn,
@@ -1000,7 +994,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
break;
#endif
case SSH_KEYTYPE_ED25519:
- /* Cannot open ed25519 keys with libgcrypt */
+ /* Cannot open ed25519 keys with libgcrypt */
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "Unkown or invalid private key type %d", type);
@@ -1146,7 +1141,6 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
}
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
err = gcry_sexp_extract_param(key->rsa,
NULL,
"ned?p?q?u?",
@@ -1216,6 +1210,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
}
break;
#endif
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
ssh_key_free(new);
@@ -1321,19 +1316,19 @@ static int _bignum_cmp(const gcry_sexp_t s1,
sexp = gcry_sexp_find_token(s2, what, 0);
if (sexp == NULL) {
- bignum_free(b1);
+ bignum_safe_free(b1);
return 1;
}
b2 = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG);
gcry_sexp_release(sexp);
if (b2 == NULL) {
- bignum_free(b1);
+ bignum_safe_free(b1);
return 1;
}
result = !! bignum_cmp(b1, b2);
- bignum_free(b1);
- bignum_free(b2);
+ bignum_safe_free(b1);
+ bignum_safe_free(b2);
return result;
}
@@ -1366,7 +1361,6 @@ int pki_key_compare(const ssh_key k1,
}
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
if (_bignum_cmp(k1->rsa, k2->rsa, "e") != 0) {
return 1;
}
@@ -1413,6 +1407,7 @@ int pki_key_compare(const ssh_key k1,
#endif
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01:
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
return 1;
}
@@ -1521,7 +1516,6 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
e = ssh_sexp_extract_mpi(key->rsa,
"e",
GCRYMPI_FMT_USG,
@@ -1592,6 +1586,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
e = NULL;
break;
#endif
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
goto fail;
@@ -1628,36 +1623,6 @@ fail:
return NULL;
}
-int pki_export_pubkey_rsa1(const ssh_key key,
- const char *host,
- char *rsa1,
- size_t rsa1_len)
-{
- gpg_error_t err;
- int rsa_size;
- bignum E, N;
- char *e, *n;
-
- err = gcry_sexp_extract_param(key->rsa, NULL, "en", &E, &N, NULL);
- if (err != 0) {
- return SSH_ERROR;
- }
- e = bignum_bn2dec(E);
- n = bignum_bn2dec(N);
-
- rsa_size = (gcry_pk_get_nbits(key->rsa) + 7) / 8;
-
- snprintf(rsa1, rsa1_len,
- "%s %d %s %s\n",
- host, rsa_size << 3, e, n);
- SAFE_FREE(e);
- SAFE_FREE(n);
- bignum_free(E);
- bignum_free(N);
-
- return SSH_OK;
-}
-
ssh_string pki_signature_to_blob(const ssh_signature sig)
{
char buffer[40] = { 0 };
@@ -1721,7 +1686,6 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
ssh_string_fill(sig_blob, buffer, 40);
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
sexp = gcry_sexp_find_token(sig->rsa_sig, "s", 0);
if (sexp == NULL) {
return NULL;
@@ -1796,6 +1760,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
break;
}
#endif
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %d", sig->type);
@@ -1856,7 +1821,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
rsalen = (gcry_pk_get_nbits(pubkey->rsa) + 7) / 8;
if (len > rsalen) {
@@ -1971,6 +1935,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
break;
#endif
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "Unknown signature type");
@@ -2021,7 +1986,6 @@ int pki_signature_verify(ssh_session session,
}
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
err = gcry_sexp_build(&sexp,
NULL,
"(data(flags pkcs1)(hash sha1 %b))",
@@ -2082,6 +2046,7 @@ int pki_signature_verify(ssh_session session,
}
break;
#endif
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
ssh_set_error(session, SSH_FATAL, "Unknown public key type");
@@ -2129,7 +2094,6 @@ ssh_signature pki_do_sign(const ssh_key privkey,
}
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
err = gcry_sexp_build(&sexp,
NULL,
"(data(flags pkcs1)(hash sha1 %b))",
@@ -2174,6 +2138,7 @@ ssh_signature pki_do_sign(const ssh_key privkey,
}
break;
#endif
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
ssh_signature_free(sig);
@@ -2223,7 +2188,6 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
}
break;
case SSH_KEYTYPE_RSA:
- case SSH_KEYTYPE_RSA1:
err = gcry_sexp_build(&sexp,
NULL,
"(data(flags pkcs1)(hash sha1 %b))",
@@ -2261,6 +2225,7 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
}
break;
#endif
+ case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:
return NULL;
@@ -2271,5 +2236,3 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
#endif /* WITH_SERVER */
#endif /* HAVE_LIBGCRYPT */
-
-/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c
new file mode 100644
index 0000000..3263db4
--- /dev/null
+++ b/src/pki_mbedcrypto.c
@@ -0,0 +1,1278 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2017 Sartura d.o.o.
+ *
+ * Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LIBMBEDCRYPTO
+#include <mbedtls/pk.h>
+#include <mbedtls/error.h>
+
+#include "libssh/priv.h"
+#include "libssh/pki.h"
+#include "libssh/pki_priv.h"
+#include "libssh/buffer.h"
+#include "libssh/bignum.h"
+
+#define MAX_PASSPHRASE_SIZE 1024
+#define MAX_KEY_SIZE 32
+
+ssh_string pki_private_key_to_pem(const ssh_key key, const char *passphrase,
+ ssh_auth_callback auth_fn, void *auth_data)
+{
+ (void) key;
+ (void) passphrase;
+ (void) auth_fn;
+ (void) auth_data; return NULL;
+}
+
+static int pki_key_ecdsa_to_nid(mbedtls_ecdsa_context *ecdsa)
+{
+ mbedtls_ecp_group_id id;
+
+ id = ecdsa->grp.id;
+ if (id == MBEDTLS_ECP_DP_SECP256R1) {
+ return NID_mbedtls_nistp256;
+ } else if (id == MBEDTLS_ECP_DP_SECP384R1) {
+ return NID_mbedtls_nistp384;
+ } else if (id == MBEDTLS_ECP_DP_SECP521R1) {
+ return NID_mbedtls_nistp521;
+ }
+
+ return -1;
+}
+
+ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase,
+ ssh_auth_callback auth_fn, void *auth_data)
+{
+ ssh_key key = NULL;
+ mbedtls_pk_context *rsa = NULL;
+ mbedtls_pk_context *ecdsa = NULL;
+ ed25519_privkey *ed25519 = NULL;
+ enum ssh_keytypes_e type;
+ int valid;
+ /* mbedtls pk_parse_key expects strlen to count the 0 byte */
+ size_t b64len = strlen(b64_key) + 1;
+ unsigned char tmp[MAX_PASSPHRASE_SIZE] = {0};
+
+ type = pki_privatekey_type_from_string(b64_key);
+ if (type == SSH_KEYTYPE_UNKNOWN) {
+ SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key.");
+ return NULL;
+ }
+
+ switch (type) {
+ case SSH_KEYTYPE_RSA:
+ rsa = malloc(sizeof(mbedtls_pk_context));
+ if (rsa == NULL) {
+ return NULL;
+ }
+
+ mbedtls_pk_init(rsa);
+
+ if (passphrase == NULL) {
+ if (auth_fn) {
+ valid = auth_fn("Passphrase for private key:", (char *) tmp,
+ MAX_PASSPHRASE_SIZE, 0, 0, auth_data);
+ if (valid < 0) {
+ return NULL;
+ }
+ /* TODO fix signedness and strlen */
+ valid = mbedtls_pk_parse_key(rsa,
+ (const unsigned char *) b64_key,
+ b64len, tmp,
+ strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE));
+ } else {
+ valid = mbedtls_pk_parse_key(rsa,
+ (const unsigned char *) b64_key,
+ b64len, NULL,
+ 0);
+ }
+ } else {
+ valid = mbedtls_pk_parse_key(rsa,
+ (const unsigned char *) b64_key, b64len,
+ (const unsigned char *) passphrase,
+ strnlen(passphrase, MAX_PASSPHRASE_SIZE));
+ }
+
+ if (valid != 0) {
+ char error_buf[100];
+ mbedtls_strerror(valid, error_buf, 100);
+ SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf);
+ goto fail;
+ }
+ break;
+ case SSH_KEYTYPE_ECDSA: