mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
Compare commits
101 Commits
63fbf00efe
...
libssh-0.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67c0ce3d21 | ||
|
|
f618689c82 | ||
|
|
aaeaca8c6e | ||
|
|
58c26f4823 | ||
|
|
c888d9c690 | ||
|
|
07df7bb4e6 | ||
|
|
5aecfb5a96 | ||
|
|
50b37f2991 | ||
|
|
a47a291303 | ||
|
|
f199bd4879 | ||
|
|
4f7cb6076a | ||
|
|
3f6820694e | ||
|
|
0da6597fe4 | ||
|
|
0a13045f68 | ||
|
|
b56ffd8424 | ||
|
|
c60ac3fe02 | ||
|
|
84eab65edc | ||
|
|
7c3e37bf4c | ||
|
|
ab9921ee6a | ||
|
|
9296bcd4bb | ||
|
|
24f39761f3 | ||
|
|
49e8a4ef19 | ||
|
|
d7e1141c1e | ||
|
|
fd5c598477 | ||
|
|
de4034bfe0 | ||
|
|
6ccd84bae9 | ||
|
|
e4c281c7ce | ||
|
|
93541fe150 | ||
|
|
e6ba98a0aa | ||
|
|
6dcb960501 | ||
|
|
fcacc7fe8c | ||
|
|
f078f53911 | ||
|
|
27f5bfd129 | ||
|
|
4a0cbe396d | ||
|
|
a1812e9ac1 | ||
|
|
0e3dbd6c69 | ||
|
|
d2af62624d | ||
|
|
93113ccfb9 | ||
|
|
9ffaa12012 | ||
|
|
ae5146f7ba | ||
|
|
dd554ebb32 | ||
|
|
fae61f1d09 | ||
|
|
9e8e5f5cb2 | ||
|
|
80c1dbdb61 | ||
|
|
4505c076b3 | ||
|
|
99dc2002b9 | ||
|
|
878d8320c1 | ||
|
|
80e729fe33 | ||
|
|
47945671af | ||
|
|
b2e7ef6836 | ||
|
|
651fea9f14 | ||
|
|
f10db964b5 | ||
|
|
703f0a0f36 | ||
|
|
7b8d57fbb6 | ||
|
|
8e793d930e | ||
|
|
cc2feabe73 | ||
|
|
4d57d73faf | ||
|
|
4bd9041afb | ||
|
|
74e084f76c | ||
|
|
6c80718c0d | ||
|
|
a330806e4b | ||
|
|
3b01c328ab | ||
|
|
5b981a9e3d | ||
|
|
36dc66da81 | ||
|
|
2a3718de51 | ||
|
|
1fd68ec732 | ||
|
|
fa3caa61fd | ||
|
|
aaa978ad06 | ||
|
|
b9530cedbe | ||
|
|
7ff0af7543 | ||
|
|
b040856ccf | ||
|
|
79900e5246 | ||
|
|
63b0399373 | ||
|
|
39665fd9c5 | ||
|
|
83f0be1f04 | ||
|
|
3bc5f88f77 | ||
|
|
466ca07626 | ||
|
|
b6e757d692 | ||
|
|
3f2375e948 | ||
|
|
4d06c2f283 | ||
|
|
0298bfbbf0 | ||
|
|
2399a9f8de | ||
|
|
79756c5c56 | ||
|
|
e8510043d2 | ||
|
|
1f7889f271 | ||
|
|
89efd56217 | ||
|
|
e3fca31c59 | ||
|
|
d71a7976dd | ||
|
|
8fe8d13e29 | ||
|
|
722f979790 | ||
|
|
2c60ef04d9 | ||
|
|
ec486d13db | ||
|
|
ebfe46f6ad | ||
|
|
3c0897b975 | ||
|
|
993e0df81e | ||
|
|
551188d99b | ||
|
|
cafafe8f5a | ||
|
|
c6c7856b51 | ||
|
|
ea71af9c22 | ||
|
|
bb98413fc1 | ||
|
|
2a8cd81e8f |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,6 +4,8 @@
|
||||
*.swp
|
||||
*~$
|
||||
cscope.*
|
||||
compile_commands.json
|
||||
/.clangd
|
||||
tags
|
||||
/build
|
||||
/obj*
|
||||
|
||||
@@ -6,7 +6,7 @@ variables:
|
||||
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
|
||||
# pkd tests fail on CentOS7 docker images, so we don't use -DSERVER_TESTING=ON
|
||||
centos7/openssl_1.0.x/x86_64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
|
||||
script:
|
||||
@@ -14,7 +14,7 @@ centos7/openssl_1.0.x/x86_64:
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -34,6 +34,7 @@ fedora/openssl_1.1.x/x86_64:
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_BLOWFISH_CIPHER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DWITH_DEBUG_CRYPTO=ON
|
||||
-DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
@@ -168,8 +169,7 @@ fedora/csbuild:
|
||||
|
||||
- csbuild
|
||||
--build-dir=obj-csbuild
|
||||
--prep-cmd="rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@"
|
||||
--build-cmd "make clean && make -j$(nproc)"
|
||||
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@ && make clean && make -j$(nproc)"
|
||||
--git-commit-range $CI_COMMIT_RANGE
|
||||
--color
|
||||
--print-current --print-fixed
|
||||
@@ -215,7 +215,7 @@ fedora/libgcrypt/x86_64:
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DWITH_GCRYPT=ON .. &&
|
||||
-DWITH_GCRYPT=ON -DWITH_DEBUG_CRYPTO=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -235,7 +235,7 @@ fedora/mbedtls/x86_64:
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DWITH_MBEDTLS=ON .. &&
|
||||
-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
|
||||
@@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
||||
include(DefineCMakeDefaults)
|
||||
include(DefineCompilerFlags)
|
||||
|
||||
project(libssh VERSION 0.8.90 LANGUAGES C)
|
||||
project(libssh VERSION 0.9.1 LANGUAGES C)
|
||||
|
||||
# global needed variable
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
@@ -22,16 +22,16 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
# Increment AGE. Set REVISION to 0
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.8.1")
|
||||
set(LIBRARY_VERSION "4.8.2")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
|
||||
# add definitions
|
||||
include(DefinePlatformDefaults)
|
||||
include(DefineInstallationPaths)
|
||||
include(DefineOptions.cmake)
|
||||
include(CPackConfig.cmake)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
include(CompilerChecks.cmake)
|
||||
|
||||
@@ -117,7 +117,7 @@ install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}/pkgconfig
|
||||
${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
COMPONENT
|
||||
pkgconfig
|
||||
)
|
||||
@@ -133,21 +133,13 @@ write_basic_package_version_file(libssh-config-version.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
# libssh-config.cmake
|
||||
configure_package_config_file(${PROJECT_NAME}-config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}/${PROJECT_NAME}
|
||||
PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR)
|
||||
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_DIR}/${PROJECT_NAME}
|
||||
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
COMPONENT
|
||||
devel
|
||||
)
|
||||
devel)
|
||||
|
||||
if (WITH_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
@@ -213,6 +205,11 @@ endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
|
||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET})
|
||||
|
||||
# Link compile database for clangd
|
||||
execute_process(COMMAND cmake -E create_symlink
|
||||
"${CMAKE_BINARY_DIR}/compile_commands.json"
|
||||
"${CMAKE_SOURCE_DIR}/compile_commands.json")
|
||||
|
||||
message(STATUS "********************************************")
|
||||
message(STATUS "********** ${PROJECT_NAME} build options : **********")
|
||||
|
||||
|
||||
82
ChangeLog
82
ChangeLog
@@ -1,7 +1,21 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.9.0 (released 2019-02-xx)
|
||||
version 0.9.1 (released 2019-10-25)
|
||||
* Added support for Ed25519 via OpenSSL
|
||||
* Added support for X25519 via OpenSSL
|
||||
* Added support for localuser in Match keyword
|
||||
* Fixed Match keyword to be case sensitive
|
||||
* Fixed compilation with LibreSSL
|
||||
* Fixed error report of channel open (T75)
|
||||
* Fixed sftp documentation (T137)
|
||||
* Fixed known_hosts parsing (T156)
|
||||
* Fixed build issue with MinGW (T157)
|
||||
* Fixed build with gcc 9 (T164)
|
||||
* Fixed deprecation issues (T165)
|
||||
* Fixed known_hosts directory creation (T166)
|
||||
|
||||
version 0.9.0 (released 2019-06-28)
|
||||
* Added support for AES-GCM
|
||||
* Added improved rekeying support
|
||||
* Added performance improvements
|
||||
@@ -11,10 +25,76 @@ version 0.9.0 (released 2019-02-xx)
|
||||
* Added support for Encrypt-then-MAC mode
|
||||
* Added support for parsing server side configuration file
|
||||
* Added support for ECDSA/Ed25519 certificates
|
||||
* Added FIPS 140-2 compatibility
|
||||
* Improved known_hosts parsing
|
||||
* Improved documentation
|
||||
* Improved OpenSSL API usage for KEX, DH, and signatures
|
||||
|
||||
version 0.8.7 (released 2019-02-25)
|
||||
* Fixed handling extension flags in the server implementation
|
||||
* Fixed exporting ed25519 private keys
|
||||
* Fixed corner cases for rsa-sha2 signatures
|
||||
* Fixed some issues with connector
|
||||
|
||||
version 0.8.6 (released 2018-12-24)
|
||||
* Fixed compilation issues with different OpenSSL versions
|
||||
* Fixed StrictHostKeyChecking in new knownhosts API
|
||||
* Fixed ssh_send_keepalive() with packet filter
|
||||
* Fixed possible crash with knownhosts options
|
||||
* Fixed issus with rekeying
|
||||
* Fixed strong ECDSA keys
|
||||
* Fixed some issues with rsa-sha2 extentions
|
||||
* Fixed access violation in ssh_init() (static linking)
|
||||
* Fixed ssh_channel_close() handling
|
||||
|
||||
version 0.8.5 (released 2018-10-29)
|
||||
* Added support to get known_hosts locations with ssh_options_get()
|
||||
* Fixed preferred algorithm for known hosts negotiations
|
||||
* Fixed KEX with some server implementations (e.g. Cisco)
|
||||
* Fixed issues with MSVC
|
||||
* Fixed keyboard-interactive auth in server mode
|
||||
(regression from CVE-2018-10933)
|
||||
* Fixed gssapi auth in server mode (regression from CVE-2018-10933)
|
||||
* Fixed socket fd handling with proxy command
|
||||
* Fixed a memory leak with OpenSSL
|
||||
|
||||
version 0.8.4 (released 2018-10-16)
|
||||
* Fixed CVE-2018-10933
|
||||
* Fixed building without globbing support
|
||||
* Fixed possible memory leaks
|
||||
* Avoid SIGPIPE on sockets
|
||||
|
||||
version 0.8.3 (released 2018-09-21)
|
||||
* Added support for rsa-sha2
|
||||
* Added support to parse private keys in openssh container format
|
||||
(other than ed25519)
|
||||
* Added support for diffie-hellman-group18-sha512 and
|
||||
diffie-hellman-group16-sha512
|
||||
* Added ssh_get_fingerprint_hash()
|
||||
* Added ssh_pki_export_privkey_base64()
|
||||
* Added support for Match keyword in config file
|
||||
* Improved performance and reduced memory footprint for sftp
|
||||
* Fixed ecdsa publickey auth
|
||||
* Fixed reading a closed channel
|
||||
* Added support to announce posix-rename@openssh.com and
|
||||
hardlink@openssh.com in the sftp server
|
||||
|
||||
version 0.8.2 (released 2018-08-30)
|
||||
* Added sha256 fingerprints for pubkeys
|
||||
* Improved compiler flag detection
|
||||
* Fixed race condition in reading sftp messages
|
||||
* Fixed doxygen generation and added modern style
|
||||
* Fixed library initialization on Windows
|
||||
* Fixed __bounded__ attribute detection
|
||||
* Fixed a bug in the options parser
|
||||
* Fixed documentation for new knwon_hosts API
|
||||
|
||||
version 0.8.1 (released 2018-08-13)
|
||||
* Fixed version number in the header
|
||||
* Fixed version number in pkg-config and cmake config
|
||||
* Fixed library initialization
|
||||
* Fixed attribute detection
|
||||
|
||||
version 0.8.0 (released 2018-08-10)
|
||||
* Removed support for deprecated SSHv1 protocol
|
||||
* Added new connector API for clients
|
||||
|
||||
@@ -9,10 +9,7 @@ include(TestBigEndian)
|
||||
|
||||
set(PACKAGE ${PROJECT_NAME})
|
||||
set(VERSION ${PROJECT_VERSION})
|
||||
set(DATADIR ${DATA_INSTALL_DIR})
|
||||
set(LIBDIR ${LIB_INSTALL_DIR})
|
||||
set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}")
|
||||
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
|
||||
set(SYSCONFDIR ${CMAKE_INSTALL_SYSCONFDIR})
|
||||
|
||||
set(BINARYDIR ${CMAKE_BINARY_DIR})
|
||||
set(SOURCEDIR ${CMAKE_SOURCE_DIR})
|
||||
@@ -131,12 +128,32 @@ if (OPENSSL_FOUND)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_KDF_CTX_new_id HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(FIPS_mode HAVE_OPENSSL_FIPS_MODE)
|
||||
|
||||
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)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_DigestSign HAVE_OPENSSL_EVP_DIGESTSIGN)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_DigestVerify HAVE_OPENSSL_EVP_DIGESTVERIFY)
|
||||
|
||||
check_function_exists(OPENSSL_ia32cap_loc HAVE_OPENSSL_IA32CAP_LOC)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_symbol_exists(EVP_PKEY_ED25519 "openssl/evp.h" HAVE_OPENSSL_ED25519)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_symbol_exists(EVP_PKEY_X25519 "openssl/evp.h" HAVE_OPENSSL_X25519)
|
||||
|
||||
unset(CMAKE_REQUIRED_INCLUDES)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif()
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
if (UNIX OR OS2)
|
||||
IF (NOT APPLICATION_NAME)
|
||||
MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME")
|
||||
SET(APPLICATION_NAME ${PROJECT_NAME})
|
||||
ENDIF (NOT APPLICATION_NAME)
|
||||
|
||||
# Suffix for Linux
|
||||
SET(LIB_SUFFIX
|
||||
CACHE STRING "Define suffix of directory name (32/64)"
|
||||
)
|
||||
|
||||
SET(EXEC_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}"
|
||||
CACHE PATH "Base directory for executables and libraries"
|
||||
)
|
||||
SET(SHARE_INSTALL_PREFIX
|
||||
"${CMAKE_INSTALL_PREFIX}/share"
|
||||
CACHE PATH "Base directory for files which go to share/"
|
||||
)
|
||||
SET(DATA_INSTALL_PREFIX
|
||||
"${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}"
|
||||
CACHE PATH "The parent directory where applications can install their data")
|
||||
|
||||
# The following are directories where stuff will be installed to
|
||||
SET(BIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/bin"
|
||||
CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)"
|
||||
)
|
||||
SET(SBIN_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/sbin"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)"
|
||||
)
|
||||
SET(LIB_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)"
|
||||
)
|
||||
SET(LIBEXEC_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/libexec"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)"
|
||||
)
|
||||
SET(PLUGIN_INSTALL_DIR
|
||||
"${LIB_INSTALL_DIR}/${APPLICATION_NAME}"
|
||||
CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})"
|
||||
)
|
||||
SET(INCLUDE_INSTALL_DIR
|
||||
"${CMAKE_INSTALL_PREFIX}/include"
|
||||
CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
|
||||
)
|
||||
|
||||
set(CMAKE_INSTALL_DIR
|
||||
"${LIB_INSTALL_DIR}/cmake"
|
||||
CACHE PATH "The subdirectory to install cmake config files")
|
||||
|
||||
SET(DATA_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}"
|
||||
CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})"
|
||||
)
|
||||
SET(HTML_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/doc/HTML"
|
||||
CACHE PATH "The HTML install dir for documentation (default data/doc/html)"
|
||||
)
|
||||
SET(ICON_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/icons"
|
||||
CACHE PATH "The icon install dir (default data/icons/)"
|
||||
)
|
||||
SET(SOUND_INSTALL_DIR
|
||||
"${DATA_INSTALL_PREFIX}/sounds"
|
||||
CACHE PATH "The install dir for sound files (default data/sounds)"
|
||||
)
|
||||
|
||||
SET(LOCALE_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/locale"
|
||||
CACHE PATH "The install dir for translations (default prefix/share/locale)"
|
||||
)
|
||||
|
||||
SET(XDG_APPS_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/applications/"
|
||||
CACHE PATH "The XDG apps dir"
|
||||
)
|
||||
SET(XDG_DIRECTORY_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/desktop-directories"
|
||||
CACHE PATH "The XDG directory"
|
||||
)
|
||||
|
||||
SET(SYSCONF_INSTALL_DIR
|
||||
"${EXEC_INSTALL_PREFIX}/etc"
|
||||
CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)"
|
||||
)
|
||||
SET(MAN_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/man"
|
||||
CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)"
|
||||
)
|
||||
SET(INFO_INSTALL_DIR
|
||||
"${SHARE_INSTALL_PREFIX}/info"
|
||||
CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)"
|
||||
)
|
||||
else()
|
||||
# Same same
|
||||
set(BIN_INSTALL_DIR "bin" CACHE PATH "-")
|
||||
set(SBIN_INSTALL_DIR "sbin" CACHE PATH "-")
|
||||
set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "-")
|
||||
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
|
||||
set(CMAKE_INSTALL_DIR "CMake" CACHE PATH "-")
|
||||
set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-")
|
||||
set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
|
||||
set(ICON_INSTALL_DIR "icons" CACHE PATH "-")
|
||||
set(SOUND_INSTALL_DIR "soudns" CACHE PATH "-")
|
||||
set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-")
|
||||
endif ()
|
||||
@@ -4,10 +4,6 @@
|
||||
/* Version number of package */
|
||||
#cmakedefine VERSION "${PROJECT_VERSION}"
|
||||
|
||||
#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}"
|
||||
#cmakedefine DATADIR "${DATADIR}"
|
||||
#cmakedefine LIBDIR "${LIBDIR}"
|
||||
#cmakedefine PLUGINDIR "${PLUGINDIR}"
|
||||
#cmakedefine SYSCONFDIR "${SYSCONFDIR}"
|
||||
#cmakedefine BINARYDIR "${BINARYDIR}"
|
||||
#cmakedefine SOURCEDIR "${SOURCEDIR}"
|
||||
@@ -101,6 +97,12 @@
|
||||
/* Define to 1 if you have gl_flags as a glob_t sturct member */
|
||||
#cmakedefine HAVE_GLOB_GL_FLAGS_MEMBER 1
|
||||
|
||||
/* Define to 1 if you have OpenSSL with Ed25519 support */
|
||||
#cmakedefine HAVE_OPENSSL_ED25519 1
|
||||
|
||||
/* Define to 1 if you have OpenSSL with X25519 support */
|
||||
#cmakedefine HAVE_OPENSSL_X25519 1
|
||||
|
||||
/*************************** FUNCTIONS ***************************/
|
||||
|
||||
/* Define to 1 if you have the `EVP_aes128_ctr' function. */
|
||||
@@ -124,6 +126,15 @@
|
||||
/* Define to 1 if you have the `EVP_KDF_CTX_new_id' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID 1
|
||||
|
||||
/* Define to 1 if you have the `FIPS_mode' function. */
|
||||
#cmakedefine HAVE_OPENSSL_FIPS_MODE 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_DigestSign' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_DIGESTSIGN 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_DigestVerify' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_DIGESTVERIFY 1
|
||||
|
||||
/* Define to 1 if you have the `OPENSSL_ia32cap_loc' function. */
|
||||
#cmakedefine HAVE_OPENSSL_IA32CAP_LOC 1
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
/* client.c */
|
||||
/* ssh_client.c */
|
||||
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
* Copyright 2003-2015 Aris Adamantiadis
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* You are free to copy this file, modify it in any way, consider it being public
|
||||
* domain. This does not apply to the rest of the library though, but it is
|
||||
* allowed to cut-and-paste working code from this file to any license of
|
||||
* program.
|
||||
* The goal is to show the API in action. It's not a reference on how terminal
|
||||
* clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
@@ -197,19 +198,20 @@ static void sizechanged(void)
|
||||
static void select_loop(ssh_session session,ssh_channel channel)
|
||||
{
|
||||
ssh_connector connector_in, connector_out, connector_err;
|
||||
int rc;
|
||||
|
||||
ssh_event event = ssh_event_new();
|
||||
|
||||
/* stdin */
|
||||
connector_in = ssh_connector_new(session);
|
||||
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDOUT);
|
||||
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
|
||||
ssh_connector_set_in_fd(connector_in, 0);
|
||||
ssh_event_add_connector(event, connector_in);
|
||||
|
||||
/* stdout */
|
||||
connector_out = ssh_connector_new(session);
|
||||
ssh_connector_set_out_fd(connector_out, 1);
|
||||
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDOUT);
|
||||
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
|
||||
ssh_event_add_connector(event, connector_out);
|
||||
|
||||
/* stderr */
|
||||
@@ -222,7 +224,11 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
||||
if (signal_delayed) {
|
||||
sizechanged();
|
||||
}
|
||||
ssh_event_dopoll(event, 60000);
|
||||
rc = ssh_event_dopoll(event, 60000);
|
||||
if (rc == SSH_ERROR) {
|
||||
fprintf(stderr, "Error in ssh_event_dopoll()\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ssh_event_remove_connector(event, connector_in);
|
||||
ssh_event_remove_connector(event, connector_out);
|
||||
@@ -233,7 +239,6 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
||||
ssh_connector_free(connector_err);
|
||||
|
||||
ssh_event_free(event);
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
static void shell(ssh_session session)
|
||||
@@ -241,7 +246,11 @@ static void shell(ssh_session session)
|
||||
ssh_channel channel;
|
||||
struct termios terminal_local;
|
||||
int interactive=isatty(0);
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (interactive) {
|
||||
tcgetattr(0, &terminal_local);
|
||||
@@ -250,6 +259,7 @@ static void shell(ssh_session session)
|
||||
|
||||
if (ssh_channel_open_session(channel)) {
|
||||
printf("Error opening channel : %s\n", ssh_get_error(session));
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
chan = channel;
|
||||
@@ -260,6 +270,7 @@ static void shell(ssh_session session)
|
||||
|
||||
if (ssh_channel_request_shell(channel)) {
|
||||
printf("Requesting shell : %s\n", ssh_get_error(session));
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -273,6 +284,7 @@ static void shell(ssh_session session)
|
||||
if (interactive) {
|
||||
do_cleanup(0);
|
||||
}
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
static void batch_shell(ssh_session session)
|
||||
@@ -289,12 +301,18 @@ static void batch_shell(ssh_session session)
|
||||
}
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_channel_open_session(channel);
|
||||
if (ssh_channel_request_exec(channel, buffer)) {
|
||||
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
select_loop(session, channel);
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
static int client(ssh_session session)
|
||||
|
||||
@@ -70,6 +70,8 @@ static void set_default_keys(ssh_bind sshbind,
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY,
|
||||
KEYS_FOLDER "ssh_host_ecdsa_key");
|
||||
}
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
|
||||
KEYS_FOLDER "ssh_host_ed25519_key");
|
||||
}
|
||||
#define DEF_STR_SIZE 1024
|
||||
char authorizedkeys[DEF_STR_SIZE] = {0};
|
||||
|
||||
@@ -26,7 +26,7 @@ install(
|
||||
FILES
|
||||
${libssh_HDRS}
|
||||
DESTINATION
|
||||
${INCLUDE_INSTALL_DIR}/${APPLICATION_NAME}
|
||||
${CMAKE_INSTALL_INCLUDEDIR}/${APPLICATION_NAME}
|
||||
COMPONENT
|
||||
headers
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
bignum ssh_make_string_bn(ssh_string string);
|
||||
ssh_string ssh_make_bignum_string(bignum num);
|
||||
void ssh_print_bignum(const char *which, const bignum num);
|
||||
void ssh_print_bignum(const char *which, const_bignum num);
|
||||
|
||||
|
||||
#endif /* BIGNUM_H_ */
|
||||
|
||||
@@ -48,6 +48,8 @@ int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
|
||||
int ssh_dh_compute_shared_secret(struct dh_ctx *ctx, int local, int remote,
|
||||
bignum *dest);
|
||||
|
||||
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c);
|
||||
|
||||
/* common functions */
|
||||
int ssh_dh_init(void);
|
||||
void ssh_dh_finalize(void);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#define SSH_KNOWNHOSTS_H_
|
||||
|
||||
struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
|
||||
char *ssh_known_hosts_get_algorithms_names(ssh_session session);
|
||||
enum ssh_known_hosts_e
|
||||
ssh_session_get_known_hosts_entry_file(ssh_session session,
|
||||
const char *filename,
|
||||
|
||||
@@ -112,7 +112,11 @@ typedef BN_CTX* bignum_CTX;
|
||||
|
||||
|
||||
/* Returns true if the OpenSSL is operating in FIPS mode */
|
||||
#ifdef HAVE_OPENSSL_FIPS_MODE
|
||||
#define ssh_fips_mode() (FIPS_mode() != 0)
|
||||
#else
|
||||
#define ssh_fips_mode() false
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
|
||||
@@ -78,7 +78,10 @@ int ssh_gcry_rand_range(bignum rnd, bignum max);
|
||||
#define bignum_bin2bn(data,datalen,dest) gcry_mpi_scan(dest,GCRYMPI_FMT_USG,data,datalen,NULL)
|
||||
#define bignum_bn2dec(num) ssh_gcry_bn2dec(num)
|
||||
#define bignum_dec2bn(num, data) ssh_gcry_dec2bn(data, num)
|
||||
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
|
||||
|
||||
#define bignum_bn2hex(num, data) \
|
||||
gcry_mpi_aprint(GCRYMPI_FMT_HEX, data, NULL, (const gcry_mpi_t)num)
|
||||
|
||||
#define bignum_hex2bn(data, num) (gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,0,NULL)==0?1:0)
|
||||
#define bignum_rand(num,bits) 1,gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo, ctx) 1,gcry_mpi_powm(dest,generator,exp,modulo)
|
||||
|
||||
@@ -75,7 +75,7 @@ struct mbedtls_ecdsa_sig {
|
||||
|
||||
bignum ssh_mbedcry_bn_new(void);
|
||||
void ssh_mbedcry_bn_free(bignum num);
|
||||
unsigned char *ssh_mbedcry_bn2num(bignum num, int radix);
|
||||
unsigned char *ssh_mbedcry_bn2num(const_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);
|
||||
int ssh_mbedcry_rand_range(bignum dest, bignum max);
|
||||
|
||||
@@ -78,8 +78,8 @@
|
||||
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 8
|
||||
#define LIBSSH_VERSION_MICRO 90
|
||||
#define LIBSSH_VERSION_MINOR 9
|
||||
#define LIBSSH_VERSION_MICRO 1
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
@@ -441,6 +441,7 @@ enum ssh_scp_request_types {
|
||||
enum ssh_connector_flags_e {
|
||||
/** Only the standard stream of the channel */
|
||||
SSH_CONNECTOR_STDOUT = 1,
|
||||
SSH_CONNECTOR_STDINOUT = 1,
|
||||
/** Only the exception stream of the channel */
|
||||
SSH_CONNECTOR_STDERR = 2,
|
||||
/** Merge both standard and exception streams */
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
char *ssh_get_user_home_dir(void);
|
||||
char *ssh_get_local_username(void);
|
||||
int ssh_file_readaccess_ok(const char *file);
|
||||
int ssh_dir_writeable(const char *path);
|
||||
|
||||
char *ssh_path_expand_tilde(const char *d);
|
||||
char *ssh_path_expand_escape(ssh_session session, const char *s);
|
||||
@@ -83,4 +84,8 @@ int ssh_match_group(const char *group, const char *object);
|
||||
|
||||
void uint64_inc(unsigned char *counter);
|
||||
|
||||
void ssh_log_hexdump(const char *descr, const unsigned char *what, size_t len);
|
||||
|
||||
int ssh_mkdirs(const char *pathname, mode_t mode);
|
||||
|
||||
#endif /* MISC_H_ */
|
||||
|
||||
@@ -30,7 +30,15 @@
|
||||
#endif
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
/* If using OpenSSL implementation, define the signature lenght which would be
|
||||
* defined in libssh/ed25519.h otherwise */
|
||||
#define ED25519_SIG_LEN 64
|
||||
#else
|
||||
#include "libssh/ed25519.h"
|
||||
#endif
|
||||
/* This definition is used for both OpenSSL and internal implementations */
|
||||
#define ED25519_KEY_LEN 32
|
||||
|
||||
#define MAX_PUBKEY_SIZE 0x100000 /* 1M */
|
||||
#define MAX_PRIVKEY_SIZE 0x400000 /* 4M */
|
||||
@@ -61,8 +69,13 @@ struct ssh_key_struct {
|
||||
void *ecdsa;
|
||||
# endif /* HAVE_OPENSSL_EC_H */
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
uint8_t *ed25519_pubkey;
|
||||
uint8_t *ed25519_privkey;
|
||||
#else
|
||||
ed25519_pubkey *ed25519_pubkey;
|
||||
ed25519_privkey *ed25519_privkey;
|
||||
#endif
|
||||
void *cert;
|
||||
enum ssh_keytypes_e cert_type;
|
||||
};
|
||||
@@ -79,7 +92,9 @@ struct ssh_signature_struct {
|
||||
ssh_string rsa_sig;
|
||||
struct mbedtls_ecdsa_sig ecdsa_sig;
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
#ifndef HAVE_OPENSSL_ED25519
|
||||
ed25519_signature *ed25519_sig;
|
||||
#endif
|
||||
ssh_string raw_sig;
|
||||
};
|
||||
|
||||
@@ -118,7 +133,7 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob,
|
||||
int ssh_pki_signature_verify(ssh_session session,
|
||||
ssh_signature sig,
|
||||
const ssh_key key,
|
||||
unsigned char *digest,
|
||||
const unsigned char *digest,
|
||||
size_t dlen);
|
||||
|
||||
/* SSH Public Key Functions */
|
||||
|
||||
@@ -124,11 +124,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
const ssh_string sig_blob,
|
||||
enum ssh_keytypes_e type,
|
||||
enum ssh_digest_e hash_type);
|
||||
int pki_signature_verify(ssh_session session,
|
||||
const ssh_signature sig,
|
||||
const ssh_key key,
|
||||
const unsigned char *input,
|
||||
size_t input_len);
|
||||
|
||||
/* SSH Signing Functions */
|
||||
ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
@@ -148,8 +143,8 @@ int pki_ed25519_key_cmp(const ssh_key k1,
|
||||
enum ssh_keycmp_e what);
|
||||
int pki_ed25519_key_dup(ssh_key new, const ssh_key key);
|
||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
|
||||
ssh_string pki_ed25519_sig_to_blob(ssh_signature sig);
|
||||
int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob);
|
||||
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig);
|
||||
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
|
||||
int pki_privkey_build_ed25519(ssh_key key,
|
||||
ssh_string pubkey,
|
||||
ssh_string privkey);
|
||||
|
||||
@@ -272,8 +272,6 @@ int ssh_auth_reply_success(ssh_session session, int partial);
|
||||
int ssh_send_banner(ssh_session session, int is_server);
|
||||
|
||||
/* connect.c */
|
||||
socket_t ssh_connect_host(ssh_session session, const char *host,const char
|
||||
*bind_addr, int port, long timeout, long usec);
|
||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port);
|
||||
|
||||
|
||||
@@ -201,13 +201,18 @@ struct sftp_statvfs_struct {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Start a new sftp session.
|
||||
* @brief Creates a new sftp session.
|
||||
*
|
||||
* This function creates a new sftp session and allocates a new sftp channel
|
||||
* with the server inside of the provided ssh session. This function call is
|
||||
* usually followed by the sftp_init(), which initializes SFTP protocol itself.
|
||||
*
|
||||
* @param session The ssh session to use.
|
||||
*
|
||||
* @return A new sftp session or NULL on error.
|
||||
*
|
||||
* @see sftp_free()
|
||||
* @see sftp_init()
|
||||
*/
|
||||
LIBSSH_API sftp_session sftp_new(ssh_session session);
|
||||
|
||||
@@ -232,7 +237,10 @@ LIBSSH_API sftp_session sftp_new_channel(ssh_session session, ssh_channel channe
|
||||
LIBSSH_API void sftp_free(sftp_session sftp);
|
||||
|
||||
/**
|
||||
* @brief Initialize the sftp session with the server.
|
||||
* @brief Initialize the sftp protocol with the server.
|
||||
*
|
||||
* This function involves the SFTP protocol initialization (as described
|
||||
* in the SFTP specification), including the version and extensions negotiation.
|
||||
*
|
||||
* @param sftp The sftp session to initialize.
|
||||
*
|
||||
|
||||
@@ -38,7 +38,11 @@ void ssh_tokens_free(struct ssh_tokens_st *tokens);
|
||||
char *ssh_find_matching(const char *available_d,
|
||||
const char *preferred_d);
|
||||
|
||||
|
||||
char *ssh_find_all_matching(const char *available_d,
|
||||
const char *preferred_d);
|
||||
|
||||
char *ssh_remove_duplicates(const char *list);
|
||||
|
||||
char *ssh_append_without_duplicates(const char *list,
|
||||
const char *appended_list);
|
||||
#endif /* TOKEN_H_ */
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/CMakeCache.txt")
|
||||
# In tree build
|
||||
set_and_check(LIBSSH_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include")
|
||||
set_and_check(LIBSSH_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/@LIBSSH_LIBRARY_NAME@")
|
||||
else()
|
||||
set_and_check(LIBSSH_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
set_and_check(LIBSSH_LIBRARIES "@PACKAGE_LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@")
|
||||
endif()
|
||||
|
||||
# For backward compatibility
|
||||
set(LIBSSH_LIBRARY ${LIBSSH_LIBRARIES})
|
||||
|
||||
mark_as_advanced(LIBSSH_LIBRARIES LIBSSH_LIBRARY LIBSSH_INCLUDE_DIR)
|
||||
@@ -1,6 +1,6 @@
|
||||
Name: ${PROJECT_NAME}
|
||||
Description: The SSH Library
|
||||
Version: ${PROJECT_VERSION}
|
||||
Libs: -L${LIB_INSTALL_DIR} -lssh
|
||||
Cflags: -I${INCLUDE_INSTALL_DIR}
|
||||
Libs: -L${CMAKE_INSTALL_FULL_LIBDIR} -lssh
|
||||
Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
4.8.1
|
||||
4.8.2
|
||||
421
src/ABI/libssh-4.8.2.symbols
Normal file
421
src/ABI/libssh-4.8.2.symbols
Normal file
@@ -0,0 +1,421 @@
|
||||
_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_submessage
|
||||
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_free
|
||||
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_parse_config
|
||||
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_forward_unix
|
||||
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_fingerprint_hash
|
||||
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_open_reply_accept_channel
|
||||
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_base64
|
||||
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_hash
|
||||
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_get_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_default
|
||||
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
|
||||
@@ -146,7 +146,6 @@ set(libssh_SRCS
|
||||
pcap.c
|
||||
pki.c
|
||||
pki_container_openssh.c
|
||||
pki_ed25519.c
|
||||
poll.c
|
||||
session.c
|
||||
scp.c
|
||||
@@ -157,14 +156,11 @@ set(libssh_SRCS
|
||||
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
|
||||
config_parser.c
|
||||
token.c
|
||||
pki_ed25519_common.c
|
||||
)
|
||||
|
||||
if (DEFAULT_C_NO_DEPRECATION_FLAGS)
|
||||
@@ -201,6 +197,11 @@ if (WITH_GCRYPT)
|
||||
pki_gcrypt.c
|
||||
ecdh_gcrypt.c
|
||||
dh_key.c
|
||||
pki_ed25519.c
|
||||
external/ed25519.c
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/sc25519.c
|
||||
)
|
||||
elseif (WITH_MBEDTLS)
|
||||
set(libssh_SRCS
|
||||
@@ -211,6 +212,11 @@ elseif (WITH_MBEDTLS)
|
||||
pki_mbedcrypto.c
|
||||
ecdh_mbedcrypto.c
|
||||
dh_key.c
|
||||
pki_ed25519.c
|
||||
external/ed25519.c
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/sc25519.c
|
||||
)
|
||||
else (WITH_GCRYPT)
|
||||
set(libssh_SRCS
|
||||
@@ -221,6 +227,16 @@ else (WITH_GCRYPT)
|
||||
libcrypto.c
|
||||
dh_crypto.c
|
||||
)
|
||||
if (NOT HAVE_OPENSSL_ED25519)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
pki_ed25519.c
|
||||
external/ed25519.c
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/sc25519.c
|
||||
)
|
||||
endif (NOT HAVE_OPENSSL_ED25519)
|
||||
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
|
||||
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
|
||||
endif()
|
||||
@@ -271,10 +287,12 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
if (NOT WITH_NACL)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
external/curve25519_ref.c
|
||||
)
|
||||
if (NOT HAVE_OPENSSL_ED25519)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
external/curve25519_ref.c
|
||||
)
|
||||
endif (NOT HAVE_OPENSSL_ED25519)
|
||||
endif (NOT WITH_NACL)
|
||||
|
||||
include_directories(
|
||||
@@ -319,7 +337,8 @@ target_compile_options(${LIBSSH_SHARED_LIBRARY}
|
||||
${DEFAULT_C_COMPILE_FLAGS}
|
||||
-D_GNU_SOURCE)
|
||||
|
||||
target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
|
||||
target_link_libraries(${LIBSSH_SHARED_LIBRARY}
|
||||
PRIVATE ${LIBSSH_LINK_LIBRARIES})
|
||||
|
||||
if (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
|
||||
if (ABIMAP_FOUND)
|
||||
@@ -354,14 +373,15 @@ if (MINGW)
|
||||
endif ()
|
||||
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
${LIBSSH_SHARED_LIBRARY}
|
||||
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
COMPONENT libraries
|
||||
)
|
||||
install(TARGETS ${LIBSSH_SHARED_LIBRARY}
|
||||
EXPORT libssh-config
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
COMPONENT libraries)
|
||||
|
||||
install(EXPORT libssh-config
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
|
||||
|
||||
if (BUILD_STATIC_LIB)
|
||||
add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS})
|
||||
@@ -370,6 +390,9 @@ if (BUILD_STATIC_LIB)
|
||||
${DEFAULT_C_COMPILE_FLAGS}
|
||||
-D_GNU_SOURCE)
|
||||
|
||||
target_link_libraries(${LIBSSH_STATIC_LIBRARY}
|
||||
PUBLIC ${LIBSSH_LINK_LIBRARIES})
|
||||
|
||||
if (MSVC)
|
||||
set(OUTPUT_SUFFIX static)
|
||||
else (MSVC)
|
||||
@@ -401,7 +424,7 @@ if (BUILD_STATIC_LIB)
|
||||
install(TARGETS
|
||||
${LIBSSH_STATIC_LIBRARY}
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
|
||||
${CMAKE_INSTALL_LIBDIR}/${OUTPUT_SUFFIX}
|
||||
COMPONENT
|
||||
libraries)
|
||||
endif (WITH_STATIC_LIB)
|
||||
|
||||
@@ -69,7 +69,7 @@ static int ssh_userauth_request_service(ssh_session session) {
|
||||
int rc;
|
||||
|
||||
rc = ssh_service_request(session, "ssh-userauth");
|
||||
if (rc != SSH_OK) {
|
||||
if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Failed to request \"ssh-userauth\" service");
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ bignum ssh_make_string_bn(ssh_string string)
|
||||
}
|
||||
|
||||
/* prints the bignum on stderr */
|
||||
void ssh_print_bignum(const char *name, const bignum num)
|
||||
void ssh_print_bignum(const char *name, const_bignum num)
|
||||
{
|
||||
unsigned char *hex = NULL;
|
||||
if (num != NULL) {
|
||||
|
||||
27
src/buffer.c
27
src/buffer.c
@@ -1119,6 +1119,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = SSH_ERROR;
|
||||
switch (*p) {
|
||||
case 'b':
|
||||
o.byte = va_arg(ap, uint8_t *);
|
||||
@@ -1128,27 +1129,32 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
case 'w':
|
||||
o.word = va_arg(ap, uint16_t *);
|
||||
rlen = ssh_buffer_get_data(buffer, o.word, sizeof(uint16_t));
|
||||
*o.word = ntohs(*o.word);
|
||||
rc = rlen==2 ? SSH_OK : SSH_ERROR;
|
||||
if (rlen == 2) {
|
||||
*o.word = ntohs(*o.word);
|
||||
rc = SSH_OK;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
o.dword = va_arg(ap, uint32_t *);
|
||||
rlen = ssh_buffer_get_u32(buffer, o.dword);
|
||||
*o.dword = ntohl(*o.dword);
|
||||
rc = rlen==4 ? SSH_OK : SSH_ERROR;
|
||||
if (rlen == 4) {
|
||||
*o.dword = ntohl(*o.dword);
|
||||
rc = SSH_OK;
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
o.qword = va_arg(ap, uint64_t*);
|
||||
rlen = ssh_buffer_get_u64(buffer, o.qword);
|
||||
*o.qword = ntohll(*o.qword);
|
||||
rc = rlen==8 ? SSH_OK : SSH_ERROR;
|
||||
if (rlen == 8) {
|
||||
*o.qword = ntohll(*o.qword);
|
||||
rc = SSH_OK;
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
o.bignum = va_arg(ap, bignum *);
|
||||
*o.bignum = NULL;
|
||||
tmp_string = ssh_buffer_get_ssh_string(buffer);
|
||||
if (tmp_string == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
*o.bignum = ssh_make_string_bn(tmp_string);
|
||||
@@ -1167,14 +1173,12 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
|
||||
o.cstring = va_arg(ap, char **);
|
||||
*o.cstring = NULL;
|
||||
rc = ssh_buffer_get_u32(buffer, &u32len);
|
||||
if (rc != 4){
|
||||
rc = SSH_ERROR;
|
||||
rlen = ssh_buffer_get_u32(buffer, &u32len);
|
||||
if (rlen != 4){
|
||||
break;
|
||||
}
|
||||
len = ntohl(u32len);
|
||||
if (len > max_len - 1) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1230,7 +1234,6 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
break;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
if (rc != SSH_OK) {
|
||||
break;
|
||||
|
||||
@@ -109,11 +109,11 @@ static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
out_packet->payload,
|
||||
len - sizeof(uint32_t));
|
||||
|
||||
/* ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */
|
||||
/* ssh_log_hexdump("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); */
|
||||
/* ssh_log_hexdump("poly1305 src", (uint8_t *)out_packet, len);
|
||||
ssh_log_hexdump("poly1305 tag", tag, POLY1305_TAGLEN); */
|
||||
}
|
||||
|
||||
static int chacha20_poly1305_aead_decrypt_length(
|
||||
@@ -159,17 +159,17 @@ static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
poly1305_ctx,
|
||||
POLY1305_KEYLEN);
|
||||
#if 0
|
||||
ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx));
|
||||
ssh_log_hexdump("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",
|
||||
ssh_log_hexdump("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);
|
||||
ssh_log_hexdump("poly1305 tag", tag, POLY1305_TAGLEN);
|
||||
ssh_log_hexdump("received tag", mac, POLY1305_TAGLEN);
|
||||
#endif
|
||||
|
||||
cmp = memcmp(tag, mac, POLY1305_TAGLEN);
|
||||
|
||||
147
src/channels.c
147
src/channels.c
@@ -277,74 +277,89 @@ static int ssh_channel_open_termination(void *c){
|
||||
*
|
||||
* @return SSH_OK if successful; SSH_ERROR otherwise.
|
||||
*/
|
||||
static int channel_open(ssh_channel channel, const char *type, int window,
|
||||
int maxpacket, ssh_buffer payload) {
|
||||
ssh_session session = channel->session;
|
||||
int err=SSH_ERROR;
|
||||
int rc;
|
||||
static int
|
||||
channel_open(ssh_channel channel,
|
||||
const char *type,
|
||||
int window,
|
||||
int maxpacket,
|
||||
ssh_buffer payload)
|
||||
{
|
||||
ssh_session session = channel->session;
|
||||
int err = SSH_ERROR;
|
||||
int rc;
|
||||
|
||||
switch(channel->state){
|
||||
case SSH_CHANNEL_STATE_NOT_OPEN:
|
||||
break;
|
||||
case SSH_CHANNEL_STATE_OPENING:
|
||||
goto pending;
|
||||
case SSH_CHANNEL_STATE_OPEN:
|
||||
case SSH_CHANNEL_STATE_CLOSED:
|
||||
case SSH_CHANNEL_STATE_OPEN_DENIED:
|
||||
goto end;
|
||||
default:
|
||||
ssh_set_error(session,SSH_FATAL,"Bad state in channel_open: %d",channel->state);
|
||||
}
|
||||
channel->local_channel = ssh_channel_new_id(session);
|
||||
channel->local_maxpacket = maxpacket;
|
||||
channel->local_window = window;
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Creating a channel %d with %d window and %d max packet",
|
||||
channel->local_channel, window, maxpacket);
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bsddd",
|
||||
SSH2_MSG_CHANNEL_OPEN,
|
||||
type,
|
||||
channel->local_channel,
|
||||
channel->local_window,
|
||||
channel->local_maxpacket);
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error_oom(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (payload != NULL) {
|
||||
if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
|
||||
return err;
|
||||
switch (channel->state) {
|
||||
case SSH_CHANNEL_STATE_NOT_OPEN:
|
||||
break;
|
||||
case SSH_CHANNEL_STATE_OPENING:
|
||||
goto pending;
|
||||
case SSH_CHANNEL_STATE_OPEN:
|
||||
case SSH_CHANNEL_STATE_CLOSED:
|
||||
case SSH_CHANNEL_STATE_OPEN_DENIED:
|
||||
goto end;
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "Bad state in channel_open: %d",
|
||||
channel->state);
|
||||
}
|
||||
|
||||
channel->local_channel = ssh_channel_new_id(session);
|
||||
channel->local_maxpacket = maxpacket;
|
||||
channel->local_window = window;
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Creating a channel %d with %d window and %d max packet",
|
||||
channel->local_channel, window, maxpacket);
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bsddd",
|
||||
SSH2_MSG_CHANNEL_OPEN,
|
||||
type,
|
||||
channel->local_channel,
|
||||
channel->local_window,
|
||||
channel->local_maxpacket);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (payload != NULL) {
|
||||
if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
channel->state = SSH_CHANNEL_STATE_OPENING;
|
||||
if (ssh_packet_send(session) == SSH_ERROR) {
|
||||
return err;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
|
||||
type, channel->local_channel);
|
||||
|
||||
pending:
|
||||
/* wait until channel is opened by server */
|
||||
err = ssh_handle_packets_termination(session,
|
||||
SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_open_termination,
|
||||
channel);
|
||||
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
err = SSH_ERROR;
|
||||
}
|
||||
|
||||
end:
|
||||
/* This needs to pass the SSH_AGAIN from the above,
|
||||
* but needs to catch failed channel states */
|
||||
if (channel->state == SSH_CHANNEL_STATE_OPEN) {
|
||||
err = SSH_OK;
|
||||
} else if (err != SSH_AGAIN) {
|
||||
/* Messages were handled correctly, but he channel state is invalid */
|
||||
err = SSH_ERROR;
|
||||
}
|
||||
}
|
||||
channel->state = SSH_CHANNEL_STATE_OPENING;
|
||||
if (ssh_packet_send(session) == SSH_ERROR) {
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
|
||||
type, channel->local_channel);
|
||||
pending:
|
||||
/* wait until channel is opened by server */
|
||||
err = ssh_handle_packets_termination(session,
|
||||
SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_open_termination,
|
||||
channel);
|
||||
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
err = SSH_ERROR;
|
||||
end:
|
||||
if(channel->state == SSH_CHANNEL_STATE_OPEN)
|
||||
err=SSH_OK;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* return channel with corresponding local id, or NULL if not found */
|
||||
@@ -2513,12 +2528,12 @@ error:
|
||||
*
|
||||
* Example:
|
||||
@code
|
||||
rc = channel_request_exec(channel, "ps aux");
|
||||
rc = ssh_channel_request_exec(channel, "ps aux");
|
||||
if (rc > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
while ((rc = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
29
src/config.c
29
src/config.c
@@ -274,10 +274,8 @@ static int
|
||||
ssh_config_match(char *value, const char *pattern, bool negate)
|
||||
{
|
||||
int ok, result = 0;
|
||||
char *lowervalue;
|
||||
|
||||
lowervalue = (value) ? ssh_lowercase(value) : NULL;
|
||||
ok = match_pattern_list(lowervalue, pattern, strlen(pattern), 0);
|
||||
ok = match_pattern_list(value, pattern, strlen(pattern), 0);
|
||||
if (ok <= 0 && negate == true) {
|
||||
result = 1;
|
||||
} else if (ok > 0 && negate == false) {
|
||||
@@ -286,7 +284,6 @@ ssh_config_match(char *value, const char *pattern, bool negate)
|
||||
SSH_LOG(SSH_LOG_TRACE, "%s '%s' against pattern '%s'%s (ok=%d)",
|
||||
result == 1 ? "Matched" : "Not matched", value, pattern,
|
||||
negate == true ? " (negated)" : "", ok);
|
||||
SAFE_FREE(lowervalue);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -450,6 +447,7 @@ ssh_config_parse_line(ssh_session session,
|
||||
int result = 1;
|
||||
size_t args = 0;
|
||||
enum ssh_config_match_e opt;
|
||||
char *localuser = NULL;
|
||||
|
||||
*parsing = 0;
|
||||
do {
|
||||
@@ -515,8 +513,29 @@ ssh_config_parse_line(ssh_session session,
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case MATCH_ORIGINALHOST:
|
||||
case MATCH_LOCALUSER:
|
||||
/* Here we match only one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"line %d: ERROR - Match user keyword "
|
||||
"requires argument", count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
localuser = ssh_get_local_username();
|
||||
if (localuser == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Can not get local username "
|
||||
"for conditional matching.", count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
result &= ssh_config_match(localuser, p, negate);
|
||||
SAFE_FREE(localuser);
|
||||
args++;
|
||||
break;
|
||||
|
||||
case MATCH_ORIGINALHOST:
|
||||
/* Skip one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
|
||||
537
src/connect.c
537
src/connect.c
@@ -90,131 +90,55 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef gai_strerror
|
||||
char WSAAPI *gai_strerrorA(int code) {
|
||||
static char buf[256];
|
||||
char WSAAPI *gai_strerrorA(int code)
|
||||
{
|
||||
static char buf[256];
|
||||
|
||||
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
|
||||
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
|
||||
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
#endif /* gai_strerror */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static int ssh_connect_socket_close(socket_t s){
|
||||
static int ssh_connect_socket_close(socket_t s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return closesocket(s);
|
||||
return closesocket(s);
|
||||
#else
|
||||
return close(s);
|
||||
return close(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int getai(const char *host, int port, struct addrinfo **ai)
|
||||
{
|
||||
const char *service = NULL;
|
||||
struct addrinfo hints;
|
||||
char s_port[10];
|
||||
|
||||
static int getai(const char *host, int port, struct addrinfo **ai) {
|
||||
const char *service = NULL;
|
||||
struct addrinfo hints;
|
||||
char s_port[10];
|
||||
ZERO_STRUCT(hints);
|
||||
|
||||
ZERO_STRUCT(hints);
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (port == 0) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
} else {
|
||||
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
|
||||
service = s_port;
|
||||
if (port == 0) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
} else {
|
||||
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
|
||||
service = s_port;
|
||||
#ifdef AI_NUMERICSERV
|
||||
hints.ai_flags=AI_NUMERICSERV;
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_is_ipaddr(host)) {
|
||||
/* this is an IP address */
|
||||
SSH_LOG(SSH_LOG_PACKET,"host %s matches an IP address",host);
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
if (ssh_is_ipaddr(host)) {
|
||||
/* this is an IP address */
|
||||
SSH_LOG(SSH_LOG_PACKET, "host %s matches an IP address", host);
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
|
||||
return getaddrinfo(host, service, &hints, ai);
|
||||
}
|
||||
|
||||
static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
||||
int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
|
||||
int timeout_ms;
|
||||
ssh_pollfd_t fds;
|
||||
int rc = 0;
|
||||
int ret;
|
||||
socklen_t len = sizeof(rc);
|
||||
|
||||
/* I know we're losing some precision. But it's not like poll-like family
|
||||
* type of mechanisms are precise up to the microsecond.
|
||||
*/
|
||||
timeout_ms=timeout * 1000 + usec / 1000;
|
||||
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket non-blocking for %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_RARE, "Trying to connect to host: %s:%d with "
|
||||
"timeout %d ms", host, port, timeout_ms);
|
||||
|
||||
/* The return value is checked later */
|
||||
connect(s, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
|
||||
fds.fd=s;
|
||||
fds.revents=0;
|
||||
fds.events=POLLOUT;
|
||||
#ifdef _WIN32
|
||||
fds.events |= POLLWRNORM;
|
||||
#endif
|
||||
rc = ssh_poll(&fds,1,timeout_ms);
|
||||
|
||||
if (rc == 0) {
|
||||
/* timeout */
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Timeout while connecting to %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"poll error: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
rc = -1;
|
||||
|
||||
/* Get connect(2) return code. Zero means no error */
|
||||
ret = getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len);
|
||||
if (ret < 0 || rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Connect to %s:%d failed: %s", host, port, strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* s is connected ? */
|
||||
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout");
|
||||
ret = ssh_socket_set_blocking(s);
|
||||
if (ret < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket as blocking connecting to %s:%d failed: %s",
|
||||
host, port, strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
return getaddrinfo(host, service, &hints, ai);
|
||||
}
|
||||
|
||||
static int set_tcp_nodelay(socket_t socket)
|
||||
@@ -228,99 +152,6 @@ static int set_tcp_nodelay(socket_t socket)
|
||||
sizeof(opt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Connect to an IPv4 or IPv6 host specified by its IP address or
|
||||
* hostname.
|
||||
*
|
||||
* @returns A file descriptor, < 0 on error.
|
||||
*/
|
||||
socket_t ssh_connect_host(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port, long timeout, long usec) {
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *itr;
|
||||
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
freeaddrinfo(ai);
|
||||
close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout || usec) {
|
||||
socket_t ret = ssh_connect_ai_timeout(session, host, port, itr,
|
||||
timeout, usec, s);
|
||||
|
||||
freeaddrinfo(ai);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
} else {
|
||||
/* We are connected */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -331,102 +162,109 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
|
||||
* @warning very ugly !!!
|
||||
*/
|
||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port) {
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *itr;
|
||||
const char *bind_addr, int port)
|
||||
{
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai = NULL;
|
||||
struct addrinfo *itr = NULL;
|
||||
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)",
|
||||
host, gai_strerror(rc));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
s=-1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next) {
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket non-blocking for %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
if (session->opts.nodelay) {
|
||||
/* For winsock, socket options are only effective before connect */
|
||||
rc = set_tcp_nodelay(s);
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai;
|
||||
bind_itr != NULL;
|
||||
bind_itr = bind_itr->ai_next)
|
||||
{
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set TCP_NODELAY on socket: %s", strerror(errno));
|
||||
"Failed to set socket non-blocking for %s:%d",
|
||||
host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
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)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to connect: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to connect: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,11 +273,13 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
* @{
|
||||
*/
|
||||
|
||||
static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
||||
fd_set *set = (fd_set *)userdata;
|
||||
if(revents & POLLIN)
|
||||
FD_SET(fd, set);
|
||||
return 0;
|
||||
static int ssh_select_cb (socket_t fd, int revents, void *userdata)
|
||||
{
|
||||
fd_set *set = (fd_set *)userdata;
|
||||
if (revents & POLLIN) {
|
||||
FD_SET(fd, set);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -473,73 +313,84 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
||||
* @see select(2)
|
||||
*/
|
||||
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
fd_set *readfds, struct timeval *timeout) {
|
||||
fd_set origfds;
|
||||
socket_t fd;
|
||||
size_t i, j;
|
||||
int rc;
|
||||
int base_tm, tm;
|
||||
struct ssh_timestamp ts;
|
||||
ssh_event event = ssh_event_new();
|
||||
int firstround=1;
|
||||
fd_set *readfds, struct timeval *timeout)
|
||||
{
|
||||
fd_set origfds;
|
||||
socket_t fd;
|
||||
size_t i, j;
|
||||
int rc;
|
||||
int base_tm, tm;
|
||||
struct ssh_timestamp ts;
|
||||
ssh_event event = ssh_event_new();
|
||||
int firstround = 1;
|
||||
|
||||
base_tm = tm=timeout->tv_sec * 1000 + timeout->tv_usec/1000;
|
||||
for (i=0 ; channels[i] != NULL; ++i){
|
||||
ssh_event_add_session(event, channels[i]->session);
|
||||
}
|
||||
|
||||
ZERO_STRUCT(origfds);
|
||||
FD_ZERO(&origfds);
|
||||
for (fd = 0; fd < maxfd ; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||
FD_SET(fd, &origfds);
|
||||
}
|
||||
}
|
||||
outchannels[0] = NULL;
|
||||
FD_ZERO(readfds);
|
||||
ssh_timestamp_init(&ts);
|
||||
do {
|
||||
/* Poll every channel */
|
||||
j = 0;
|
||||
for (i = 0; channels[i]; i++) {
|
||||
if(ssh_channel_poll(channels[i], 0) != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
} else if(ssh_channel_poll(channels[i], 1) != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
}
|
||||
base_tm = tm = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
|
||||
for (i = 0 ; channels[i] != NULL; ++i) {
|
||||
ssh_event_add_session(event, channels[i]->session);
|
||||
}
|
||||
outchannels[j] = NULL;
|
||||
if(j != 0)
|
||||
break;
|
||||
/* watch if a user socket was triggered */
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
|
||||
ZERO_STRUCT(origfds);
|
||||
FD_ZERO(&origfds);
|
||||
for (fd = 0; fd < maxfd ; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
goto out;
|
||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||
FD_SET(fd, &origfds);
|
||||
}
|
||||
}
|
||||
outchannels[0] = NULL;
|
||||
FD_ZERO(readfds);
|
||||
ssh_timestamp_init(&ts);
|
||||
do {
|
||||
/* Poll every channel */
|
||||
j = 0;
|
||||
for (i = 0; channels[i]; i++) {
|
||||
rc = ssh_channel_poll(channels[i], 0);
|
||||
if (rc != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
} else {
|
||||
rc = ssh_channel_poll(channels[i], 1);
|
||||
if (rc != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the timeout is elapsed, we should go out */
|
||||
if(!firstround && ssh_timeout_elapsed(&ts, base_tm))
|
||||
goto out;
|
||||
/* since there's nothing, let's fire the polling */
|
||||
rc = ssh_event_dopoll(event,tm);
|
||||
if (rc == SSH_ERROR){
|
||||
goto out;
|
||||
}
|
||||
tm = ssh_timeout_update(&ts, base_tm);
|
||||
firstround=0;
|
||||
} while (1);
|
||||
outchannels[j] = NULL;
|
||||
if (j != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* watch if a user socket was triggered */
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the timeout is elapsed, we should go out */
|
||||
if (!firstround && ssh_timeout_elapsed(&ts, base_tm)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* since there's nothing, let's fire the polling */
|
||||
rc = ssh_event_dopoll(event,tm);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
tm = ssh_timeout_update(&ts, base_tm);
|
||||
firstround = 0;
|
||||
} while (1);
|
||||
out:
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, &origfds)) {
|
||||
ssh_event_remove_fd(event, fd);
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, &origfds)) {
|
||||
ssh_event_remove_fd(event, fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
ssh_event_free(event);
|
||||
return SSH_OK;
|
||||
ssh_event_free(event);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
255
src/curve25519.c
255
src/curve25519.c
@@ -39,6 +39,10 @@
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_X25519
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply);
|
||||
|
||||
static ssh_packet_callback dh_client_callbacks[] = {
|
||||
@@ -52,58 +56,221 @@ static struct ssh_packet_callbacks_struct ssh_curve25519_client_callbacks = {
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
static int ssh_curve25519_init(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
#ifdef HAVE_OPENSSL_X25519
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
|
||||
size_t pkey_len = CURVE25519_PRIVKEY_SIZE;
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen_init(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 keygen: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen(pctx, &pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to generate X25519 keys: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey,
|
||||
session->next_crypto->curve25519_server_pubkey,
|
||||
&pubkey_len);
|
||||
} else {
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey,
|
||||
session->next_crypto->curve25519_client_pubkey,
|
||||
&pubkey_len);
|
||||
}
|
||||
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get X25519 raw public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_get_raw_private_key(pkey,
|
||||
session->next_crypto->curve25519_privkey,
|
||||
&pkey_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get X25519 raw private key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
#else
|
||||
rc = ssh_get_random(session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (rc != 1) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
} else {
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_X25519 */
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief Starts curve25519-sha256@libssh.org / curve25519-sha256 key exchange
|
||||
*/
|
||||
int ssh_client_curve25519_init(ssh_session session){
|
||||
int rc;
|
||||
int ok;
|
||||
int ssh_client_curve25519_init(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
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;
|
||||
}
|
||||
rc = ssh_curve25519_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bdP",
|
||||
SSH2_MSG_KEX_ECDH_INIT,
|
||||
CURVE25519_PUBKEY_SIZE,
|
||||
(size_t)CURVE25519_PUBKEY_SIZE,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bdP",
|
||||
SSH2_MSG_KEX_ECDH_INIT,
|
||||
CURVE25519_PUBKEY_SIZE,
|
||||
(size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_client_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_curve25519_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_curve25519_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ssh_curve25519_build_k(ssh_session session) {
|
||||
ssh_curve25519_pubkey k;
|
||||
static int ssh_curve25519_build_k(ssh_session session)
|
||||
{
|
||||
ssh_curve25519_pubkey k;
|
||||
|
||||
if (session->server)
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
else
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
#ifdef HAVE_OPENSSL_X25519
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL, *pubkey = NULL;
|
||||
size_t shared_key_len;
|
||||
int rc;
|
||||
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE);
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create X25519 EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
pctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_init(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 key derivation: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_client_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
} else {
|
||||
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_server_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
}
|
||||
if (pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create X25519 public key EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_set_peer(pctx, pubkey);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to set peer X25519 public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_free(pubkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive(pctx,
|
||||
k,
|
||||
&shared_key_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to derive X25519 shared secret: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_free(pubkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#else
|
||||
if (session->server) {
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
} else {
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_X25519 */
|
||||
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Session server cookie",
|
||||
ssh_log_hexdump("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
ssh_log_hexdump("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
#endif
|
||||
@@ -222,7 +389,6 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||
ssh_key privkey;
|
||||
ssh_string sig_blob = NULL;
|
||||
int ok;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
@@ -245,19 +411,16 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
}
|
||||
|
||||
memcpy(session->next_crypto->curve25519_client_pubkey,
|
||||
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
|
||||
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
|
||||
ssh_string_free(q_c_string);
|
||||
/* Build server's keypair */
|
||||
|
||||
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (!ok) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
rc = ssh_curve25519_init(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to generate curve25519 keys");
|
||||
goto error;
|
||||
}
|
||||
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
|
||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
|
||||
24
src/dh-gex.c
24
src/dh-gex.c
@@ -107,7 +107,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
|
||||
int blen;
|
||||
bignum pmin1 = NULL, one = NULL;
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
bignum modulus, generator;
|
||||
bignum modulus = NULL, generator = NULL;
|
||||
const_bignum pubkey;
|
||||
(void) type;
|
||||
(void) user;
|
||||
@@ -179,14 +179,18 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
|
||||
bignum_ctx_free(ctx);
|
||||
ctx = NULL;
|
||||
|
||||
/* all checks passed, set parameters */
|
||||
/* all checks passed, set parameters (the BNs are copied in openssl backend) */
|
||||
rc = ssh_dh_set_parameters(session->next_crypto->dh_ctx,
|
||||
modulus, generator);
|
||||
if (rc != SSH_OK) {
|
||||
bignum_safe_free(modulus);
|
||||
bignum_safe_free(generator);
|
||||
goto error;
|
||||
}
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_safe_free(modulus);
|
||||
bignum_safe_free(generator);
|
||||
#endif
|
||||
modulus = NULL;
|
||||
generator = NULL;
|
||||
|
||||
/* compute and send DH public parameter */
|
||||
rc = ssh_dh_keypair_gen_keys(session->next_crypto->dh_ctx,
|
||||
@@ -194,8 +198,13 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR, NULL, &pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bB",
|
||||
SSH2_MSG_KEX_DH_GEX_INIT,
|
||||
@@ -216,6 +225,8 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
error:
|
||||
bignum_safe_free(modulus);
|
||||
bignum_safe_free(generator);
|
||||
bignum_safe_free(one);
|
||||
bignum_safe_free(pmin1);
|
||||
if(!bignum_ctx_invalid(ctx)) {
|
||||
@@ -262,6 +273,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
|
||||
rc = ssh_dh_compute_shared_secret(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR, DH_SERVER_KEYPAIR,
|
||||
&session->next_crypto->shared_secret);
|
||||
ssh_dh_debug_crypto(session->next_crypto);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
||||
goto error;
|
||||
@@ -636,8 +648,8 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request)
|
||||
generator);
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_safe_free(generator);
|
||||
bignum_safe_free(modulus);
|
||||
bignum_safe_free(generator);
|
||||
bignum_safe_free(modulus);
|
||||
#endif
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
|
||||
2
src/dh.c
2
src/dh.c
@@ -373,6 +373,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
|
||||
rc = ssh_dh_compute_shared_secret(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR, DH_SERVER_KEYPAIR,
|
||||
&session->next_crypto->shared_secret);
|
||||
ssh_dh_debug_crypto(session->next_crypto);
|
||||
if (rc == SSH_ERROR){
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
||||
goto error;
|
||||
@@ -462,6 +463,7 @@ int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet)
|
||||
rc = ssh_dh_compute_shared_secret(crypto->dh_ctx,
|
||||
DH_SERVER_KEYPAIR, DH_CLIENT_KEYPAIR,
|
||||
&crypto->shared_secret);
|
||||
ssh_dh_debug_crypto(crypto);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
||||
goto error;
|
||||
|
||||
@@ -41,6 +41,27 @@ struct dh_ctx {
|
||||
DH *keypair[2];
|
||||
};
|
||||
|
||||
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c)
|
||||
{
|
||||
#ifdef DEBUG_CRYPTO
|
||||
const_bignum x = NULL, y = NULL, e = NULL, f = NULL;
|
||||
|
||||
ssh_dh_keypair_get_keys(c->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
|
||||
ssh_dh_keypair_get_keys(c->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
|
||||
ssh_print_bignum("x", x);
|
||||
ssh_print_bignum("y", y);
|
||||
ssh_print_bignum("e", e);
|
||||
ssh_print_bignum("f", f);
|
||||
|
||||
ssh_log_hexdump("Session server cookie", c->server_kex.cookie, 16);
|
||||
ssh_log_hexdump("Session client cookie", c->client_kex.cookie, 16);
|
||||
ssh_print_bignum("k", c->shared_secret);
|
||||
|
||||
#else
|
||||
(void)c; /* UNUSED_PARAM */
|
||||
#endif
|
||||
}
|
||||
|
||||
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
|
||||
const_bignum *priv, const_bignum *pub)
|
||||
{
|
||||
@@ -96,12 +117,14 @@ int ssh_dh_get_parameters(struct dh_ctx *ctx,
|
||||
int ssh_dh_set_parameters(struct dh_ctx *ctx,
|
||||
const bignum modulus, const bignum generator)
|
||||
{
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
if ((ctx == NULL) || (modulus == NULL) || (generator == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
bignum p = NULL;
|
||||
bignum g = NULL;
|
||||
|
||||
|
||||
47
src/dh_key.c
47
src/dh_key.c
@@ -60,6 +60,28 @@ struct dh_ctx {
|
||||
bignum modulus;
|
||||
};
|
||||
|
||||
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c)
|
||||
{
|
||||
#ifdef DEBUG_CRYPTO
|
||||
const_bignum x = NULL, y = NULL, e = NULL, f = NULL;
|
||||
|
||||
ssh_dh_keypair_get_keys(c->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
|
||||
ssh_dh_keypair_get_keys(c->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
|
||||
ssh_print_bignum("p", c->dh_ctx->modulus);
|
||||
ssh_print_bignum("g", c->dh_ctx->generator);
|
||||
ssh_print_bignum("x", x);
|
||||
ssh_print_bignum("y", y);
|
||||
ssh_print_bignum("e", e);
|
||||
ssh_print_bignum("f", f);
|
||||
|
||||
ssh_log_hexdump("Session server cookie", c->server_kex.cookie, 16);
|
||||
ssh_log_hexdump("Session client cookie", c->client_kex.cookie, 16);
|
||||
ssh_print_bignum("k", c->shared_secret);
|
||||
#else
|
||||
(void)c; /* UNUSED_PARAM */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ssh_dh_free_modulus(struct dh_ctx *ctx)
|
||||
{
|
||||
if ((ctx->modulus != ssh_dh_group1) &&
|
||||
@@ -263,30 +285,6 @@ void ssh_dh_cleanup(struct ssh_crypto_struct *crypto)
|
||||
crypto->dh_ctx = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
static void ssh_dh_debug(ssh_session session)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
const_bignum x, y, e, f;
|
||||
ssh_dh_keypair_get_keys(crypto->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
|
||||
ssh_dh_keypair_get_keys(crypto->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
|
||||
ssh_print_bignum("p", crypto->dh_ctx->modulus);
|
||||
ssh_print_bignum("g", crypto->dh_ctx->generator);
|
||||
ssh_print_bignum("x", x);
|
||||
ssh_print_bignum("y", y);
|
||||
ssh_print_bignum("e", e);
|
||||
ssh_print_bignum("f", f);
|
||||
|
||||
ssh_print_hexa("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("k", session->next_crypto->shared_secret);
|
||||
}
|
||||
#else
|
||||
#define ssh_dh_debug(session)
|
||||
#endif
|
||||
|
||||
/** @internal
|
||||
* @brief generates a secret DH parameter of at least DH_SECURITY_BITS
|
||||
* security as well as the corresponding public key.
|
||||
@@ -370,7 +368,6 @@ int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
|
||||
|
||||
done:
|
||||
bignum_ctx_free(ctx);
|
||||
ssh_dh_debug(session);
|
||||
if (rc != 1) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -181,9 +181,9 @@ int ecdh_build_k(ssh_session session) {
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Session server cookie",
|
||||
ssh_log_hexdump("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
ssh_log_hexdump("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
#endif
|
||||
|
||||
@@ -242,9 +242,9 @@ int ecdh_build_k(ssh_session session)
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Session server cookie",
|
||||
ssh_log_hexdump("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
ssh_log_hexdump("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
#endif
|
||||
|
||||
189
src/kex.c
189
src/kex.c
@@ -547,7 +547,7 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
|
||||
int i = 0;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("session cookie", kex->cookie, 16);
|
||||
ssh_log_hexdump("session cookie", kex->cookie, 16);
|
||||
#endif
|
||||
|
||||
for(i = 0; i < SSH_KEX_METHODS; i++) {
|
||||
@@ -561,103 +561,94 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief selects the hostkey mechanisms to be chosen for the key exchange,
|
||||
* as some hostkey mechanisms may be present in known_hosts file and preferred
|
||||
* as some hostkey mechanisms may be present in known_hosts files.
|
||||
*
|
||||
* @returns a cstring containing a comma-separated list of hostkey methods.
|
||||
* NULL if no method matches
|
||||
*/
|
||||
char *ssh_client_select_hostkeys(ssh_session session)
|
||||
{
|
||||
char methods_buffer[128]={0};
|
||||
char tail_buffer[128]={0};
|
||||
const char *wanted = NULL;
|
||||
char *wanted_without_certs = NULL;
|
||||
char *known_hosts_algorithms = NULL;
|
||||
char *known_hosts_ordered = NULL;
|
||||
char *new_hostkeys = NULL;
|
||||
static const char *preferred_hostkeys[] = {
|
||||
"ssh-ed25519",
|
||||
"ecdsa-sha2-nistp521",
|
||||
"ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp256",
|
||||
"rsa-sha2-512",
|
||||
"rsa-sha2-256",
|
||||
"ssh-rsa",
|
||||
#ifdef HAVE_DSA
|
||||
"ssh-dss",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
struct ssh_list *algo_list = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
size_t algo_count;
|
||||
int needcomma = 0;
|
||||
size_t i, len;
|
||||
char *fips_hostkeys = NULL;
|
||||
|
||||
algo_list = ssh_known_hosts_get_algorithms(session);
|
||||
if (algo_list == NULL) {
|
||||
wanted = session->opts.wanted_methods[SSH_HOSTKEYS];
|
||||
if (wanted == NULL) {
|
||||
if (ssh_fips_mode()) {
|
||||
wanted = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
|
||||
} else {
|
||||
wanted = ssh_kex_get_default_methods(SSH_HOSTKEYS);
|
||||
}
|
||||
}
|
||||
|
||||
/* This removes the certificate types, unsupported for now */
|
||||
wanted_without_certs = ssh_find_all_matching(HOSTKEYS, wanted);
|
||||
if (wanted_without_certs == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"List of allowed host key algorithms is empty or contains only "
|
||||
"unsupported algorithms");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
algo_count = ssh_list_count(algo_list);
|
||||
if (algo_count == 0) {
|
||||
ssh_list_free(algo_list);
|
||||
return NULL;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Order of wanted host keys: \"%s\"",
|
||||
wanted_without_certs);
|
||||
|
||||
for (i = 0; preferred_hostkeys[i] != NULL; ++i) {
|
||||
bool found = false;
|
||||
/* This is a signature type: We list also the SHA2 extensions */
|
||||
enum ssh_keytypes_e base_preferred =
|
||||
ssh_key_type_from_signature_name(preferred_hostkeys[i]);
|
||||
|
||||
for (it = ssh_list_get_iterator(algo_list);
|
||||
it != NULL;
|
||||
it = it->next) {
|
||||
const char *algo = ssh_iterator_value(const char *, it);
|
||||
/* This is always key type so we do not have to care for the
|
||||
* SHA2 extension */
|
||||
enum ssh_keytypes_e base_algo = ssh_key_type_from_name(algo);
|
||||
|
||||
if (base_preferred == base_algo) {
|
||||
/* Matching the keys already verified it is a known type */
|
||||
if (needcomma) {
|
||||
strncat(methods_buffer,
|
||||
",",
|
||||
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
|
||||
}
|
||||
strncat(methods_buffer,
|
||||
preferred_hostkeys[i],
|
||||
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
|
||||
needcomma = 1;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
/* Collect the rest of the algorithms in other buffer, that will
|
||||
* follow the preferred buffer. This will signalize all the algorithms
|
||||
* we are willing to accept.
|
||||
*/
|
||||
if (!found) {
|
||||
snprintf(tail_buffer + strlen(tail_buffer),
|
||||
sizeof(tail_buffer) - strlen(tail_buffer),
|
||||
",%s", preferred_hostkeys[i]);
|
||||
}
|
||||
}
|
||||
ssh_list_free(algo_list);
|
||||
|
||||
if (strlen(methods_buffer) == 0) {
|
||||
known_hosts_algorithms = ssh_known_hosts_get_algorithms_names(session);
|
||||
if (known_hosts_algorithms == NULL) {
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"No supported kex method for existing key in known_hosts file");
|
||||
return NULL;
|
||||
"No key found in known_hosts; "
|
||||
"changing host key method to \"%s\"",
|
||||
wanted_without_certs);
|
||||
|
||||
return wanted_without_certs;
|
||||
}
|
||||
|
||||
/* Append the supported list to the preferred.
|
||||
* The length is maximum 128 + 128 + 1, which will not overflow
|
||||
*/
|
||||
len = strlen(methods_buffer) + strlen(tail_buffer) + 1;
|
||||
new_hostkeys = malloc(len);
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Algorithms found in known_hosts files: \"%s\"",
|
||||
known_hosts_algorithms);
|
||||
|
||||
/* Filter and order the keys from known_hosts according to wanted list */
|
||||
known_hosts_ordered = ssh_find_all_matching(known_hosts_algorithms,
|
||||
wanted_without_certs);
|
||||
SAFE_FREE(known_hosts_algorithms);
|
||||
if (known_hosts_ordered == NULL) {
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"No key found in known_hosts is allowed; "
|
||||
"changing host key method to \"%s\"",
|
||||
wanted_without_certs);
|
||||
|
||||
return wanted_without_certs;
|
||||
}
|
||||
|
||||
/* Append the other supported keys after the preferred ones
|
||||
* This function tolerates NULL pointers in parameters */
|
||||
new_hostkeys = ssh_append_without_duplicates(known_hosts_ordered,
|
||||
wanted_without_certs);
|
||||
SAFE_FREE(known_hosts_ordered);
|
||||
SAFE_FREE(wanted_without_certs);
|
||||
if (new_hostkeys == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return NULL;
|
||||
}
|
||||
snprintf(new_hostkeys, len,
|
||||
"%s%s", methods_buffer, tail_buffer);
|
||||
|
||||
if (ssh_fips_mode()) {
|
||||
/* Filter out algorithms not allowed in FIPS mode */
|
||||
fips_hostkeys = ssh_keep_fips_algos(SSH_HOSTKEYS, new_hostkeys);
|
||||
SAFE_FREE(new_hostkeys);
|
||||
if (fips_hostkeys == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"None of the wanted host keys or keys in known_hosts files "
|
||||
"is allowed in FIPS mode.");
|
||||
return NULL;
|
||||
}
|
||||
new_hostkeys = fips_hostkeys;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Changing host key method to \"%s\"",
|
||||
@@ -672,7 +663,7 @@ 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;
|
||||
struct ssh_kex_struct *client = &session->next_crypto->client_kex;
|
||||
const char *wanted;
|
||||
char *kex = NULL;
|
||||
char *kex_tmp = NULL;
|
||||
@@ -687,14 +678,22 @@ int ssh_set_client_kex(ssh_session session)
|
||||
}
|
||||
|
||||
memset(client->methods, 0, KEX_METHODS_SIZE * sizeof(char **));
|
||||
/* first check if we have specific host key methods */
|
||||
if (session->opts.wanted_methods[SSH_HOSTKEYS] == NULL) {
|
||||
/* Only if no override */
|
||||
session->opts.wanted_methods[SSH_HOSTKEYS] =
|
||||
ssh_client_select_hostkeys(session);
|
||||
}
|
||||
|
||||
/* Set the list of allowed algorithms in order of preference, if it hadn't
|
||||
* been set yet. */
|
||||
for (i = 0; i < KEX_METHODS_SIZE; i++) {
|
||||
if (i == SSH_HOSTKEYS) {
|
||||
/* Set the hostkeys in the following order:
|
||||
* - First: keys present in known_hosts files ordered by preference
|
||||
* - Next: other wanted algorithms ordered by preference */
|
||||
client->methods[i] = ssh_client_select_hostkeys(session);
|
||||
if (client->methods[i] == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
wanted = session->opts.wanted_methods[i];
|
||||
if (wanted == NULL) {
|
||||
if (ssh_fips_mode()) {
|
||||
@@ -1120,7 +1119,7 @@ int ssh_make_sessionid(ssh_session session)
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("hash buffer", ssh_buffer_get(buf), ssh_buffer_get_len(buf));
|
||||
ssh_log_hexdump("hash buffer", ssh_buffer_get(buf), ssh_buffer_get_len(buf));
|
||||
#endif
|
||||
|
||||
switch (session->next_crypto->kex_type) {
|
||||
@@ -1196,8 +1195,8 @@ int ssh_make_sessionid(ssh_session session)
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
printf("Session hash: \n");
|
||||
ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
|
||||
ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
|
||||
ssh_log_hexdump("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
|
||||
ssh_log_hexdump("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
|
||||
#endif
|
||||
|
||||
rc = SSH_OK;
|
||||
@@ -1384,15 +1383,15 @@ int ssh_generate_session_keys(ssh_session session)
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Client to Server IV", IV_cli_to_srv, IV_len);
|
||||
ssh_print_hexa("Server to Client IV", IV_srv_to_cli, IV_len);
|
||||
ssh_print_hexa("Client to Server Encryption Key", enckey_cli_to_srv,
|
||||
ssh_log_hexdump("Client to Server IV", IV_cli_to_srv, IV_len);
|
||||
ssh_log_hexdump("Server to Client IV", IV_srv_to_cli, IV_len);
|
||||
ssh_log_hexdump("Client to Server Encryption Key", enckey_cli_to_srv,
|
||||
enckey_cli_to_srv_len);
|
||||
ssh_print_hexa("Server to Client Encryption Key", enckey_srv_to_cli,
|
||||
ssh_log_hexdump("Server to Client Encryption Key", enckey_srv_to_cli,
|
||||
enckey_srv_to_cli_len);
|
||||
ssh_print_hexa("Client to Server Integrity Key", intkey_cli_to_srv,
|
||||
ssh_log_hexdump("Client to Server Integrity Key", intkey_cli_to_srv,
|
||||
intkey_cli_to_srv_len);
|
||||
ssh_print_hexa("Server to Client Integrity Key", intkey_srv_to_cli,
|
||||
ssh_log_hexdump("Server to Client Integrity Key", intkey_srv_to_cli,
|
||||
intkey_srv_to_cli_len);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -405,8 +405,12 @@ int ssh_is_server_known(ssh_session session)
|
||||
|
||||
if ((ret == SSH_SERVER_NOT_KNOWN) &&
|
||||
(session->opts.StrictHostKeyChecking == 0)) {
|
||||
ssh_write_knownhost(session);
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
int rv = ssh_session_update_known_hosts(session);
|
||||
if (rv != SSH_OK) {
|
||||
ret = SSH_SERVER_ERROR;
|
||||
} else {
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_FREE(host);
|
||||
@@ -492,10 +496,12 @@ char * ssh_dump_knownhost(ssh_session session) {
|
||||
* @deprecated Please use ssh_session_update_known_hosts()
|
||||
* @brief This function is deprecated
|
||||
*/
|
||||
int ssh_write_knownhost(ssh_session session) {
|
||||
int ssh_write_knownhost(ssh_session session)
|
||||
{
|
||||
FILE *file;
|
||||
char *buffer;
|
||||
char *buffer = NULL;
|
||||
char *dir;
|
||||
int rc;
|
||||
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
@@ -504,33 +510,45 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
errno = 0;
|
||||
file = fopen(session->opts.knownhosts, "a");
|
||||
if (file == NULL) {
|
||||
if (errno == ENOENT) {
|
||||
dir = ssh_dirname(session->opts.knownhosts);
|
||||
if (dir == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (!ssh_file_readaccess_ok(dir)) {
|
||||
if (ssh_mkdir(dir, 0700) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory.", dir);
|
||||
rc = ssh_mkdirs(dir, 0700);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory: %s",
|
||||
dir, strerror(errno));
|
||||
SAFE_FREE(dir);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
errno = 0;
|
||||
file = fopen(session->opts.knownhosts, "a");
|
||||
if (file == 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;
|
||||
}
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Couldn't open known_hosts file %s for appending: %s",
|
||||
session->opts.knownhosts, strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
file = fopen(session->opts.knownhosts, "a");
|
||||
if (file == 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;
|
||||
}
|
||||
|
||||
buffer = ssh_dump_knownhost(session);
|
||||
if (buffer == NULL) {
|
||||
rc = ssh_session_export_known_hosts_entry(session, &buffer);
|
||||
if (rc != SSH_OK) {
|
||||
fclose(file);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
246
src/knownhosts.c
246
src/knownhosts.c
@@ -42,6 +42,7 @@
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/knownhosts.h"
|
||||
#include "libssh/token.h"
|
||||
|
||||
/**
|
||||
* @addtogroup libssh_session
|
||||
@@ -306,7 +307,7 @@ static char *ssh_session_get_host_port(ssh_session session)
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Can't verify server inn known hosts if the host we "
|
||||
"Can't verify server in known hosts if the host we "
|
||||
"should connect to has not been set");
|
||||
|
||||
return NULL;
|
||||
@@ -451,6 +452,146 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Returns a static string containing a list of the signature types the
|
||||
* given key type can generate.
|
||||
*
|
||||
* @returns A static cstring containing the signature types the key is able to
|
||||
* generate separated by commas; NULL in case of error
|
||||
*/
|
||||
static const char *ssh_known_host_sigs_from_hostkey_type(enum ssh_keytypes_e type)
|
||||
{
|
||||
switch (type) {
|
||||
case SSH_KEYTYPE_RSA:
|
||||
return "rsa-sha2-512,rsa-sha2-256,ssh-rsa";
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
return "ssh-ed25519";
|
||||
#ifdef HAVE_DSA
|
||||
case SSH_KEYTYPE_DSS:
|
||||
return "ssh-dss";
|
||||
#endif
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
return "ecdsa-sha2-nistp256";
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
return "ecdsa-sha2-nistp384";
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
return "ecdsa-sha2-nistp521";
|
||||
#endif
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_WARN, "The given type %d is not a base private key type "
|
||||
"or is unsupported", type);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Get the host keys algorithms identifiers from the known_hosts files
|
||||
*
|
||||
* This expands the signatures types that can be generated from the keys types
|
||||
* present in the known_hosts files
|
||||
*
|
||||
* @param[in] session The ssh session to use.
|
||||
*
|
||||
* @return A newly allocated cstring containing a list of signature algorithms
|
||||
* that can be generated by the host using the keys listed in the known_hosts
|
||||
* files, NULL on error.
|
||||
*/
|
||||
char *ssh_known_hosts_get_algorithms_names(ssh_session session)
|
||||
{
|
||||
char methods_buffer[256 + 1] = {0};
|
||||
struct ssh_list *entry_list = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
char *host_port = NULL;
|
||||
size_t count;
|
||||
bool needcomma = false;
|
||||
char *names;
|
||||
|
||||
int rc;
|
||||
|
||||
if (session->opts.knownhosts == NULL ||
|
||||
session->opts.global_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;
|
||||
}
|
||||
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.knownhosts,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.global_knownhosts,
|
||||
&entry_list);
|
||||
SAFE_FREE(host_port);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (entry_list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = ssh_list_count(entry_list);
|
||||
if (count == 0) {
|
||||
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;
|
||||
const char *algo = NULL;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
algo = ssh_known_host_sigs_from_hostkey_type(entry->publickey->type);
|
||||
if (algo == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (needcomma) {
|
||||
strncat(methods_buffer,
|
||||
",",
|
||||
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
|
||||
}
|
||||
|
||||
strncat(methods_buffer,
|
||||
algo,
|
||||
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
|
||||
needcomma = true;
|
||||
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
ssh_list_remove(entry_list, it);
|
||||
}
|
||||
|
||||
ssh_list_free(entry_list);
|
||||
|
||||
names = ssh_remove_duplicates(methods_buffer);
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse a line from a known_hosts entry into a structure
|
||||
*
|
||||
@@ -638,14 +779,15 @@ 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;
|
||||
bool ok;
|
||||
bool global_known_hosts_found = false;
|
||||
bool known_hosts_found = false;
|
||||
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");
|
||||
"Cannot find a known_hosts file");
|
||||
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
}
|
||||
@@ -653,50 +795,67 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
||||
|
||||
if (session->opts.knownhosts == NULL &&
|
||||
session->opts.global_knownhosts == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"No path set for a known_hosts file");
|
||||
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (session->opts.knownhosts != NULL) {
|
||||
ok = ssh_file_readaccess_ok(session->opts.knownhosts);
|
||||
if (!ok) {
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
known_hosts_found = ssh_file_readaccess_ok(session->opts.knownhosts);
|
||||
if (!known_hosts_found) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
|
||||
session->opts.knownhosts);
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.global_knownhosts != NULL) {
|
||||
ok = ssh_file_readaccess_ok(session->opts.global_knownhosts);
|
||||
if (!ok) {
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
global_known_hosts_found =
|
||||
ssh_file_readaccess_ok(session->opts.global_knownhosts);
|
||||
if (!global_known_hosts_found) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
|
||||
session->opts.global_knownhosts);
|
||||
}
|
||||
}
|
||||
|
||||
if ((!known_hosts_found) && (!global_known_hosts_found)) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Cannot 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;
|
||||
}
|
||||
|
||||
if (session->opts.knownhosts != NULL) {
|
||||
if (known_hosts_found) {
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.knownhosts,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.global_knownhosts != NULL) {
|
||||
if (global_known_hosts_found) {
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.global_knownhosts,
|
||||
&entry_list);
|
||||
SAFE_FREE(host_port);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_FREE(host_port);
|
||||
|
||||
if (ssh_list_count(entry_list) == 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
@@ -820,34 +979,41 @@ int ssh_session_update_known_hosts(ssh_session session)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory.", dir);
|
||||
SAFE_FREE(dir);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
errno = 0;
|
||||
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;
|
||||
if (errno == ENOENT) {
|
||||
dir = ssh_dirname(session->opts.knownhosts);
|
||||
if (dir == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_mkdirs(dir, 0700);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory: %s",
|
||||
dir, strerror(errno));
|
||||
SAFE_FREE(dir);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
errno = 0;
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
|
||||
@@ -686,8 +686,12 @@ static int aes_ctr_set_key(struct ssh_cipher_struct *cipher, void *key,
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void aes_ctr_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len) {
|
||||
static void
|
||||
aes_ctr_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
unsigned char tmp_buffer[AES_BLOCK_SIZE];
|
||||
unsigned int num=0;
|
||||
/* Some things are special with ctr128 :
|
||||
|
||||
@@ -45,7 +45,7 @@ void ssh_mbedcry_bn_free(bignum bn)
|
||||
SAFE_FREE(bn);
|
||||
}
|
||||
|
||||
unsigned char *ssh_mbedcry_bn2num(bignum num, int radix)
|
||||
unsigned char *ssh_mbedcry_bn2num(const_bignum num, int radix)
|
||||
{
|
||||
char *buf = NULL;
|
||||
size_t olen;
|
||||
|
||||
@@ -1491,12 +1491,18 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
msg->type = SSH_REQUEST_GLOBAL;
|
||||
|
||||
if (strcmp(request, "tcpip-forward") == 0) {
|
||||
|
||||
/* According to RFC4254, the client SHOULD reject this message */
|
||||
if (session->client) {
|
||||
goto reply_with_failure;
|
||||
}
|
||||
|
||||
r = ssh_buffer_unpack(packet, "sd",
|
||||
&msg->global_request.bind_address,
|
||||
&msg->global_request.bind_port
|
||||
);
|
||||
if (r != SSH_OK){
|
||||
goto error;
|
||||
goto reply_with_failure;
|
||||
}
|
||||
msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
|
||||
msg->global_request.want_reply = want_reply;
|
||||
@@ -1516,11 +1522,17 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
return rc;
|
||||
}
|
||||
} else if (strcmp(request, "cancel-tcpip-forward") == 0) {
|
||||
|
||||
/* According to RFC4254, the client SHOULD reject this message */
|
||||
if (session->client) {
|
||||
goto reply_with_failure;
|
||||
}
|
||||
|
||||
r = ssh_buffer_unpack(packet, "sd",
|
||||
&msg->global_request.bind_address,
|
||||
&msg->global_request.bind_port);
|
||||
if (r != SSH_OK){
|
||||
goto error;
|
||||
goto reply_with_failure;
|
||||
}
|
||||
msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
|
||||
msg->global_request.want_reply = want_reply;
|
||||
@@ -1546,18 +1558,41 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
ssh_message_global_request_reply_success(msg, 0);
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply);
|
||||
rc = SSH_PACKET_NOT_USED;
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s, "
|
||||
"want_reply = %d", request, want_reply);
|
||||
goto reply_with_failure;
|
||||
}
|
||||
|
||||
SAFE_FREE(msg);
|
||||
SAFE_FREE(request);
|
||||
return rc;
|
||||
|
||||
reply_with_failure:
|
||||
/* Only report the failure if requested */
|
||||
if (want_reply) {
|
||||
r = ssh_buffer_add_u8(session->out_buffer,
|
||||
SSH2_MSG_REQUEST_FAILURE);
|
||||
if (r < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = ssh_packet_send(session);
|
||||
if (r != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"The requester doesn't want to know the request failed!");
|
||||
}
|
||||
|
||||
/* Consume the message to avoid sending UNIMPLEMENTED later */
|
||||
rc = SSH_PACKET_USED;
|
||||
error:
|
||||
SAFE_FREE(msg);
|
||||
SAFE_FREE(request);
|
||||
SSH_LOG(SSH_LOG_WARNING, "Invalid SSH_MSG_GLOBAL_REQUEST packet");
|
||||
return SSH_PACKET_NOT_USED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
317
src/misc.c
317
src/misc.c
@@ -130,6 +130,31 @@ int ssh_file_readaccess_ok(const char *file) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the given path is an existing directory and that is
|
||||
* accessible for writing.
|
||||
*
|
||||
* @param[in] path Path to the directory to be checked
|
||||
*
|
||||
* @return Return 1 if the directory exists and is accessible; 0 otherwise
|
||||
* */
|
||||
int ssh_dir_writeable(const char *path)
|
||||
{
|
||||
struct _stat buffer;
|
||||
int rc;
|
||||
|
||||
rc = _stat(path, &buffer);
|
||||
if (rc < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((buffer.st_mode & _S_IFDIR) && (buffer.st_mode & _S_IWRITE)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SSH_USEC_IN_SEC 1000000LL
|
||||
#define SSH_SECONDS_SINCE_1601 11644473600LL
|
||||
|
||||
@@ -247,6 +272,31 @@ int ssh_file_readaccess_ok(const char *file)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the given path is an existing directory and that is
|
||||
* accessible for writing.
|
||||
*
|
||||
* @param[in] path Path to the directory to be checked
|
||||
*
|
||||
* @return Return 1 if the directory exists and is accessible; 0 otherwise
|
||||
* */
|
||||
int ssh_dir_writeable(const char *path)
|
||||
{
|
||||
struct stat buffer;
|
||||
int rc;
|
||||
|
||||
rc = stat(path, &buffer);
|
||||
if (rc < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (S_ISDIR(buffer.st_mode) && (buffer.st_mode & S_IWRITE)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *ssh_get_local_username(void)
|
||||
{
|
||||
struct passwd pwd;
|
||||
@@ -389,6 +439,193 @@ void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
|
||||
free(hexa);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Log the content of a buffer in hexadecimal format, similar to the
|
||||
* output of 'hexdump -C' command.
|
||||
*
|
||||
* The first logged line is the given description followed by the length.
|
||||
* Then the content of the buffer is logged 16 bytes per line in the following
|
||||
* format:
|
||||
*
|
||||
* (offset) (first 8 bytes) (last 8 bytes) (the 16 bytes as ASCII char values)
|
||||
*
|
||||
* The output for a 16 bytes array containing values from 0x00 to 0x0f would be:
|
||||
*
|
||||
* "Example (16 bytes):"
|
||||
* " 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................"
|
||||
*
|
||||
* The value for each byte as corresponding ASCII character is printed at the
|
||||
* end if the value is printable. Otherwise it is replace with '.'.
|
||||
*
|
||||
* @param[in] descr A description for the content to be logged
|
||||
* @param[in] what The buffer to be logged
|
||||
* @param[in] len The length of the buffer given in what
|
||||
*
|
||||
* @note If a too long description is provided (which would result in a first
|
||||
* line longer than 80 bytes), the function will fail.
|
||||
*/
|
||||
void ssh_log_hexdump(const char *descr, const unsigned char *what, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
char ascii[17];
|
||||
const unsigned char *pc = NULL;
|
||||
size_t count = 0;
|
||||
ssize_t printed = 0;
|
||||
|
||||
/* The required buffer size is calculated from:
|
||||
*
|
||||
* 2 bytes for spaces at the beginning
|
||||
* 8 bytes for the offset
|
||||
* 2 bytes for spaces
|
||||
* 24 bytes to print the first 8 bytes + spaces
|
||||
* 1 byte for an extra space
|
||||
* 24 bytes to print next 8 bytes + spaces
|
||||
* 2 bytes for extra spaces
|
||||
* 16 bytes for the content as ASCII characters at the end
|
||||
* 1 byte for the ending '\0'
|
||||
*
|
||||
* Resulting in 80 bytes.
|
||||
*
|
||||
* Except for the first line (description + size), all lines have fixed
|
||||
* length. If a too long description is used, the function will fail.
|
||||
* */
|
||||
char buffer[80];
|
||||
|
||||
/* Print description */
|
||||
if (descr != NULL) {
|
||||
printed = snprintf(buffer, sizeof(buffer), "%s ", descr);
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
count += printed;
|
||||
} else {
|
||||
printed = snprintf(buffer, sizeof(buffer), "(NULL description) ");
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
count += printed;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count,
|
||||
"(zero length):");
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
|
||||
return;
|
||||
} else {
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count,
|
||||
"(%zu bytes):", len);
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
count += printed;
|
||||
}
|
||||
|
||||
if (what == NULL) {
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count,
|
||||
"(NULL)");
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
|
||||
|
||||
/* Reset state */
|
||||
count = 0;
|
||||
pc = what;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
/* Add one space after printing 8 bytes */
|
||||
if ((i % 8) == 0) {
|
||||
if (i != 0) {
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count, " ");
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
count += printed;
|
||||
}
|
||||
}
|
||||
|
||||
/* Log previous line and reset state for new line */
|
||||
if ((i % 16) == 0) {
|
||||
if (i != 0) {
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count,
|
||||
" %s", ascii);
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/* Start a new line with the offset */
|
||||
printed = snprintf(buffer, sizeof(buffer),
|
||||
" %08zx ", i);
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
count += printed;
|
||||
}
|
||||
|
||||
/* Print the current byte hexadecimal representation */
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count,
|
||||
" %02x", pc[i]);
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
count += printed;
|
||||
|
||||
/* If printable, store the ASCII character */
|
||||
if (isprint(pc[i])) {
|
||||
ascii[i % 16] = pc[i];
|
||||
} else {
|
||||
ascii[i % 16] = '.';
|
||||
}
|
||||
ascii[(i % 16) + 1] = '\0';
|
||||
}
|
||||
|
||||
/* Add padding if not exactly 16 characters */
|
||||
while ((i % 16) != 0) {
|
||||
/* Add one space after printing 8 bytes */
|
||||
if ((i % 8) == 0) {
|
||||
if (i != 0) {
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count, " ");
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
count += printed;
|
||||
}
|
||||
}
|
||||
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count, " ");
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
count += printed;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Print the last printable part */
|
||||
printed = snprintf(buffer + count, sizeof(buffer) - count,
|
||||
" %s", ascii);
|
||||
if (printed < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
SSH_LOG(SSH_LOG_WARN, "Could not print to buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if libssh is the required version or get the version
|
||||
* string.
|
||||
@@ -713,16 +950,81 @@ char *ssh_basename (const char *path) {
|
||||
*
|
||||
* @return 0 on success, < 0 on error with errno set.
|
||||
*/
|
||||
int ssh_mkdir(const char *pathname, mode_t mode) {
|
||||
int r;
|
||||
|
||||
int ssh_mkdir(const char *pathname, mode_t mode)
|
||||
{
|
||||
int r;
|
||||
#ifdef _WIN32
|
||||
r = _mkdir(pathname);
|
||||
r = _mkdir(pathname);
|
||||
#else
|
||||
r = mkdir(pathname, mode);
|
||||
r = mkdir(pathname, mode);
|
||||
#endif
|
||||
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attempts to create a directory with the given pathname. The missing
|
||||
* directories in the given pathname are created recursively.
|
||||
*
|
||||
* @param[in] pathname The path name to create the directory.
|
||||
*
|
||||
* @param[in] mode The permissions to use.
|
||||
*
|
||||
* @return 0 on success, < 0 on error with errno set.
|
||||
*
|
||||
* @note mode is ignored on Windows systems.
|
||||
*/
|
||||
int ssh_mkdirs(const char *pathname, mode_t mode)
|
||||
{
|
||||
int rc = 0;
|
||||
char *parent = NULL;
|
||||
|
||||
if (pathname == NULL ||
|
||||
pathname[0] == '\0' ||
|
||||
!strcmp(pathname, "/") ||
|
||||
!strcmp(pathname, "."))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
rc = _mkdir(pathname);
|
||||
#else
|
||||
rc = mkdir(pathname, mode);
|
||||
#endif
|
||||
|
||||
if (rc < 0) {
|
||||
/* If a directory was missing, try to create the parent */
|
||||
if (errno == ENOENT) {
|
||||
parent = ssh_dirname(pathname);
|
||||
if (parent == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ssh_mkdirs(parent, mode);
|
||||
if (rc < 0) {
|
||||
/* We could not create the parent */
|
||||
SAFE_FREE(parent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SAFE_FREE(parent);
|
||||
|
||||
/* Try again */
|
||||
errno = 0;
|
||||
#ifdef _WIN32
|
||||
rc = _mkdir(pathname);
|
||||
#else
|
||||
rc = mkdir(pathname, mode);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -825,6 +1127,7 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
|
||||
|
||||
for (i = 0; *p != '\0'; p++) {
|
||||
if (*p != '%') {
|
||||
escape:
|
||||
buf[i] = *p;
|
||||
i++;
|
||||
if (i >= MAX_BUF_SIZE) {
|
||||
@@ -841,6 +1144,8 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
case '%':
|
||||
goto escape;
|
||||
case 'd':
|
||||
x = strdup(session->opts.sshdir);
|
||||
break;
|
||||
|
||||
@@ -1472,6 +1472,13 @@ int ssh_options_apply(ssh_session session) {
|
||||
it != NULL;
|
||||
it = it->next) {
|
||||
char *id = (char *) it->data;
|
||||
if (strncmp(id, "pkcs11:", 6) == 0) {
|
||||
/* PKCS#11 URIs are using percent-encoding so we can not mix
|
||||
* it with ssh expansion of ssh escape characters.
|
||||
* Skip these identities now, before we will have PKCS#11 support
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
tmp = ssh_path_expand_escape(session, id);
|
||||
if (tmp == NULL) {
|
||||
return -1;
|
||||
|
||||
79
src/packet.c
79
src/packet.c
@@ -1438,37 +1438,54 @@ void ssh_packet_set_default_callbacks(ssh_session session){
|
||||
* @brief dispatch the call of packet handlers callbacks for a received packet
|
||||
* @param type type of packet
|
||||
*/
|
||||
void ssh_packet_process(ssh_session session, uint8_t type){
|
||||
struct ssh_iterator *i;
|
||||
int r=SSH_PACKET_NOT_USED;
|
||||
ssh_packet_callbacks cb;
|
||||
void ssh_packet_process(ssh_session session, uint8_t type)
|
||||
{
|
||||
struct ssh_iterator *i = NULL;
|
||||
int rc = SSH_PACKET_NOT_USED;
|
||||
ssh_packet_callbacks cb;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d",type);
|
||||
if(session->packet_callbacks == NULL){
|
||||
SSH_LOG(SSH_LOG_RARE,"Packet callback is not initialized !");
|
||||
SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d", type);
|
||||
if (session->packet_callbacks == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Packet callback is not initialized !");
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
i=ssh_list_get_iterator(session->packet_callbacks);
|
||||
while(i != NULL){
|
||||
cb=ssh_iterator_value(ssh_packet_callbacks,i);
|
||||
i=i->next;
|
||||
if(!cb)
|
||||
continue;
|
||||
if(cb->start > type)
|
||||
continue;
|
||||
if(cb->start + cb->n_callbacks <= type)
|
||||
continue;
|
||||
if(cb->callbacks[type - cb->start]==NULL)
|
||||
continue;
|
||||
r=cb->callbacks[type - cb->start](session,type,session->in_buffer,cb->user);
|
||||
if(r==SSH_PACKET_USED)
|
||||
break;
|
||||
}
|
||||
if(r==SSH_PACKET_NOT_USED){
|
||||
SSH_LOG(SSH_LOG_RARE,"Couldn't do anything with packet type %d",type);
|
||||
ssh_packet_send_unimplemented(session, session->recv_seq-1);
|
||||
}
|
||||
i = ssh_list_get_iterator(session->packet_callbacks);
|
||||
while (i != NULL) {
|
||||
cb = ssh_iterator_value(ssh_packet_callbacks, i);
|
||||
i = i->next;
|
||||
|
||||
if (!cb) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cb->start > type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cb->start + cb->n_callbacks <= type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cb->callbacks[type - cb->start] == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = cb->callbacks[type - cb->start](session, type, session->in_buffer,
|
||||
cb->user);
|
||||
if (rc == SSH_PACKET_USED) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == SSH_PACKET_NOT_USED) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Couldn't do anything with packet type %d", type);
|
||||
rc = ssh_packet_send_unimplemented(session, session->recv_seq - 1);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Failed to send unimplemented: %s",
|
||||
ssh_get_error(session));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -1929,6 +1946,8 @@ ssh_packet_set_newkeys(ssh_session session,
|
||||
session->next_crypto->decryptkey,
|
||||
session->next_crypto->decryptIV);
|
||||
if (rc < 0) {
|
||||
/* On error, make sure it is not used */
|
||||
session->next_crypto->used = 0;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -1937,6 +1956,8 @@ ssh_packet_set_newkeys(ssh_session session,
|
||||
session->next_crypto->encryptkey,
|
||||
session->next_crypto->encryptIV);
|
||||
if (rc < 0) {
|
||||
/* On error, make sure it is not used */
|
||||
session->next_crypto->used = 0;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -196,11 +196,11 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len)
|
||||
hmac_final(ctx, crypto->hmacbuf, &finallen);
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("mac: ",data,hmac_digest_len(type));
|
||||
ssh_log_hexdump("mac: ", data, len);
|
||||
if (finallen != hmac_digest_len(type)) {
|
||||
printf("Final len is %d\n",finallen);
|
||||
printf("Final len is %d\n", finallen);
|
||||
}
|
||||
ssh_print_hexa("Packet hmac", crypto->hmacbuf, hmac_digest_len(type));
|
||||
ssh_log_hexdump("Packet hmac", crypto->hmacbuf, hmac_digest_len(type));
|
||||
#endif
|
||||
}
|
||||
explicit_bzero(out, len);
|
||||
@@ -264,9 +264,9 @@ int ssh_packet_hmac_verify(ssh_session session,
|
||||
hmac_final(ctx, hmacbuf, &hmaclen);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("received mac",mac,hmaclen);
|
||||
ssh_print_hexa("Computed mac",hmacbuf,hmaclen);
|
||||
ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(uint32_t));
|
||||
ssh_log_hexdump("received mac",mac,hmaclen);
|
||||
ssh_log_hexdump("Computed mac",hmacbuf,hmaclen);
|
||||
ssh_log_hexdump("seq",(unsigned char *)&seq,sizeof(uint32_t));
|
||||
#endif
|
||||
if (secure_memcmp(mac, hmacbuf, hmaclen) == 0) {
|
||||
return 0;
|
||||
|
||||
108
src/pki.c
108
src/pki.c
@@ -64,16 +64,22 @@
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/agent.h"
|
||||
|
||||
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey) {
|
||||
if (strncmp(privkey, DSA_HEADER_BEGIN, strlen(DSA_HEADER_BEGIN)) == 0) {
|
||||
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey)
|
||||
{
|
||||
char *start = NULL;
|
||||
|
||||
start = strstr(privkey, DSA_HEADER_BEGIN);
|
||||
if (start != NULL) {
|
||||
return SSH_KEYTYPE_DSS;
|
||||
}
|
||||
|
||||
if (strncmp(privkey, RSA_HEADER_BEGIN, strlen(RSA_HEADER_BEGIN)) == 0) {
|
||||
start = strstr(privkey, RSA_HEADER_BEGIN);
|
||||
if (start != NULL) {
|
||||
return SSH_KEYTYPE_RSA;
|
||||
}
|
||||
|
||||
if (strncmp(privkey, ECDSA_HEADER_BEGIN, strlen(ECDSA_HEADER_BEGIN)) == 0) {
|
||||
start = strstr(privkey, ECDSA_HEADER_BEGIN);
|
||||
if (start != 0) {
|
||||
/* We don't know what the curve is at this point, so we don't actually
|
||||
* know the type. We figure out the actual curve and fix things up in
|
||||
* pki_private_key_from_base64 */
|
||||
@@ -156,7 +162,14 @@ void ssh_key_clean (ssh_key key){
|
||||
}
|
||||
#endif
|
||||
if (key->ed25519_privkey != NULL){
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
/* In OpenSSL implementation the private key is only the private
|
||||
* original seed. In the internal implementation the private key is the
|
||||
* concatenation of the original private seed with the public key.*/
|
||||
explicit_bzero(key->ed25519_privkey, ED25519_KEY_LEN);
|
||||
#else
|
||||
explicit_bzero(key->ed25519_privkey, sizeof(ed25519_privkey));
|
||||
#endif
|
||||
SAFE_FREE(key->ed25519_privkey);
|
||||
}
|
||||
SAFE_FREE(key->ed25519_pubkey);
|
||||
@@ -382,6 +395,19 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
||||
case SSH_KEYTYPE_DSS:
|
||||
return SSH_DIGEST_SHA1;
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
/* If we are talking to an old OpenSSH version which does not support
|
||||
* SHA2 in certificates */
|
||||
if ((session->openssh > 0) &&
|
||||
(session->openssh < SSH_VERSION_INT(7, 2, 0)))
|
||||
{
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"We are talking to an old OpenSSH (%x); "
|
||||
"returning SSH_DIGEST_SHA1",
|
||||
session->openssh);
|
||||
|
||||
return SSH_DIGEST_SHA1;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
case SSH_KEYTYPE_RSA:
|
||||
if (ssh_key_algorithm_allowed(session, "rsa-sha2-512") &&
|
||||
(session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
|
||||
@@ -435,6 +461,21 @@ ssh_key_get_signature_algorithm(ssh_session session,
|
||||
{
|
||||
enum ssh_digest_e hash_type;
|
||||
|
||||
if (type == SSH_KEYTYPE_RSA_CERT01) {
|
||||
/* If we are talking to an old OpenSSH version which does not support
|
||||
* rsa-sha2-{256,512}-cert-v01@openssh.com */
|
||||
if ((session->openssh > 0) &&
|
||||
(session->openssh < SSH_VERSION_INT(7, 8, 0)))
|
||||
{
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"We are talking to an old OpenSSH (%x); "
|
||||
"using old cert format",
|
||||
session->openssh);
|
||||
|
||||
return "ssh-rsa-cert-v01@openssh.com";
|
||||
}
|
||||
}
|
||||
|
||||
hash_type = ssh_key_type_to_hash(session, type);
|
||||
|
||||
return ssh_key_signature_to_char(type, hash_type);
|
||||
@@ -645,7 +686,10 @@ void ssh_signature_free(ssh_signature sig)
|
||||
#endif
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
#ifndef HAVE_OPENSSL_ED25519
|
||||
/* When using OpenSSL, the signature is stored in sig->raw_sig */
|
||||
SAFE_FREE(sig->ed25519_sig);
|
||||
#endif
|
||||
break;
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
@@ -690,7 +734,7 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
|
||||
ssh_key *pkey)
|
||||
{
|
||||
ssh_key key;
|
||||
int cmp;
|
||||
char *openssh_header = NULL;
|
||||
|
||||
if (b64_key == NULL || pkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
@@ -705,9 +749,9 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
|
||||
passphrase ? "true" : "false");
|
||||
|
||||
/* Test for OpenSSH key format first */
|
||||
cmp = strncmp(b64_key, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN));
|
||||
if (cmp == 0) {
|
||||
key = ssh_pki_openssh_privkey_import(b64_key,
|
||||
openssh_header = strstr(b64_key, OPENSSH_HEADER_BEGIN);
|
||||
if (openssh_header != NULL) {
|
||||
key = ssh_pki_openssh_privkey_import(openssh_header,
|
||||
passphrase,
|
||||
auth_fn,
|
||||
auth_data);
|
||||
@@ -1030,12 +1074,12 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type,
|
||||
|
||||
rc = pki_privkey_build_dss(key, p, q, g, pubkey, privkey);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
|
||||
ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
|
||||
ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g));
|
||||
ssh_print_hexa("pubkey", ssh_string_data(pubkey),
|
||||
ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
|
||||
ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
|
||||
ssh_log_hexdump("g", ssh_string_data(g), ssh_string_len(g));
|
||||
ssh_log_hexdump("pubkey", ssh_string_data(pubkey),
|
||||
ssh_string_len(pubkey));
|
||||
ssh_print_hexa("privkey", ssh_string_data(privkey),
|
||||
ssh_log_hexdump("privkey", ssh_string_data(privkey),
|
||||
ssh_string_len(privkey));
|
||||
#endif
|
||||
ssh_string_burn(p);
|
||||
@@ -1071,13 +1115,13 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type,
|
||||
|
||||
rc = pki_privkey_build_rsa(key, n, e, d, iqmp, p, q);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n));
|
||||
ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e));
|
||||
ssh_print_hexa("d", ssh_string_data(d), ssh_string_len(d));
|
||||
ssh_print_hexa("iqmp", ssh_string_data(iqmp),
|
||||
ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
|
||||
ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
|
||||
ssh_log_hexdump("d", ssh_string_data(d), ssh_string_len(d));
|
||||
ssh_log_hexdump("iqmp", ssh_string_data(iqmp),
|
||||
ssh_string_len(iqmp));
|
||||
ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
|
||||
ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
|
||||
ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
|
||||
ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
|
||||
#endif
|
||||
ssh_string_burn(n);
|
||||
ssh_string_free(n);
|
||||
@@ -1203,9 +1247,9 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
|
||||
|
||||
rc = pki_pubkey_build_dss(key, p, q, g, pubkey);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
|
||||
ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
|
||||
ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g));
|
||||
ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
|
||||
ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
|
||||
ssh_log_hexdump("g", ssh_string_data(g), ssh_string_len(g));
|
||||
#endif
|
||||
ssh_string_burn(p);
|
||||
ssh_string_free(p);
|
||||
@@ -1234,8 +1278,8 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
|
||||
|
||||
rc = pki_pubkey_build_rsa(key, e, n);
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e));
|
||||
ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n));
|
||||
ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
|
||||
ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
|
||||
#endif
|
||||
ssh_string_burn(e);
|
||||
ssh_string_free(e);
|
||||
@@ -1287,21 +1331,21 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
{
|
||||
ssh_string pubkey = ssh_buffer_get_ssh_string(buffer);
|
||||
if (ssh_string_len(pubkey) != ED25519_PK_LEN) {
|
||||
if (ssh_string_len(pubkey) != ED25519_KEY_LEN) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid public key length");
|
||||
ssh_string_burn(pubkey);
|
||||
ssh_string_free(pubkey);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(ED25519_PK_LEN);
|
||||
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
ssh_string_burn(pubkey);
|
||||
ssh_string_free(pubkey);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN);
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
|
||||
ssh_string_burn(pubkey);
|
||||
ssh_string_free(pubkey);
|
||||
}
|
||||
@@ -2195,7 +2239,7 @@ int pki_key_check_hash_compatible(ssh_key key,
|
||||
int ssh_pki_signature_verify(ssh_session session,
|
||||
ssh_signature sig,
|
||||
const ssh_key key,
|
||||
unsigned char *input,
|
||||
const unsigned char *input,
|
||||
size_t input_len)
|
||||
{
|
||||
int rc;
|
||||
@@ -2225,7 +2269,7 @@ int ssh_pki_signature_verify(ssh_session session,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = pki_signature_verify(session, sig, key, input, input_len);
|
||||
rc = pki_verify_data_signature(sig, key, input, input_len);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -2249,12 +2293,6 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (privkey->type == SSH_KEYTYPE_ED25519 ||
|
||||
privkey->type == SSH_KEYTYPE_ED25519_CERT01)
|
||||
{
|
||||
return pki_do_sign_hash(privkey, input, input_len, SSH_DIGEST_AUTO);
|
||||
}
|
||||
|
||||
return pki_sign_data(privkey, hash_type, input, input_len);
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ ssh_pki_openssh_import(const char *text_key,
|
||||
void *auth_data,
|
||||
bool private)
|
||||
{
|
||||
const char *ptr=text_key;
|
||||
const char *ptr = text_key;
|
||||
const char *end;
|
||||
char *base64;
|
||||
int cmp;
|
||||
@@ -250,7 +250,7 @@ ssh_pki_openssh_import(const char *text_key,
|
||||
uint8_t padding;
|
||||
|
||||
cmp = strncmp(ptr, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN));
|
||||
if (cmp != 0){
|
||||
if (cmp != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no header)");
|
||||
goto out;
|
||||
}
|
||||
@@ -259,15 +259,15 @@ ssh_pki_openssh_import(const char *text_key,
|
||||
ptr++;
|
||||
}
|
||||
end = strstr(ptr, OPENSSH_HEADER_END);
|
||||
if (end == NULL){
|
||||
if (end == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no footer)");
|
||||
goto out;
|
||||
}
|
||||
base64 = malloc(end - ptr + 1);
|
||||
if (base64 == NULL){
|
||||
if (base64 == NULL) {
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; ptr < end; ptr++){
|
||||
for (i = 0; ptr < end; ptr++) {
|
||||
if (!isspace((int)ptr[0])) {
|
||||
base64[i] = ptr[0];
|
||||
i++;
|
||||
@@ -276,7 +276,7 @@ ssh_pki_openssh_import(const char *text_key,
|
||||
base64[i] = '\0';
|
||||
buffer = base64_to_bin(base64);
|
||||
SAFE_FREE(base64);
|
||||
if (buffer == NULL){
|
||||
if (buffer == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (base64 error)");
|
||||
goto out;
|
||||
}
|
||||
@@ -289,21 +289,21 @@ ssh_pki_openssh_import(const char *text_key,
|
||||
&nkeys,
|
||||
&pubkey0,
|
||||
&privkeys);
|
||||
if (rc == SSH_ERROR){
|
||||
if (rc == SSH_ERROR) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (unpack error)");
|
||||
goto out;
|
||||
}
|
||||
cmp = strncmp(magic, OPENSSH_AUTH_MAGIC, strlen(OPENSSH_AUTH_MAGIC));
|
||||
if (cmp != 0){
|
||||
if (cmp != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (bad magic)");
|
||||
goto out;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Opening OpenSSH private key: ciphername: %s, kdf: %s, nkeys: %d\n",
|
||||
"Opening OpenSSH private key: ciphername: %s, kdf: %s, nkeys: %d",
|
||||
ciphername,
|
||||
kdfname,
|
||||
nkeys);
|
||||
if (nkeys != 1){
|
||||
if (nkeys != 1) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Opening OpenSSH private key: only 1 key supported (%d available)", nkeys);
|
||||
goto out;
|
||||
}
|
||||
@@ -327,7 +327,7 @@ ssh_pki_openssh_import(const char *text_key,
|
||||
kdfoptions,
|
||||
auth_fn,
|
||||
auth_data);
|
||||
if (rc == SSH_ERROR){
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -342,20 +342,20 @@ ssh_pki_openssh_import(const char *text_key,
|
||||
ssh_string_len(privkeys));
|
||||
|
||||
rc = ssh_buffer_unpack(privkey_buffer, "dd", &checkint1, &checkint2);
|
||||
if (rc == SSH_ERROR || checkint1 != checkint2){
|
||||
if (rc == SSH_ERROR || checkint1 != checkint2) {
|
||||
SSH_LOG(SSH_LOG_WARN, "OpenSSH private key unpack error (correct password?)");
|
||||
goto out;
|
||||
}
|
||||
rc = pki_openssh_import_privkey_blob(privkey_buffer, &key);
|
||||
if (rc == SSH_ERROR){
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
comment = ssh_buffer_get_ssh_string(privkey_buffer);
|
||||
SAFE_FREE(comment);
|
||||
/* verify that the remaining data is correct padding */
|
||||
for (i=1; ssh_buffer_get_len(privkey_buffer) > 0; ++i){
|
||||
for (i = 1; ssh_buffer_get_len(privkey_buffer) > 0; ++i) {
|
||||
ssh_buffer_get_u8(privkey_buffer, &padding);
|
||||
if (padding != i){
|
||||
if (padding != i) {
|
||||
ssh_key_free(key);
|
||||
key = NULL;
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid padding");
|
||||
@@ -415,12 +415,13 @@ static int pki_openssh_export_privkey_blob(const ssh_key privkey,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
rc = ssh_buffer_pack(buffer,
|
||||
"sdPdP",
|
||||
"sdPdPP",
|
||||
privkey->type_c,
|
||||
(uint32_t)ED25519_PK_LEN,
|
||||
(size_t)ED25519_PK_LEN, privkey->ed25519_pubkey,
|
||||
(uint32_t)ED25519_SK_LEN,
|
||||
(size_t)ED25519_SK_LEN, privkey->ed25519_privkey);
|
||||
(uint32_t)ED25519_KEY_LEN,
|
||||
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey,
|
||||
(uint32_t)(2 * ED25519_KEY_LEN),
|
||||
(size_t)ED25519_KEY_LEN, privkey->ed25519_privkey,
|
||||
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
408
src/pki_crypto.c
408
src/pki_crypto.c
@@ -529,7 +529,7 @@ int pki_key_generate_rsa(ssh_key key, int parameter){
|
||||
|
||||
BN_free(e);
|
||||
|
||||
if (rc == -1 || key->rsa == NULL)
|
||||
if (rc <= 0 || key->rsa == NULL)
|
||||
return SSH_ERROR;
|
||||
return SSH_OK;
|
||||
}
|
||||
@@ -730,29 +730,58 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (key->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_set1_DSA(pkey, key->dsa);
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_set1_RSA(pkey, key->rsa);
|
||||
break;
|
||||
#ifdef HAVE_ECC
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
/* In OpenSSL, the input is the private key seed only, which means
|
||||
* the first half of the SSH private key (the second half is the
|
||||
* public key) */
|
||||
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
|
||||
(const uint8_t *)key->ed25519_privkey,
|
||||
ED25519_KEY_LEN);
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create ed25519 EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Mark the operation as successful as for the other key types */
|
||||
rc = 1;
|
||||
break;
|
||||
#else
|
||||
SSH_LOG(SSH_LOG_WARN, "PEM output not supported for key type ssh-ed25519");
|
||||
goto err;
|
||||
#endif
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||
@@ -821,7 +850,11 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
BIO *mem = NULL;
|
||||
DSA *dsa = NULL;
|
||||
RSA *rsa = NULL;
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
uint8_t *ed25519 = NULL;
|
||||
#else
|
||||
ed25519_privkey *ed25519 = NULL;
|
||||
#endif
|
||||
ssh_key key = NULL;
|
||||
enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
@@ -861,7 +894,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Parsing private key: %s",
|
||||
ERR_error_string(ERR_get_error(),NULL));
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
type = SSH_KEYTYPE_DSS;
|
||||
break;
|
||||
@@ -871,7 +904,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Parsing private key: %s",
|
||||
ERR_error_string(ERR_get_error(),NULL));
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
type = SSH_KEYTYPE_RSA;
|
||||
break;
|
||||
@@ -882,7 +915,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Parsing private key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* pki_privatekey_type_from_string always returns P256 for ECDSA
|
||||
@@ -894,6 +927,43 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
case EVP_PKEY_ED25519:
|
||||
{
|
||||
size_t key_len;
|
||||
int evp_rc = 0;
|
||||
|
||||
/* Get the key length */
|
||||
evp_rc = EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len);
|
||||
if (evp_rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get ed25519 raw private key length: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (key_len != ED25519_KEY_LEN) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ed25519 = malloc(key_len);
|
||||
if (ed25519 == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Out of memory");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
evp_rc = EVP_PKEY_get_raw_private_key(pkey, (uint8_t *)ed25519,
|
||||
&key_len);
|
||||
if (evp_rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get ed25519 raw private key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto fail;
|
||||
}
|
||||
type = SSH_KEYTYPE_ED25519;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
EVP_PKEY_free(pkey);
|
||||
@@ -923,13 +993,16 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
|
||||
return key;
|
||||
fail:
|
||||
EVP_PKEY_free(pkey);
|
||||
ssh_key_free(key);
|
||||
DSA_free(dsa);
|
||||
RSA_free(rsa);
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
EC_KEY_free(ecdsa);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
SAFE_FREE(ed25519);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1473,7 +1546,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
sig_blob = ssh_string_copy(sig->raw_sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
sig_blob = pki_ed25519_sig_to_blob(sig);
|
||||
sig_blob = pki_ed25519_signature_to_blob(sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
@@ -1519,7 +1592,7 @@ static int pki_signature_from_rsa_blob(const ssh_key pubkey,
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
SSH_LOG(SSH_LOG_WARN, "RSA signature len: %lu", (unsigned long)len);
|
||||
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
|
||||
ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len);
|
||||
#endif
|
||||
|
||||
if (len == rsalen) {
|
||||
@@ -1583,8 +1656,8 @@ static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey),
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("r", ssh_string_data(sig_blob), 20);
|
||||
ssh_print_hexa("s", (unsigned char *)ssh_string_data(sig_blob) + 20, 20);
|
||||
ssh_log_hexdump("r", ssh_string_data(sig_blob), 20);
|
||||
ssh_log_hexdump("s", (unsigned char *)ssh_string_data(sig_blob) + 20, 20);
|
||||
#endif
|
||||
|
||||
r = ssh_string_new(20);
|
||||
@@ -1695,7 +1768,7 @@ static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey),
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
|
||||
ssh_log_hexdump("r", ssh_string_data(r), ssh_string_len(r));
|
||||
#endif
|
||||
|
||||
pr = ssh_make_string_bn(r);
|
||||
@@ -1723,7 +1796,7 @@ static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey),
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
|
||||
ssh_log_hexdump("s", ssh_string_data(s), ssh_string_len(s));
|
||||
#endif
|
||||
|
||||
ps = ssh_make_string_bn(s);
|
||||
@@ -1821,7 +1894,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_ed25519_sig_from_blob(sig, sig_blob);
|
||||
rc = pki_signature_from_ed25519_blob(sig, sig_blob);
|
||||
if (rc != SSH_OK){
|
||||
goto error;
|
||||
}
|
||||
@@ -1852,54 +1925,6 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int pki_signature_verify(ssh_session session,
|
||||
const ssh_signature sig,
|
||||
const ssh_key key,
|
||||
const unsigned char *input,
|
||||
size_t input_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (session == NULL || sig == NULL || key == NULL || input == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
|
||||
"pki_signature_verify()");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (ssh_key_type_plain(key->type) != sig->type) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Can not verify %s signature with %s key",
|
||||
sig->type_c,
|
||||
key->type_c);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Check if public key and hash type are compatible */
|
||||
rc = pki_key_check_hash_compatible(key, sig->hash_type);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* For ed25519 keys, verify using the input directly */
|
||||
if (key->type == SSH_KEYTYPE_ED25519 ||
|
||||
key->type == SSH_KEYTYPE_ED25519_CERT01)
|
||||
{
|
||||
rc = pki_ed25519_verify(key, sig, input, input_len);
|
||||
} else {
|
||||
/* For the other key types, calculate the hash and verify the signature */
|
||||
rc = pki_verify_data_signature(sig, key, input, input_len);
|
||||
}
|
||||
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Signature verification error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static const EVP_MD *pki_digest_to_md(enum ssh_digest_e hash_type)
|
||||
{
|
||||
const EVP_MD *md = NULL;
|
||||
@@ -1918,6 +1943,8 @@ static const EVP_MD *pki_digest_to_md(enum ssh_digest_e hash_type)
|
||||
md = EVP_sha1();
|
||||
break;
|
||||
case SSH_DIGEST_AUTO:
|
||||
md = NULL;
|
||||
break;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
|
||||
hash_type);
|
||||
@@ -1931,12 +1958,6 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
|
||||
{
|
||||
EVP_PKEY *pkey = NULL;
|
||||
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(key->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
@@ -1944,6 +1965,12 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
|
||||
SSH_LOG(SSH_LOG_TRACE, "NULL key->dsa");
|
||||
goto error;
|
||||
}
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY_set1_DSA(pkey, key->dsa);
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA:
|
||||
@@ -1953,6 +1980,12 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
|
||||
SSH_LOG(SSH_LOG_TRACE, "NULL key->rsa");
|
||||
goto error;
|
||||
}
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY_set1_RSA(pkey, key->rsa);
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
@@ -1966,12 +1999,46 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
|
||||
SSH_LOG(SSH_LOG_TRACE, "NULL key->ecdsa");
|
||||
goto error;
|
||||
}
|
||||
pkey = EVP_PKEY_new();
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
|
||||
break;
|
||||
# endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
/* Not supported yet. This type requires the use of EVP_DigestSign*()
|
||||
* API and ECX keys. There is no EVP_set1_ECX_KEY() or equivalent yet. */
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
# if defined(HAVE_OPENSSL_ED25519)
|
||||
if (ssh_key_is_private(key)) {
|
||||
if (key->ed25519_privkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "NULL key->ed25519_privkey");
|
||||
goto error;
|
||||
}
|
||||
/* In OpenSSL, the input is the private key seed only, which means
|
||||
* the first half of the SSH private key (the second half is the
|
||||
* public key). Both keys have the same length (32 bytes) */
|
||||
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
|
||||
(const uint8_t *)key->ed25519_privkey,
|
||||
ED25519_KEY_LEN);
|
||||
} else {
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "NULL key->ed25519_pubkey");
|
||||
goto error;
|
||||
}
|
||||
pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
|
||||
(const uint8_t *)key->ed25519_pubkey,
|
||||
ED25519_KEY_LEN);
|
||||
}
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create ed25519 EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown private key algorithm for type: %d",
|
||||
@@ -2009,7 +2076,7 @@ ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
EVP_PKEY *pkey = NULL;
|
||||
|
||||
unsigned char *raw_sig_data = NULL;
|
||||
unsigned int raw_sig_len;
|
||||
size_t raw_sig_len;
|
||||
|
||||
ssh_signature sig = NULL;
|
||||
|
||||
@@ -2027,10 +2094,20 @@ ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef HAVE_OPENSSL_ED25519
|
||||
if (privkey->type == SSH_KEYTYPE_ED25519 ||
|
||||
privkey->type == SSH_KEYTYPE_ED25519_CERT01)
|
||||
{
|
||||
return pki_do_sign_hash(privkey, input, input_len, hash_type);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set hash algorithm to be used */
|
||||
md = pki_digest_to_md(hash_type);
|
||||
if (md == NULL) {
|
||||
return NULL;
|
||||
if (hash_type != SSH_DIGEST_AUTO) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup private key EVP_PKEY */
|
||||
@@ -2055,26 +2132,42 @@ ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
}
|
||||
|
||||
/* Sign the data */
|
||||
rc = EVP_SignInit_ex(ctx, md, NULL);
|
||||
if (!rc){
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_SignInit() failed");
|
||||
rc = EVP_DigestSignInit(ctx, NULL, md, NULL, pkey);
|
||||
if (rc != 1){
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"EVP_DigestSignInit() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EVP_SignUpdate(ctx, input, input_len);
|
||||
if (!rc) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_SignUpdate() failed");
|
||||
#ifdef HAVE_OPENSSL_EVP_DIGESTSIGN
|
||||
rc = EVP_DigestSign(ctx, raw_sig_data, &raw_sig_len, input, input_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"EVP_DigestSign() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
#else
|
||||
rc = EVP_DigestSignUpdate(ctx, input, input_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"EVP_DigestSignUpdate() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EVP_SignFinal(ctx, raw_sig_data, &raw_sig_len, pkey);
|
||||
if (!rc) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_SignFinal() failed");
|
||||
rc = EVP_DigestSignFinal(ctx, raw_sig_data, &raw_sig_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"EVP_DigestSignFinal() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Generated signature", raw_sig_data, raw_sig_len);
|
||||
ssh_log_hexdump("Generated signature", raw_sig_data, raw_sig_len);
|
||||
#endif
|
||||
|
||||
/* Allocate and fill output signature */
|
||||
@@ -2144,7 +2237,11 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
int evp_rc;
|
||||
|
||||
if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL ||
|
||||
signature == NULL || signature->raw_sig == NULL)
|
||||
signature == NULL || (signature->raw_sig == NULL
|
||||
#ifndef HAVE_OPENSSL_ED25519
|
||||
&& signature->ed25519_sig == NULL
|
||||
#endif
|
||||
))
|
||||
{
|
||||
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
|
||||
"pki_verify_data_signature()");
|
||||
@@ -2157,6 +2254,14 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifndef HAVE_OPENSSL_ED25519
|
||||
if (pubkey->type == SSH_KEYTYPE_ED25519 ||
|
||||
pubkey->type == SSH_KEYTYPE_ED25519_CERT01)
|
||||
{
|
||||
return pki_ed25519_verify(pubkey, signature, input, input_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get the signature to be verified */
|
||||
raw_sig_data = ssh_string_data(signature->raw_sig);
|
||||
raw_sig_len = ssh_string_len(signature->raw_sig);
|
||||
@@ -2167,7 +2272,9 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
/* Set hash algorithm to be used */
|
||||
md = pki_digest_to_md(signature->hash_type);
|
||||
if (md == NULL) {
|
||||
return SSH_ERROR;
|
||||
if (signature->hash_type != SSH_DIGEST_AUTO) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup public key EVP_PKEY */
|
||||
@@ -2179,33 +2286,42 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
/* Create the context */
|
||||
ctx = EVP_MD_CTX_create();
|
||||
if (ctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create EVP_MD_CTX: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Verify the signature */
|
||||
evp_rc = EVP_VerifyInit_ex(ctx, md, NULL);
|
||||
if (!evp_rc){
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_SignInit() failed");
|
||||
evp_rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, pkey);
|
||||
if (evp_rc != 1){
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"EVP_DigestVerifyInit() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
evp_rc = EVP_VerifyUpdate(ctx, input, input_len);
|
||||
if (!evp_rc) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_SignUpdate() failed");
|
||||
#ifdef HAVE_OPENSSL_EVP_DIGESTVERIFY
|
||||
evp_rc = EVP_DigestVerify(ctx, raw_sig_data, raw_sig_len, input, input_len);
|
||||
#else
|
||||
evp_rc = EVP_DigestVerifyUpdate(ctx, input, input_len);
|
||||
if (evp_rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"EVP_DigestVerifyUpdate() failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
evp_rc = EVP_VerifyFinal(ctx, raw_sig_data, raw_sig_len, pkey);
|
||||
if (evp_rc < 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_SignFinal() failed");
|
||||
rc = SSH_ERROR;
|
||||
} else if (evp_rc == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Signature invalid");
|
||||
rc = SSH_ERROR;
|
||||
} else if (evp_rc == 1) {
|
||||
evp_rc = EVP_DigestVerifyFinal(ctx, raw_sig_data, raw_sig_len);
|
||||
#endif
|
||||
if (evp_rc == 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Signature valid");
|
||||
rc = SSH_OK;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Signature invalid: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -2218,6 +2334,92 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
int pki_key_generate_ed25519(ssh_key key)
|
||||
{
|
||||
int evp_rc;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
size_t privkey_len = ED25519_KEY_LEN;
|
||||
size_t pubkey_len = ED25519_KEY_LEN;
|
||||
|
||||
if (key == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create ed25519 EVP_PKEY_CTX: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
evp_rc = EVP_PKEY_keygen_init(pctx);
|
||||
if (evp_rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize ed25519 key generation: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
evp_rc = EVP_PKEY_keygen(pctx, &pkey);
|
||||
if (evp_rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to generate ed25519 key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->ed25519_privkey = malloc(ED25519_KEY_LEN);
|
||||
if (key->ed25519_privkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to allocate memory for ed25519 private key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to allocate memory for ed25519 public key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
evp_rc = EVP_PKEY_get_raw_private_key(pkey, (uint8_t *)key->ed25519_privkey,
|
||||
&privkey_len);
|
||||
if (evp_rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get ed25519 raw private key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
evp_rc = EVP_PKEY_get_raw_public_key(pkey, (uint8_t *)key->ed25519_pubkey,
|
||||
&pubkey_len);
|
||||
if (evp_rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get ed25519 raw public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto error;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
if (pctx != NULL) {
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
}
|
||||
if (pkey != NULL) {
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
SAFE_FREE(key->ed25519_privkey);
|
||||
SAFE_FREE(key->ed25519_pubkey);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#else
|
||||
ssh_signature pki_do_sign_hash(const ssh_key privkey,
|
||||
const unsigned char *hash,
|
||||
size_t hlen,
|
||||
@@ -2250,4 +2452,6 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey,
|
||||
|
||||
return sig;
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_ED25519 */
|
||||
|
||||
#endif /* _PKI_CRYPTO_H */
|
||||
|
||||
@@ -56,28 +56,6 @@ error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
int pki_privkey_build_ed25519(ssh_key key,
|
||||
ssh_string pubkey,
|
||||
ssh_string privkey)
|
||||
{
|
||||
if (ssh_string_len(pubkey) != ED25519_PK_LEN ||
|
||||
ssh_string_len(privkey) != ED25519_SK_LEN) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
key->ed25519_privkey = malloc(ED25519_SK_LEN);
|
||||
key->ed25519_pubkey = malloc(ED25519_PK_LEN);
|
||||
if (key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
|
||||
ED25519_SK_LEN);
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
|
||||
ED25519_PK_LEN);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int pki_ed25519_sign(const ssh_key privkey,
|
||||
ssh_signature sig,
|
||||
const unsigned char *hash,
|
||||
@@ -170,165 +148,3 @@ error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Compare ed25519 keys if they are equal.
|
||||
*
|
||||
* @param[in] k1 The first key to compare.
|
||||
*
|
||||
* @param[in] k2 The second key to compare.
|
||||
*
|
||||
* @param[in] what What part or type of the key do you want to compare.
|
||||
*
|
||||
* @return 0 if equal, 1 if not.
|
||||
*/
|
||||
int pki_ed25519_key_cmp(const ssh_key k1,
|
||||
const ssh_key k2,
|
||||
enum ssh_keycmp_e what)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
switch(what) {
|
||||
case SSH_KEY_CMP_PRIVATE:
|
||||
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
|
||||
return 1;
|
||||
}
|
||||
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_SK_LEN);
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case SSH_KEY_CMP_PUBLIC:
|
||||
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
|
||||
return 1;
|
||||
}
|
||||
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_PK_LEN);
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief duplicate an ed25519 key
|
||||
*
|
||||
* @param[out\ new preinitialized output ssh_ke
|
||||
*
|
||||
* @param[in] key key to copy
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
|
||||
{
|
||||
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief outputs an ed25519 public key in a blob buffer.
|
||||
*
|
||||
* @param[out] buffer output buffer
|
||||
*
|
||||
* @param[in] key key to output
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (key->ed25519_pubkey == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(buffer,
|
||||
"dP",
|
||||
(uint32_t)ED25519_PK_LEN,
|
||||
(size_t)ED25519_PK_LEN, key->ed25519_pubkey);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief output a signature blob from an ed25519 signature
|
||||
*
|
||||
* @param[in] sig signature to convert
|
||||
*
|
||||
* @return Signature blob in SSH string, or NULL on error
|
||||
*/
|
||||
ssh_string pki_ed25519_sig_to_blob(ssh_signature sig)
|
||||
{
|
||||
ssh_string sig_blob;
|
||||
|
||||
if (sig->ed25519_sig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sig_blob = ssh_string_new(ED25519_SIG_LEN);
|
||||
if (sig_blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN);
|
||||
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Convert a signature blob in an ed25519 signature.
|
||||
*
|
||||
* @param[out] sig a preinitialized signature
|
||||
*
|
||||
* @param[in] sig_blob a signature blob
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = ssh_string_len(sig_blob);
|
||||
if (len != ED25519_SIG_LEN){
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid ssh-ed25519 signature len: %zu", len);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
sig->ed25519_sig = malloc(ED25519_SIG_LEN);
|
||||
if (sig->ed25519_sig == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
280
src/pki_ed25519_common.c
Normal file
280
src/pki_ed25519_common.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* pki_ed25519_common.c - Common ed25519 functions
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2014 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/pki.h"
|
||||
#include "libssh/pki_priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
|
||||
int pki_privkey_build_ed25519(ssh_key key,
|
||||
ssh_string pubkey,
|
||||
ssh_string privkey)
|
||||
{
|
||||
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
|
||||
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN))
|
||||
{
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
/* In OpenSSL implementation, the private key is the original private seed,
|
||||
* without the public key. */
|
||||
key->ed25519_privkey = malloc(ED25519_KEY_LEN);
|
||||
#else
|
||||
/* In the internal implementation, the private key is the concatenation of
|
||||
* the private seed with the public key. */
|
||||
key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
if (key->ed25519_privkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
|
||||
ED25519_KEY_LEN);
|
||||
#else
|
||||
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
|
||||
2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
|
||||
ED25519_KEY_LEN);
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
SAFE_FREE(key->ed25519_privkey);
|
||||
SAFE_FREE(key->ed25519_pubkey);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Compare ed25519 keys if they are equal.
|
||||
*
|
||||
* @param[in] k1 The first key to compare.
|
||||
*
|
||||
* @param[in] k2 The second key to compare.
|
||||
*
|
||||
* @param[in] what What part or type of the key do you want to compare.
|
||||
*
|
||||
* @return 0 if equal, 1 if not.
|
||||
*/
|
||||
int pki_ed25519_key_cmp(const ssh_key k1,
|
||||
const ssh_key k2,
|
||||
enum ssh_keycmp_e what)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
switch(what) {
|
||||
case SSH_KEY_CMP_PRIVATE:
|
||||
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
|
||||
return 1;
|
||||
}
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
/* In OpenSSL implementation, the private key is the original private
|
||||
* seed, without the public key. */
|
||||
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_KEY_LEN);
|
||||
#else
|
||||
/* In the internal implementation, the private key is the concatenation
|
||||
* of the private seed with the public key. */
|
||||
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey,
|
||||
2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case SSH_KEY_CMP_PUBLIC:
|
||||
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
|
||||
return 1;
|
||||
}
|
||||
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Duplicate an Ed25519 key
|
||||
*
|
||||
* @param[out] new Pre-initialized ssh_key structure
|
||||
*
|
||||
* @param[in] key Key to copy
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
|
||||
{
|
||||
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (key->ed25519_privkey != NULL) {
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
/* In OpenSSL implementation, the private key is the original private
|
||||
* seed, without the public key. */
|
||||
new->ed25519_privkey = malloc(ED25519_KEY_LEN);
|
||||
#else
|
||||
/* In the internal implementation, the private key is the concatenation
|
||||
* of the private seed with the public key. */
|
||||
new->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
if (new->ed25519_privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN);
|
||||
#else
|
||||
memcpy(new->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (key->ed25519_pubkey != NULL) {
|
||||
new->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (new->ed25519_pubkey == NULL) {
|
||||
SAFE_FREE(new->ed25519_privkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Outputs an Ed25519 public key in a blob buffer.
|
||||
*
|
||||
* @param[out] buffer Output buffer
|
||||
*
|
||||
* @param[in] key Key to output
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (key->ed25519_pubkey == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(buffer,
|
||||
"dP",
|
||||
(uint32_t)ED25519_KEY_LEN,
|
||||
(size_t)ED25519_KEY_LEN, key->ed25519_pubkey);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief output a signature blob from an ed25519 signature
|
||||
*
|
||||
* @param[in] sig signature to convert
|
||||
*
|
||||
* @return Signature blob in SSH string, or NULL on error
|
||||
*/
|
||||
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig)
|
||||
{
|
||||
ssh_string sig_blob;
|
||||
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
/* When using the OpenSSL implementation, the signature is stored in raw_sig
|
||||
* which is shared by all algorithms.*/
|
||||
if (sig->raw_sig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
/* When using the internal implementation, the signature is stored in an
|
||||
* algorithm specific field. */
|
||||
if (sig->ed25519_sig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
sig_blob = ssh_string_new(ED25519_SIG_LEN);
|
||||
if (sig_blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
ssh_string_fill(sig_blob, ssh_string_data(sig->raw_sig),
|
||||
ssh_string_len(sig->raw_sig));
|
||||
#else
|
||||
ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN);
|
||||
#endif
|
||||
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Convert a signature blob in an ed25519 signature.
|
||||
*
|
||||
* @param[out] sig a preinitialized signature
|
||||
*
|
||||
* @param[in] sig_blob a signature blob
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = ssh_string_len(sig_blob);
|
||||
if (len != ED25519_SIG_LEN){
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid ssh-ed25519 signature len: %zu", len);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
sig->raw_sig = ssh_string_copy(sig_blob);
|
||||
#else
|
||||
sig->ed25519_sig = malloc(ED25519_SIG_LEN);
|
||||
if (sig->ed25519_sig == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN);
|
||||
#endif
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -1832,7 +1832,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
gcry_sexp_release(sexp);
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
sig_blob = pki_ed25519_sig_to_blob(sig);
|
||||
sig_blob = pki_ed25519_signature_to_blob(sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
@@ -1945,7 +1945,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"DSA signature len: %lu",
|
||||
(unsigned long)len);
|
||||
ssh_print_hexa("DSA signature", ssh_string_data(sig_blob), len);
|
||||
ssh_log_hexdump("DSA signature", ssh_string_data(sig_blob), len);
|
||||
#endif
|
||||
|
||||
err = gcry_sexp_build(&sig->dsa_sig,
|
||||
@@ -1980,7 +1980,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
SSH_LOG(SSH_LOG_DEBUG, "RSA signature len: %lu", (unsigned long)len);
|
||||
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
|
||||
ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len);
|
||||
#endif
|
||||
|
||||
err = gcry_sexp_build(&sig->rsa_sig,
|
||||
@@ -1994,7 +1994,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_ed25519_sig_from_blob(sig, sig_blob);
|
||||
rc = pki_signature_from_ed25519_blob(sig, sig_blob);
|
||||
if (rc != SSH_OK){
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
@@ -2055,8 +2055,8 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
|
||||
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
|
||||
ssh_log_hexdump("r", ssh_string_data(r), ssh_string_len(r));
|
||||
ssh_log_hexdump("s", ssh_string_data(s), ssh_string_len(s));
|
||||
#endif
|
||||
|
||||
err = gcry_sexp_build(&sig->ecdsa_sig,
|
||||
@@ -2087,54 +2087,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
return sig;
|
||||
}
|
||||
|
||||
int pki_signature_verify(ssh_session session,
|
||||
const ssh_signature sig,
|
||||
const ssh_key key,
|
||||
const unsigned char *input,
|
||||
size_t input_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (session == NULL || sig == NULL || key == NULL || input == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
|
||||
"pki_signature_verify()");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (ssh_key_type_plain(key->type) != sig->type) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Can not verify %s signature with %s key",
|
||||
sig->type_c,
|
||||
key->type_c);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Check if public key and hash type are compatible */
|
||||
rc = pki_key_check_hash_compatible(key, sig->hash_type);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* For ed25519 keys, verify using the input directly */
|
||||
if (key->type == SSH_KEYTYPE_ED25519 ||
|
||||
key->type == SSH_KEYTYPE_ED25519_CERT01)
|
||||
{
|
||||
rc = pki_ed25519_verify(key, sig, input, input_len);
|
||||
} else {
|
||||
/* For the other key types, calculate the hash and verify the signature */
|
||||
rc = pki_verify_data_signature(sig, key, input, input_len);
|
||||
}
|
||||
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Signature verification error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
ssh_signature pki_do_sign_hash(const ssh_key privkey,
|
||||
const unsigned char *hash,
|
||||
size_t hlen,
|
||||
@@ -2268,6 +2220,7 @@ ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
size_t input_len)
|
||||
{
|
||||
unsigned char hash[SHA512_DIGEST_LEN] = {0};
|
||||
const unsigned char *sign_input = NULL;
|
||||
uint32_t hlen = 0;
|
||||
int rc;
|
||||
|
||||
@@ -2287,27 +2240,38 @@ ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
case SSH_DIGEST_SHA256:
|
||||
sha256(input, input_len, hash);
|
||||
hlen = SHA256_DIGEST_LEN;
|
||||
sign_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA384:
|
||||
sha384(input, input_len, hash);
|
||||
hlen = SHA384_DIGEST_LEN;
|
||||
sign_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA512:
|
||||
sha512(input, input_len, hash);
|
||||
hlen = SHA512_DIGEST_LEN;
|
||||
sign_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA1:
|
||||
sha1(input, input_len, hash);
|
||||
hlen = SHA_DIGEST_LEN;
|
||||
sign_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_AUTO:
|
||||
if (privkey->type == SSH_KEYTYPE_ED25519) {
|
||||
/* SSH_DIGEST_AUTO should only be used with ed25519 */
|
||||
sign_input = input;
|
||||
hlen = input_len;
|
||||
break;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
|
||||
hash_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pki_do_sign_hash(privkey, hash, hlen, hash_type);
|
||||
return pki_do_sign_hash(privkey, sign_input, hlen, hash_type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2336,6 +2300,8 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
unsigned char *hash = ghash + 1;
|
||||
uint32_t hlen = 0;
|
||||
|
||||
const unsigned char *verify_input = NULL;
|
||||
|
||||
int rc;
|
||||
|
||||
if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL ||
|
||||
@@ -2357,23 +2323,35 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
sha256(input, input_len, hash);
|
||||
hlen = SHA256_DIGEST_LEN;
|
||||
hash_type = "sha256";
|
||||
verify_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA384:
|
||||
sha384(input, input_len, hash);
|
||||
hlen = SHA384_DIGEST_LEN;
|
||||
hash_type = "sha384";
|
||||
verify_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA512:
|
||||
sha512(input, input_len, hash);
|
||||
hlen = SHA512_DIGEST_LEN;
|
||||
hash_type = "sha512";
|
||||
verify_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA1:
|
||||
sha1(input, input_len, hash);
|
||||
hlen = SHA_DIGEST_LEN;
|
||||
hash_type = "sha1";
|
||||
verify_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_AUTO:
|
||||
if (pubkey->type == SSH_KEYTYPE_ED25519 ||
|
||||
pubkey->type == SSH_KEYTYPE_ED25519_CERT01)
|
||||
{
|
||||
verify_input = input;
|
||||
hlen = input_len;
|
||||
break;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown sig->hash_type: %d", signature->hash_type);
|
||||
return SSH_ERROR;
|
||||
@@ -2461,6 +2439,14 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
rc = pki_ed25519_verify(pubkey, signature, verify_input, hlen);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "ED25519 error: Signature invalid");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "libssh/pki_priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/bignum.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#define MAX_PASSPHRASE_SIZE 1024
|
||||
#define MAX_KEY_SIZE 32
|
||||
@@ -836,7 +837,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
sig_blob = pki_ed25519_sig_to_blob(sig);
|
||||
sig_blob = pki_ed25519_signature_to_blob(sig);
|
||||
break;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %s",
|
||||
@@ -873,7 +874,7 @@ static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey, const
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
SSH_LOG(SSH_LOG_WARN, "RSA signature len: %lu", (unsigned long)len);
|
||||
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
|
||||
ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len);
|
||||
#endif
|
||||
|
||||
if (len == rsalen) {
|
||||
@@ -966,7 +967,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
return NULL;
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
|
||||
ssh_log_hexdump("r", ssh_string_data(r), ssh_string_len(r));
|
||||
#endif
|
||||
sig->ecdsa_sig.r = ssh_make_string_bn(r);
|
||||
ssh_string_burn(r);
|
||||
@@ -986,7 +987,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
|
||||
ssh_log_hexdump("s", ssh_string_data(s), ssh_string_len(s));
|
||||
#endif
|
||||
sig->ecdsa_sig.s = ssh_make_string_bn(s);
|
||||
ssh_string_burn(s);
|
||||
@@ -1007,7 +1008,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
break;
|
||||
}
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_ed25519_sig_from_blob(sig, sig_blob);
|
||||
rc = pki_signature_from_ed25519_blob(sig, sig_blob);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
@@ -1021,51 +1022,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
return sig;
|
||||
}
|
||||
|
||||
int pki_signature_verify(ssh_session session, const ssh_signature sig, const
|
||||
ssh_key key, const unsigned char *input, size_t input_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (session == NULL || sig == NULL || key == NULL || input == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
|
||||
"pki_signature_verify()");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (ssh_key_type_plain(key->type) != sig->type) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Can not verify %s signature with %s key",
|
||||
sig->type_c,
|
||||
key->type_c);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Check if public key and hash type are compatible */
|
||||
rc = pki_key_check_hash_compatible(key, sig->hash_type);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* For ed25519 keys, verify using the input directly */
|
||||
if (key->type == SSH_KEYTYPE_ED25519 ||
|
||||
key->type == SSH_KEYTYPE_ED25519_CERT01)
|
||||
{
|
||||
rc = pki_ed25519_verify(key, sig, input, input_len);
|
||||
} else {
|
||||
/* For the other key types, calculate the hash and verify the signature */
|
||||
rc = pki_verify_data_signature(sig, key, input, input_len);
|
||||
}
|
||||
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Signature verification error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static ssh_string rsa_do_sign_hash(const unsigned char *digest,
|
||||
int dlen,
|
||||
mbedtls_pk_context *privkey,
|
||||
@@ -1213,6 +1169,7 @@ ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
size_t input_len)
|
||||
{
|
||||
unsigned char hash[SHA512_DIGEST_LEN] = {0};
|
||||
const unsigned char *sign_input = NULL;
|
||||
uint32_t hlen = 0;
|
||||
int rc;
|
||||
|
||||
@@ -1232,27 +1189,38 @@ ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
case SSH_DIGEST_SHA256:
|
||||
sha256(input, input_len, hash);
|
||||
hlen = SHA256_DIGEST_LEN;
|
||||
sign_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA384:
|
||||
sha384(input, input_len, hash);
|
||||
hlen = SHA384_DIGEST_LEN;
|
||||
sign_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA512:
|
||||
sha512(input, input_len, hash);
|
||||
hlen = SHA512_DIGEST_LEN;
|
||||
sign_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA1:
|
||||
sha1(input, input_len, hash);
|
||||
hlen = SHA_DIGEST_LEN;
|
||||
sign_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_AUTO:
|
||||
if (privkey->type == SSH_KEYTYPE_ED25519) {
|
||||
/* SSH_DIGEST_AUTO should only be used with ed25519 */
|
||||
sign_input = input;
|
||||
hlen = input_len;
|
||||
break;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
|
||||
hash_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pki_do_sign_hash(privkey, hash, hlen, hash_type);
|
||||
return pki_do_sign_hash(privkey, sign_input, hlen, hash_type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1275,6 +1243,7 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
{
|
||||
|
||||
unsigned char hash[SHA512_DIGEST_LEN] = {0};
|
||||
const unsigned char *verify_input = NULL;
|
||||
uint32_t hlen = 0;
|
||||
|
||||
mbedtls_md_type_t md = 0;
|
||||
@@ -1300,23 +1269,35 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
sha256(input, input_len, hash);
|
||||
hlen = SHA256_DIGEST_LEN;
|
||||
md = MBEDTLS_MD_SHA256;
|
||||
verify_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA384:
|
||||
sha384(input, input_len, hash);
|
||||
hlen = SHA384_DIGEST_LEN;
|
||||
md = MBEDTLS_MD_SHA384;
|
||||
verify_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA512:
|
||||
sha512(input, input_len, hash);
|
||||
hlen = SHA512_DIGEST_LEN;
|
||||
md = MBEDTLS_MD_SHA512;
|
||||
verify_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_SHA1:
|
||||
sha1(input, input_len, hash);
|
||||
hlen = SHA_DIGEST_LEN;
|
||||
md = MBEDTLS_MD_SHA1;
|
||||
verify_input = hash;
|
||||
break;
|
||||
case SSH_DIGEST_AUTO:
|
||||
if (pubkey->type == SSH_KEYTYPE_ED25519 ||
|
||||
pubkey->type == SSH_KEYTYPE_ED25519_CERT01)
|
||||
{
|
||||
verify_input = input;
|
||||
hlen = input_len;
|
||||
break;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown sig->hash_type: %d",
|
||||
signature->hash_type);
|
||||
@@ -1353,6 +1334,14 @@ int pki_verify_data_signature(ssh_signature signature,
|
||||
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
rc = pki_ed25519_verify(pubkey, signature, verify_input, hlen);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "ED25519 error: Signature invalid");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown public key type");
|
||||
return SSH_ERROR;
|
||||
|
||||
508
src/socket.c
508
src/socket.c
@@ -102,36 +102,37 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
|
||||
* \internal
|
||||
* \brief inits the socket system (windows specific)
|
||||
*/
|
||||
int ssh_socket_init(void) {
|
||||
if (sockets_initialized == 0) {
|
||||
int ssh_socket_init(void)
|
||||
{
|
||||
if (sockets_initialized == 0) {
|
||||
#ifdef _WIN32
|
||||
struct WSAData wsaData;
|
||||
struct WSAData wsaData;
|
||||
|
||||
/* Initiates use of the Winsock DLL by a process. */
|
||||
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
|
||||
return -1;
|
||||
/* Initiates use of the Winsock DLL by a process. */
|
||||
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
ssh_poll_init();
|
||||
|
||||
sockets_initialized = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
ssh_poll_init();
|
||||
|
||||
sockets_initialized = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cleanup the socket system.
|
||||
*/
|
||||
void ssh_socket_cleanup(void) {
|
||||
if (sockets_initialized == 1) {
|
||||
ssh_poll_cleanup();
|
||||
void ssh_socket_cleanup(void)
|
||||
{
|
||||
if (sockets_initialized == 1) {
|
||||
ssh_poll_cleanup();
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
WSACleanup();
|
||||
#endif
|
||||
sockets_initialized = 0;
|
||||
}
|
||||
sockets_initialized = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,37 +140,38 @@ void ssh_socket_cleanup(void) {
|
||||
* \internal
|
||||
* \brief creates a new Socket object
|
||||
*/
|
||||
ssh_socket ssh_socket_new(ssh_session session) {
|
||||
ssh_socket s;
|
||||
ssh_socket ssh_socket_new(ssh_session session)
|
||||
{
|
||||
ssh_socket s;
|
||||
|
||||
s = calloc(1, sizeof(struct ssh_socket_struct));
|
||||
if (s == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return NULL;
|
||||
}
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
s->last_errno = -1;
|
||||
s->fd_is_socket = 1;
|
||||
s->session = session;
|
||||
s->in_buffer = ssh_buffer_new();
|
||||
if (s->in_buffer == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(s);
|
||||
return NULL;
|
||||
}
|
||||
s->out_buffer=ssh_buffer_new();
|
||||
if (s->out_buffer == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
ssh_buffer_free(s->in_buffer);
|
||||
SAFE_FREE(s);
|
||||
return NULL;
|
||||
}
|
||||
s->read_wontblock = 0;
|
||||
s->write_wontblock = 0;
|
||||
s->data_except = 0;
|
||||
s->poll_handle = NULL;
|
||||
s->state=SSH_SOCKET_NONE;
|
||||
return s;
|
||||
s = calloc(1, sizeof(struct ssh_socket_struct));
|
||||
if (s == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return NULL;
|
||||
}
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
s->last_errno = -1;
|
||||
s->fd_is_socket = 1;
|
||||
s->session = session;
|
||||
s->in_buffer = ssh_buffer_new();
|
||||
if (s->in_buffer == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(s);
|
||||
return NULL;
|
||||
}
|
||||
s->out_buffer=ssh_buffer_new();
|
||||
if (s->out_buffer == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
ssh_buffer_free(s->in_buffer);
|
||||
SAFE_FREE(s);
|
||||
return NULL;
|
||||
}
|
||||
s->read_wontblock = 0;
|
||||
s->write_wontblock = 0;
|
||||
s->data_except = 0;
|
||||
s->poll_handle = NULL;
|
||||
s->state=SSH_SOCKET_NONE;
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,17 +179,18 @@ ssh_socket ssh_socket_new(ssh_session session) {
|
||||
* @brief Reset the state of a socket so it looks brand-new
|
||||
* @param[in] s socket to rest
|
||||
*/
|
||||
void ssh_socket_reset(ssh_socket s){
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
s->last_errno = -1;
|
||||
s->fd_is_socket = 1;
|
||||
ssh_buffer_reinit(s->in_buffer);
|
||||
ssh_buffer_reinit(s->out_buffer);
|
||||
s->read_wontblock = 0;
|
||||
s->write_wontblock = 0;
|
||||
s->data_except = 0;
|
||||
s->poll_handle = NULL;
|
||||
s->state=SSH_SOCKET_NONE;
|
||||
void ssh_socket_reset(ssh_socket s)
|
||||
{
|
||||
s->fd = SSH_INVALID_SOCKET;
|
||||
s->last_errno = -1;
|
||||
s->fd_is_socket = 1;
|
||||
ssh_buffer_reinit(s->in_buffer);
|
||||
ssh_buffer_reinit(s->out_buffer);
|
||||
s->read_wontblock = 0;
|
||||
s->write_wontblock = 0;
|
||||
s->data_except = 0;
|
||||
s->poll_handle = NULL;
|
||||
s->state=SSH_SOCKET_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,8 +201,9 @@ void ssh_socket_reset(ssh_socket s){
|
||||
* @param callbacks a ssh_socket_callback object reference.
|
||||
*/
|
||||
|
||||
void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){
|
||||
s->callbacks=callbacks;
|
||||
void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks)
|
||||
{
|
||||
s->callbacks = callbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,71 +387,73 @@ ssh_poll_handle ssh_socket_get_poll_handle(ssh_socket s)
|
||||
/** \internal
|
||||
* \brief Deletes a socket object
|
||||
*/
|
||||
void ssh_socket_free(ssh_socket s){
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
ssh_socket_close(s);
|
||||
ssh_buffer_free(s->in_buffer);
|
||||
ssh_buffer_free(s->out_buffer);
|
||||
SAFE_FREE(s);
|
||||
void ssh_socket_free(ssh_socket s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
ssh_socket_close(s);
|
||||
ssh_buffer_free(s->in_buffer);
|
||||
ssh_buffer_free(s->out_buffer);
|
||||
SAFE_FREE(s);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
int ssh_socket_unix(ssh_socket s, const char *path) {
|
||||
struct sockaddr_un sunaddr;
|
||||
socket_t fd;
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
|
||||
int ssh_socket_unix(ssh_socket s, const char *path)
|
||||
{
|
||||
struct sockaddr_un sunaddr;
|
||||
socket_t fd;
|
||||
sunaddr.sun_family = AF_UNIX;
|
||||
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == SSH_INVALID_SOCKET) {
|
||||
ssh_set_error(s->session, SSH_FATAL,
|
||||
"Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == SSH_INVALID_SOCKET) {
|
||||
ssh_set_error(s->session, SSH_FATAL,
|
||||
"Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(fd, F_SETFD, 1) == -1) {
|
||||
ssh_set_error(s->session, SSH_FATAL,
|
||||
"Error from fcntl(fd, F_SETFD, 1): %s",
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (fcntl(fd, F_SETFD, 1) == -1) {
|
||||
ssh_set_error(s->session, SSH_FATAL,
|
||||
"Error from fcntl(fd, F_SETFD, 1): %s",
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(fd, (struct sockaddr *) &sunaddr,
|
||||
sizeof(sunaddr)) < 0) {
|
||||
ssh_set_error(s->session, SSH_FATAL, "Error from connect(): %s",
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
ssh_socket_set_fd(s,fd);
|
||||
return 0;
|
||||
if (connect(fd, (struct sockaddr *) &sunaddr, sizeof(sunaddr)) < 0) {
|
||||
ssh_set_error(s->session, SSH_FATAL, "Error from connect(): %s",
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
ssh_socket_set_fd(s,fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \internal
|
||||
* \brief closes a socket
|
||||
*/
|
||||
void ssh_socket_close(ssh_socket s){
|
||||
if (ssh_socket_is_open(s)) {
|
||||
void ssh_socket_close(ssh_socket s)
|
||||
{
|
||||
if (ssh_socket_is_open(s)) {
|
||||
#ifdef _WIN32
|
||||
CLOSE_SOCKET(s->fd);
|
||||
s->last_errno = WSAGetLastError();
|
||||
CLOSE_SOCKET(s->fd);
|
||||
s->last_errno = WSAGetLastError();
|
||||
#else
|
||||
CLOSE_SOCKET(s->fd);
|
||||
s->last_errno = errno;
|
||||
CLOSE_SOCKET(s->fd);
|
||||
s->last_errno = errno;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if(s->poll_handle != NULL){
|
||||
ssh_poll_free(s->poll_handle);
|
||||
s->poll_handle=NULL;
|
||||
}
|
||||
if (s->poll_handle != NULL) {
|
||||
ssh_poll_free(s->poll_handle);
|
||||
s->poll_handle = NULL;
|
||||
}
|
||||
|
||||
s->state = SSH_SOCKET_CLOSED;
|
||||
s->state = SSH_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -458,7 +464,8 @@ void ssh_socket_close(ssh_socket s){
|
||||
* @warning this function updates boths the input and output
|
||||
* file descriptors
|
||||
*/
|
||||
void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
|
||||
void ssh_socket_set_fd(ssh_socket s, socket_t fd)
|
||||
{
|
||||
s->fd = fd;
|
||||
|
||||
if (s->poll_handle) {
|
||||
@@ -479,14 +486,15 @@ void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
|
||||
*/
|
||||
socket_t ssh_socket_get_fd(ssh_socket s)
|
||||
{
|
||||
return s->fd;
|
||||
return s->fd;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief returns nonzero if the socket is open
|
||||
*/
|
||||
int ssh_socket_is_open(ssh_socket s) {
|
||||
return s->fd != SSH_INVALID_SOCKET;
|
||||
int ssh_socket_is_open(ssh_socket s)
|
||||
{
|
||||
return s->fd != SSH_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@@ -564,29 +572,31 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
|
||||
/** \internal
|
||||
* \brief returns nonzero if the current socket is in the fd_set
|
||||
*/
|
||||
int ssh_socket_fd_isset(ssh_socket s, fd_set *set) {
|
||||
if(s->fd == SSH_INVALID_SOCKET) {
|
||||
return 0;
|
||||
}
|
||||
return FD_ISSET(s->fd,set);
|
||||
int ssh_socket_fd_isset(ssh_socket s, fd_set *set)
|
||||
{
|
||||
if(s->fd == SSH_INVALID_SOCKET) {
|
||||
return 0;
|
||||
}
|
||||
return FD_ISSET(s->fd,set);
|
||||
}
|
||||
|
||||
/** \internal
|
||||
* \brief sets the current fd in a fd_set and updates the max_fd
|
||||
*/
|
||||
|
||||
void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) {
|
||||
if (s->fd == SSH_INVALID_SOCKET) {
|
||||
return;
|
||||
}
|
||||
void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd)
|
||||
{
|
||||
if (s->fd == SSH_INVALID_SOCKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
FD_SET(s->fd,set);
|
||||
FD_SET(s->fd,set);
|
||||
|
||||
if (s->fd >= 0 &&
|
||||
s->fd >= *max_fd &&
|
||||
s->fd != SSH_INVALID_SOCKET) {
|
||||
*max_fd = s->fd + 1;
|
||||
}
|
||||
if (s->fd >= 0 &&
|
||||
s->fd >= *max_fd &&
|
||||
s->fd != SSH_INVALID_SOCKET) {
|
||||
*max_fd = s->fd + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** \internal
|
||||
@@ -594,16 +604,17 @@ void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) {
|
||||
* \returns SSH_OK, or SSH_ERROR
|
||||
* \warning has no effect on socket before a flush
|
||||
*/
|
||||
int ssh_socket_write(ssh_socket s, const void *buffer, int len) {
|
||||
if(len > 0) {
|
||||
if (ssh_buffer_add_data(s->out_buffer, buffer, len) < 0) {
|
||||
ssh_set_error_oom(s->session);
|
||||
return SSH_ERROR;
|
||||
int ssh_socket_write(ssh_socket s, const void *buffer, int len)
|
||||
{
|
||||
if (len > 0) {
|
||||
if (ssh_buffer_add_data(s->out_buffer, buffer, len) < 0) {
|
||||
ssh_set_error_oom(s->session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ssh_socket_nonblocking_flush(s);
|
||||
}
|
||||
ssh_socket_nonblocking_flush(s);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -685,24 +696,29 @@ int ssh_socket_nonblocking_flush(ssh_socket s)
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
void ssh_socket_set_write_wontblock(ssh_socket s) {
|
||||
s->write_wontblock = 1;
|
||||
void ssh_socket_set_write_wontblock(ssh_socket s)
|
||||
{
|
||||
s->write_wontblock = 1;
|
||||
}
|
||||
|
||||
void ssh_socket_set_read_wontblock(ssh_socket s) {
|
||||
s->read_wontblock = 1;
|
||||
void ssh_socket_set_read_wontblock(ssh_socket s)
|
||||
{
|
||||
s->read_wontblock = 1;
|
||||
}
|
||||
|
||||
void ssh_socket_set_except(ssh_socket s) {
|
||||
s->data_except = 1;
|
||||
void ssh_socket_set_except(ssh_socket s)
|
||||
{
|
||||
s->data_except = 1;
|
||||
}
|
||||
|
||||
int ssh_socket_data_available(ssh_socket s) {
|
||||
return s->read_wontblock;
|
||||
int ssh_socket_data_available(ssh_socket s)
|
||||
{
|
||||
return s->read_wontblock;
|
||||
}
|
||||
|
||||
int ssh_socket_data_writable(ssh_socket s) {
|
||||
return s->write_wontblock;
|
||||
int ssh_socket_data_writable(ssh_socket s)
|
||||
{
|
||||
return s->write_wontblock;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -710,60 +726,69 @@ int ssh_socket_data_writable(ssh_socket s) {
|
||||
* @param s the socket
|
||||
* @returns numbers of bytes buffered, or 0 if the socket isn't connected
|
||||
*/
|
||||
int ssh_socket_buffered_write_bytes(ssh_socket s){
|
||||
if(s==NULL || s->out_buffer == NULL)
|
||||
return 0;
|
||||
return ssh_buffer_get_len(s->out_buffer);
|
||||
int ssh_socket_buffered_write_bytes(ssh_socket s)
|
||||
{
|
||||
if (s==NULL || s->out_buffer == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ssh_buffer_get_len(s->out_buffer);
|
||||
}
|
||||
|
||||
|
||||
int ssh_socket_get_status(ssh_socket s) {
|
||||
int r = 0;
|
||||
int ssh_socket_get_status(ssh_socket s)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (ssh_buffer_get_len(s->in_buffer) > 0) {
|
||||
r |= SSH_READ_PENDING;
|
||||
}
|
||||
if (ssh_buffer_get_len(s->in_buffer) > 0) {
|
||||
r |= SSH_READ_PENDING;
|
||||
}
|
||||
|
||||
if (ssh_buffer_get_len(s->out_buffer) > 0) {
|
||||
r |= SSH_WRITE_PENDING;
|
||||
}
|
||||
if (ssh_buffer_get_len(s->out_buffer) > 0) {
|
||||
r |= SSH_WRITE_PENDING;
|
||||
}
|
||||
|
||||
if (s->data_except) {
|
||||
r |= SSH_CLOSED_ERROR;
|
||||
}
|
||||
if (s->data_except) {
|
||||
r |= SSH_CLOSED_ERROR;
|
||||
}
|
||||
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
int ssh_socket_get_poll_flags(ssh_socket s) {
|
||||
int r = 0;
|
||||
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLIN) > 0) {
|
||||
r |= SSH_READ_PENDING;
|
||||
}
|
||||
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLOUT) > 0) {
|
||||
r |= SSH_WRITE_PENDING;
|
||||
}
|
||||
return r;
|
||||
int ssh_socket_get_poll_flags(ssh_socket s)
|
||||
{
|
||||
int r = 0;
|
||||
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLIN) > 0) {
|
||||
r |= SSH_READ_PENDING;
|
||||
}
|
||||
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLOUT) > 0) {
|
||||
r |= SSH_WRITE_PENDING;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int ssh_socket_set_nonblocking(socket_t fd) {
|
||||
u_long nonblocking = 1;
|
||||
return ioctlsocket(fd, FIONBIO, &nonblocking);
|
||||
int ssh_socket_set_nonblocking(socket_t fd)
|
||||
{
|
||||
u_long nonblocking = 1;
|
||||
return ioctlsocket(fd, FIONBIO, &nonblocking);
|
||||
}
|
||||
|
||||
int ssh_socket_set_blocking(socket_t fd) {
|
||||
u_long nonblocking = 0;
|
||||
return ioctlsocket(fd, FIONBIO, &nonblocking);
|
||||
int ssh_socket_set_blocking(socket_t fd)
|
||||
{
|
||||
u_long nonblocking = 0;
|
||||
return ioctlsocket(fd, FIONBIO, &nonblocking);
|
||||
}
|
||||
|
||||
#else /* _WIN32 */
|
||||
int ssh_socket_set_nonblocking(socket_t fd) {
|
||||
return fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
int ssh_socket_set_nonblocking(socket_t fd)
|
||||
{
|
||||
return fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
}
|
||||
|
||||
int ssh_socket_set_blocking(socket_t fd) {
|
||||
return fcntl(fd, F_SETFL, 0);
|
||||
int ssh_socket_set_blocking(socket_t fd)
|
||||
{
|
||||
return fcntl(fd, F_SETFL, 0);
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
@@ -782,21 +807,24 @@ int ssh_socket_set_blocking(socket_t fd) {
|
||||
* which is problematic for hosts having DNS fail-over.
|
||||
*/
|
||||
|
||||
int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr){
|
||||
socket_t fd;
|
||||
|
||||
if(s->state != SSH_SOCKET_NONE) {
|
||||
ssh_set_error(s->session, SSH_FATAL,
|
||||
"ssh_socket_connect called on socket not unconnected");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
fd=ssh_connect_host_nonblocking(s->session,host,bind_addr,port);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd);
|
||||
if(fd == SSH_INVALID_SOCKET)
|
||||
return SSH_ERROR;
|
||||
ssh_socket_set_fd(s,fd);
|
||||
|
||||
return SSH_OK;
|
||||
int
|
||||
ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr)
|
||||
{
|
||||
socket_t fd;
|
||||
|
||||
if (s->state != SSH_SOCKET_NONE) {
|
||||
ssh_set_error(s->session, SSH_FATAL,
|
||||
"ssh_socket_connect called on socket not unconnected");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
fd = ssh_connect_host_nonblocking(s->session, host, bind_addr, port);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Nonblocking connection socket: %d", fd);
|
||||
if (fd == SSH_INVALID_SOCKET) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ssh_socket_set_fd(s,fd);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -807,16 +835,26 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin
|
||||
* @param in input file descriptor
|
||||
* @param out output file descriptor
|
||||
*/
|
||||
void ssh_execute_command(const char *command, socket_t in, socket_t out){
|
||||
const char *args[]={"/bin/sh","-c",command,NULL};
|
||||
/* redirect in and out to stdin, stdout and stderr */
|
||||
dup2(in, 0);
|
||||
dup2(out,1);
|
||||
dup2(out,2);
|
||||
close(in);
|
||||
close(out);
|
||||
execv(args[0],(char * const *)args);
|
||||
exit(1);
|
||||
void
|
||||
ssh_execute_command(const char *command, socket_t in, socket_t out)
|
||||
{
|
||||
const char *args[] = {"/bin/sh", "-c", command, NULL};
|
||||
/* Prepare /dev/null socket for the stderr redirection */
|
||||
int devnull = open("/dev/null", O_WRONLY);
|
||||
if (devnull == -1) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Failed to open stderr");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* redirect in and out to stdin, stdout */
|
||||
dup2(in, 0);
|
||||
dup2(out, 1);
|
||||
/* Ignore anything on the stderr */
|
||||
dup2(devnull, STDERR_FILENO);
|
||||
close(in);
|
||||
close(out);
|
||||
execv(args[0], (char * const *)args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -829,37 +867,39 @@ void ssh_execute_command(const char *command, socket_t in, socket_t out){
|
||||
* @returns SSH_ERROR error while executing the command.
|
||||
*/
|
||||
|
||||
int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){
|
||||
socket_t pair[2];
|
||||
int pid;
|
||||
int rc;
|
||||
int
|
||||
ssh_socket_connect_proxycommand(ssh_socket s, const char *command)
|
||||
{
|
||||
socket_t pair[2];
|
||||
int pid;
|
||||
int rc;
|
||||
|
||||
if (s->state != SSH_SOCKET_NONE) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (s->state != SSH_SOCKET_NONE) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
|
||||
if (rc < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
|
||||
if (rc < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,"Executing proxycommand '%s'",command);
|
||||
pid = fork();
|
||||
if(pid == 0){
|
||||
ssh_execute_command(command,pair[0],pair[0]);
|
||||
}
|
||||
close(pair[0]);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]);
|
||||
ssh_socket_set_fd(s, pair[1]);
|
||||
s->state=SSH_SOCKET_CONNECTED;
|
||||
s->fd_is_socket=0;
|
||||
/* POLLOUT is the event to wait for in a nonblocking connect */
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLIN | POLLOUT);
|
||||
if(s->callbacks && s->callbacks->connected) {
|
||||
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Executing proxycommand '%s'", command);
|
||||
pid = fork();
|
||||
if(pid == 0) {
|
||||
ssh_execute_command(command, pair[0], pair[0]);
|
||||
}
|
||||
close(pair[0]);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]);
|
||||
ssh_socket_set_fd(s, pair[1]);
|
||||
s->state=SSH_SOCKET_CONNECTED;
|
||||
s->fd_is_socket=0;
|
||||
/* POLLOUT is the event to wait for in a nonblocking connect */
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLIN | POLLOUT);
|
||||
if (s->callbacks && s->callbacks->connected) {
|
||||
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK, 0, s->callbacks->userdata);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
152
src/token.c
152
src/token.c
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/token.h"
|
||||
@@ -175,7 +176,7 @@ char *ssh_find_matching(const char *available_list,
|
||||
|
||||
for (i = 0; p_tok->tokens[i]; i++) {
|
||||
for (j = 0; a_tok->tokens[j]; j++) {
|
||||
if (strcmp(a_tok->tokens[j], p_tok->tokens[i]) == 0){
|
||||
if (strcmp(a_tok->tokens[j], p_tok->tokens[i]) == 0) {
|
||||
ret = strdup(a_tok->tokens[j]);
|
||||
goto out;
|
||||
}
|
||||
@@ -260,3 +261,152 @@ out:
|
||||
ssh_tokens_free(p_tok);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Given a string containing a list of elements, remove all duplicates
|
||||
* and return in a newly allocated string.
|
||||
*
|
||||
* @param[in] list The list to be freed of duplicates
|
||||
*
|
||||
* @return A newly allocated copy of the string free of duplicates; NULL in
|
||||
* case of error.
|
||||
*/
|
||||
char *ssh_remove_duplicates(const char *list)
|
||||
{
|
||||
struct ssh_tokens_st *tok = NULL;
|
||||
|
||||
size_t i, j, num_tokens, max_len;
|
||||
char *ret = NULL;
|
||||
bool *should_copy = NULL, need_comma = false;
|
||||
|
||||
if (list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The maximum number of tokens is the size of the list */
|
||||
max_len = strlen(list);
|
||||
if (max_len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add space for ending '\0' */
|
||||
max_len++;
|
||||
|
||||
tok = ssh_tokenize(list, ',');
|
||||
if ((tok == NULL) || (tok->tokens == NULL) || (tok->tokens[0] == NULL)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
should_copy = calloc(1, max_len);
|
||||
if (should_copy == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strlen(tok->tokens[0]) > 0) {
|
||||
should_copy[0] = true;
|
||||
}
|
||||
|
||||
for (i = 1; tok->tokens[i]; i++) {
|
||||
for (j = 0; j < i; j++) {
|
||||
if (strcmp(tok->tokens[i], tok->tokens[j]) == 0) {
|
||||
/* Found a duplicate; do not copy */
|
||||
should_copy[i] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No matching token before */
|
||||
if (j == i) {
|
||||
/* Only copy if it is not an empty string */
|
||||
if (strlen(tok->tokens[i]) > 0) {
|
||||
should_copy[i] = true;
|
||||
} else {
|
||||
should_copy[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
num_tokens = i;
|
||||
|
||||
ret = calloc(1, max_len);
|
||||
if (ret == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_tokens; i++) {
|
||||
if (should_copy[i]) {
|
||||
if (need_comma) {
|
||||
strncat(ret, ",", (max_len - strlen(ret) - 1));
|
||||
}
|
||||
strncat(ret, tok->tokens[i], (max_len - strlen(ret) - 1));
|
||||
need_comma = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no comma is needed, nothing was copied */
|
||||
if (!need_comma) {
|
||||
SAFE_FREE(ret);
|
||||
}
|
||||
|
||||
out:
|
||||
SAFE_FREE(should_copy);
|
||||
ssh_tokens_free(tok);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Given two strings containing lists of tokens, return a newly
|
||||
* allocated string containing all the elements of the first list appended with
|
||||
* all the elements of the second list, without duplicates. The order of the
|
||||
* elements will be preserved.
|
||||
*
|
||||
* @param[in] list The first list
|
||||
* @param[in] appended_list The list to be appended
|
||||
*
|
||||
* @return A newly allocated copy list containing all the elements of the
|
||||
* kept_list appended with the elements of the appended_list without duplicates;
|
||||
* NULL in case of error.
|
||||
*/
|
||||
char *ssh_append_without_duplicates(const char *list,
|
||||
const char *appended_list)
|
||||
{
|
||||
size_t concat_len = 0;
|
||||
char *ret = NULL, *concat = NULL;
|
||||
|
||||
if (list != NULL) {
|
||||
concat_len = strlen(list);
|
||||
}
|
||||
|
||||
if (appended_list != NULL) {
|
||||
concat_len += strlen(appended_list);
|
||||
}
|
||||
|
||||
if (concat_len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add room for ending '\0' and for middle ',' */
|
||||
concat_len += 2;
|
||||
concat = calloc(1, concat_len);
|
||||
if (concat == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (list != NULL) {
|
||||
strcpy(concat, list);
|
||||
strncat(concat, ",", concat_len - strlen(concat) - 1);
|
||||
}
|
||||
if (appended_list != NULL) {
|
||||
strncat(concat, appended_list, concat_len - strlen(concat) - 1);
|
||||
}
|
||||
|
||||
ret = ssh_remove_duplicates(concat);
|
||||
|
||||
SAFE_FREE(concat);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -67,8 +67,8 @@ if (CLIENT_TESTING)
|
||||
find_program(SSH_EXECUTABLE NAMES ssh)
|
||||
if (SSH_EXECUTABLE)
|
||||
execute_process(COMMAND ${SSH_EXECUTABLE} -V ERROR_VARIABLE OPENSSH_VERSION_STR)
|
||||
string(REGEX REPLACE "^OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
|
||||
string(REGEX REPLACE "^OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
|
||||
string(REGEX REPLACE "^.*OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
|
||||
string(REGEX REPLACE "^.*OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
|
||||
add_definitions(-DOPENSSH_VERSION_MAJOR=${OPENSSH_VERSION_MAJOR} -DOPENSSH_VERSION_MINOR=${OPENSSH_VERSION_MINOR})
|
||||
endif()
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ set(LIBSSH_CLIENT_TESTS
|
||||
torture_knownhosts_verify
|
||||
torture_proxycommand
|
||||
torture_session
|
||||
torture_request_env)
|
||||
torture_request_env
|
||||
torture_client_global_requests)
|
||||
|
||||
if (DEFAULT_C_NO_DEPRECATION_FLAGS)
|
||||
set_source_files_properties(torture_knownhosts.c
|
||||
|
||||
152
tests/client/torture_client_global_requests.c
Normal file
152
tests/client/torture_client_global_requests.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* torture_client_global_requests.c - Tests for client global requests
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
*
|
||||
* 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"
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#include "torture.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/channels.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
|
||||
static int sshd_setup(void **state)
|
||||
{
|
||||
torture_setup_sshd_server(state, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sshd_teardown(void **state)
|
||||
{
|
||||
torture_teardown_sshd_server(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_setup(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
int verbosity = torture_libssh_verbosity();
|
||||
struct passwd *pwd;
|
||||
bool b = false;
|
||||
int rc;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
rc = setuid(pwd->pw_uid);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
s->ssh.session = ssh_new();
|
||||
assert_non_null(s->ssh.session);
|
||||
|
||||
ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
|
||||
/* Make sure no other configuration options from system will get used */
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_teardown(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
|
||||
ssh_disconnect(s->ssh.session);
|
||||
ssh_free(s->ssh.session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int authenticate(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_BOB);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_userauth_password(session, NULL, TORTURE_SSH_USER_BOB_PASSWORD);
|
||||
assert_int_equal(rc, SSH_AUTH_SUCCESS);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void torture_unknown_request(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
ssh_channel channel;
|
||||
int rc;
|
||||
|
||||
rc = authenticate(state);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
/* Request asking for reply */
|
||||
rc = ssh_global_request(session, "unknown-request-00@test.com", NULL, 1);
|
||||
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||
|
||||
/* Request and don't ask for reply */
|
||||
rc = ssh_global_request(session, "another-bad-req-00@test.com", NULL, 0);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
/* Open channel to make sure the session is still working */
|
||||
channel = ssh_channel_new(session);
|
||||
assert_non_null(channel);
|
||||
|
||||
rc = ssh_channel_open_session(channel);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
ssh_channel_close(channel);
|
||||
}
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
int rc;
|
||||
struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test_setup_teardown(torture_unknown_request,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
torture_filter_tests(tests);
|
||||
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
|
||||
ssh_finalize();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "session.c"
|
||||
#include "known_hosts.c"
|
||||
|
||||
#define TORTURE_KNOWN_HOSTS_FILE "libssh_torture_knownhosts"
|
||||
#define TMP_FILE_TEMPLATE "known_hosts_XXXXXX"
|
||||
|
||||
#define BADRSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQChm5" \
|
||||
"a6Av65O8cKtx5YXOnui3wJnYE6A6J/I4kZSAibbn14Jcl+34VJQwv96f25AxNmo" \
|
||||
@@ -62,6 +62,7 @@ static int session_setup(void **state)
|
||||
struct torture_state *s = *state;
|
||||
int verbosity = torture_libssh_verbosity();
|
||||
struct passwd *pwd;
|
||||
bool process_config = false;
|
||||
int rc;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
@@ -74,8 +75,9 @@ static int session_setup(void **state)
|
||||
assert_non_null(s->ssh.session);
|
||||
|
||||
ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG,
|
||||
&process_config);
|
||||
ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
|
||||
ssh_options_set(s->ssh.session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
|
||||
|
||||
return 0;
|
||||
@@ -84,19 +86,10 @@ static int session_setup(void **state)
|
||||
static int session_teardown(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
char known_hosts_file[1024];
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
|
||||
ssh_disconnect(s->ssh.session);
|
||||
ssh_free(s->ssh.session);
|
||||
|
||||
unlink(known_hosts_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -104,17 +97,22 @@ static int session_teardown(void **state)
|
||||
static void torture_knownhosts_port(void **state) {
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024];
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
char buffer[200];
|
||||
char *p;
|
||||
FILE *file;
|
||||
int rc;
|
||||
bool process_config = false;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -140,8 +138,10 @@ static void torture_knownhosts_port(void **state) {
|
||||
/* Now, connect back to the ssh server and verify the known host line */
|
||||
s->ssh.session = session = ssh_new();
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
free(known_hosts_file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -155,16 +155,20 @@ static void torture_knownhosts_wildcard(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024];
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
const char *key = NULL;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
file = fopen(known_hosts_file, "w");
|
||||
assert_non_null(file);
|
||||
@@ -176,6 +180,7 @@ static void torture_knownhosts_wildcard(void **state)
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
free(known_hosts_file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -188,16 +193,20 @@ static void torture_knownhosts_standard_port(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024];
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
const char *key = NULL;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
file = fopen(known_hosts_file, "w");
|
||||
assert_non_null(file);
|
||||
@@ -209,6 +218,7 @@ static void torture_knownhosts_standard_port(void **state)
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
free(known_hosts_file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -220,15 +230,19 @@ static void torture_knownhosts_standard_port(void **state)
|
||||
static void torture_knownhosts_fail(void **state) {
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024];
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -238,6 +252,7 @@ static void torture_knownhosts_fail(void **state) {
|
||||
|
||||
file = fopen(known_hosts_file, "w");
|
||||
assert_non_null(file);
|
||||
free(known_hosts_file);
|
||||
|
||||
fprintf(file, "127.0.0.10 ssh-rsa %s\n", BADRSA);
|
||||
fclose(file);
|
||||
@@ -252,15 +267,19 @@ static void torture_knownhosts_fail(void **state) {
|
||||
static void torture_knownhosts_other(void **state) {
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024];
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -270,6 +289,8 @@ static void torture_knownhosts_other(void **state) {
|
||||
|
||||
file = fopen(known_hosts_file, "w");
|
||||
assert_non_null(file);
|
||||
free(known_hosts_file);
|
||||
|
||||
fprintf(file, "127.0.0.10 ssh-rsa %s\n", BADRSA);
|
||||
fclose(file);
|
||||
|
||||
@@ -283,14 +304,18 @@ static void torture_knownhosts_other(void **state) {
|
||||
static void torture_knownhosts_other_auto(void **state) {
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024];
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -333,20 +358,25 @@ static void torture_knownhosts_other_auto(void **state) {
|
||||
assert_int_equal(rc, SSH_SERVER_KNOWN_OK);
|
||||
|
||||
/* session will be freed by session_teardown() */
|
||||
free(known_hosts_file);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_conflict(void **state) {
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024];
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -393,6 +423,7 @@ static void torture_knownhosts_conflict(void **state) {
|
||||
assert_int_equal(rc, SSH_SERVER_KNOWN_OK);
|
||||
|
||||
/* session will be freed by session_teardown() */
|
||||
free(known_hosts_file);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_no_hostkeychecking(void **state)
|
||||
@@ -400,19 +431,24 @@ static void torture_knownhosts_no_hostkeychecking(void **state)
|
||||
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024] = {0};
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
enum ssh_known_hosts_e found;
|
||||
int strict_host_key_checking = 0;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
free(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ecdsa-sha2-nistp521");
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
@@ -31,9 +31,17 @@
|
||||
|
||||
#include "knownhosts.c"
|
||||
|
||||
#define TORTURE_KNOWN_HOSTS_FILE "libssh_torture_knownhosts"
|
||||
#define TMP_FILE_TEMPLATE "known_hosts_XXXXXX"
|
||||
|
||||
#define BAD_RSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQDXvXuawzaArEwkLIXTz/EWywLOCtqQL3P9yKkrhz6AplXP2PhOh5pyxa1VfGKe453jNeYBJ0ROto3BshXgZXbo86oLXTkbe0gO5xi3r5WjXxjOFvRRTLot5fPLNDOv9+TnsPmkNn0iIeyPnfrcPIyjWt5zSWUfkNC8oNHxsiSshjpbJvTXSDipukpUy41d7jg4uWGuonMTF7yu7HfuHqq7lhb0WlwSpfbqAbfYARBddcdcARyhix4RMWZZqVY20H3Vsjq8bjKC+NJXFce1PRg+qcOWQdlXEei4dkzAvHvfQRx1TjzkrBZ6B6thmZtyeb9IsiB0tg2g0JN2VTAGkxqp"
|
||||
#define BAD_RSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQDXvXuawzaArEwkLIXTz/EWywLOC" \
|
||||
"tqQL3P9yKkrhz6AplXP2PhOh5pyxa1VfGKe453jNeYBJ0ROto3BshXgZX" \
|
||||
"bo86oLXTkbe0gO5xi3r5WjXxjOFvRRTLot5fPLNDOv9+TnsPmkNn0iIey" \
|
||||
"PnfrcPIyjWt5zSWUfkNC8oNHxsiSshjpbJvTXSDipukpUy41d7jg4uWGu" \
|
||||
"onMTF7yu7HfuHqq7lhb0WlwSpfbqAbfYARBddcdcARyhix4RMWZZqVY20" \
|
||||
"H3Vsjq8bjKC+NJXFce1PRg+qcOWQdlXEei4dkzAvHvfQRx1TjzkrBZ6B6" \
|
||||
"thmZtyeb9IsiB0tg2g0JN2VTAGkxqp"
|
||||
|
||||
const char template[] = "temp_dir_XXXXXX";
|
||||
|
||||
static int sshd_group_setup(void **state)
|
||||
{
|
||||
@@ -55,6 +63,8 @@ static int session_setup(void **state)
|
||||
struct passwd *pwd;
|
||||
int rc;
|
||||
|
||||
bool process_config = false;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
@@ -67,6 +77,10 @@ static int session_setup(void **state)
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG,
|
||||
&process_config);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
@@ -81,19 +95,9 @@ static int session_setup(void **state)
|
||||
static int session_teardown(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
char known_hosts_file[1024];
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
|
||||
ssh_disconnect(s->ssh.session);
|
||||
ssh_free(s->ssh.session);
|
||||
|
||||
unlink(known_hosts_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -147,15 +151,19 @@ static void torture_knownhosts_precheck(void **state)
|
||||
struct ssh_iterator *it = NULL;
|
||||
size_t algo_count;
|
||||
const char *algo = NULL;
|
||||
char known_hosts_file[1024] = {0};
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
file = fopen(known_hosts_file, "w");
|
||||
assert_non_null(file);
|
||||
@@ -175,6 +183,7 @@ static void torture_knownhosts_precheck(void **state)
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
free(known_hosts_file);
|
||||
|
||||
algo_list = ssh_known_hosts_get_algorithms(session);
|
||||
assert_non_null(algo_list);
|
||||
@@ -212,15 +221,19 @@ static void torture_knownhosts_duplicate(void **state)
|
||||
struct ssh_iterator *it = NULL;
|
||||
size_t algo_count;
|
||||
const char *algo = NULL;
|
||||
char known_hosts_file[1024] = {0};
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
file = fopen(known_hosts_file, "w");
|
||||
assert_non_null(file);
|
||||
@@ -240,6 +253,7 @@ static void torture_knownhosts_duplicate(void **state)
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
free(known_hosts_file);
|
||||
|
||||
algo_list = ssh_known_hosts_get_algorithms(session);
|
||||
assert_non_null(algo_list);
|
||||
@@ -259,16 +273,20 @@ static void torture_knownhosts_other(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024] = {0};
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
enum ssh_known_hosts_e found;
|
||||
FILE *file = NULL;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -282,6 +300,7 @@ static void torture_knownhosts_other(void **state)
|
||||
"127.0.0.10 %s\n",
|
||||
torture_get_testkey_pub(SSH_KEYTYPE_RSA));
|
||||
fclose(file);
|
||||
free(known_hosts_file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -294,15 +313,19 @@ static void torture_knownhosts_unknown(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024] = {0};
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
enum ssh_known_hosts_e found;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -347,22 +370,27 @@ static void torture_knownhosts_unknown(void **state)
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
|
||||
/* session will be freed by session_teardown() */
|
||||
free(known_hosts_file);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_conflict(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
char known_hosts_file[1024] = {0};
|
||||
char tmp_file[1024] = {0};
|
||||
char *known_hosts_file = NULL;
|
||||
enum ssh_known_hosts_e found;
|
||||
FILE *file = NULL;
|
||||
int rc;
|
||||
|
||||
snprintf(known_hosts_file,
|
||||
sizeof(known_hosts_file),
|
||||
snprintf(tmp_file,
|
||||
sizeof(tmp_file),
|
||||
"%s/%s",
|
||||
s->socket_dir,
|
||||
TORTURE_KNOWN_HOSTS_FILE);
|
||||
TMP_FILE_TEMPLATE);
|
||||
|
||||
known_hosts_file = torture_create_temp_file(tmp_file);
|
||||
assert_non_null(known_hosts_file);
|
||||
|
||||
file = fopen(known_hosts_file, "w");
|
||||
assert_non_null(file);
|
||||
@@ -412,6 +440,44 @@ static void torture_knownhosts_conflict(void **state)
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
|
||||
/* session will be freed by session_teardown() */
|
||||
free(known_hosts_file);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_new_file(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
enum ssh_known_hosts_e found;
|
||||
int rc;
|
||||
|
||||
char new_known_hosts[256];
|
||||
char *tmp_dir = NULL;
|
||||
ssize_t count = 0;
|
||||
|
||||
/* Create a disposable directory */
|
||||
tmp_dir = torture_make_temp_dir(template);
|
||||
assert_non_null(tmp_dir);
|
||||
|
||||
count = snprintf(new_known_hosts, sizeof(new_known_hosts),
|
||||
"%s/a/b/c/d/known_hosts", tmp_dir);
|
||||
assert_return_code(count, errno);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, new_known_hosts);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
rc = ssh_session_update_known_hosts(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
found = ssh_session_is_known_server(session);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
|
||||
/* Cleanup */
|
||||
torture_rmdirs(tmp_dir);
|
||||
|
||||
SAFE_FREE(tmp_dir);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
@@ -438,6 +504,9 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_duplicate,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_new_file,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -65,10 +66,17 @@ static void torture_options_set_proxycommand(void **state)
|
||||
const char *address = torture_server_address(AF_INET);
|
||||
int port = torture_server_port();
|
||||
char command[255] = {0};
|
||||
struct stat sb;
|
||||
int rc;
|
||||
socket_t fd;
|
||||
|
||||
rc = snprintf(command, sizeof(command), "nc %s %d", address, port);
|
||||
rc = stat("/bin/nc", &sb);
|
||||
if (rc != 0 || (sb.st_mode & S_IXOTH) == 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Could not find /bin/nc: Skipping the test");
|
||||
skip();
|
||||
}
|
||||
|
||||
rc = snprintf(command, sizeof(command), "/bin/nc %s %d", address, port);
|
||||
assert_true((size_t)rc < sizeof(command));
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, command);
|
||||
@@ -115,6 +123,28 @@ static void torture_options_set_proxycommand_ssh(void **state)
|
||||
assert_int_equal(rc & O_RDWR, O_RDWR);
|
||||
}
|
||||
|
||||
static void torture_options_set_proxycommand_ssh_stderr(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
ssh_session session = s->ssh.session;
|
||||
const char *address = torture_server_address(AF_INET);
|
||||
char command[255] = {0};
|
||||
int rc;
|
||||
socket_t fd;
|
||||
|
||||
rc = snprintf(command, sizeof(command), "ssh -vvv -W [%%h]:%%p alice@%s", address);
|
||||
assert_true((size_t)rc < sizeof(command));
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, command);
|
||||
assert_int_equal(rc, 0);
|
||||
rc = ssh_connect(session);
|
||||
assert_ssh_return_code(session, rc);
|
||||
fd = ssh_get_fd(session);
|
||||
assert_true(fd != SSH_INVALID_SOCKET);
|
||||
rc = fcntl(fd, F_GETFL);
|
||||
assert_int_equal(rc & O_RDWR, O_RDWR);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct CMUnitTest tests[] = {
|
||||
@@ -127,6 +157,9 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh_stderr,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -252,6 +252,7 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args)
|
||||
size_t kex_len = 0;
|
||||
const char *all_ciphers = NULL;
|
||||
const uint64_t rekey_data_limit = args->rekey_data_limit;
|
||||
bool process_config = false;
|
||||
|
||||
pkd_state.eof_received = 0;
|
||||
pkd_state.close_received = 0;
|
||||
@@ -291,6 +292,13 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args)
|
||||
goto outclose;
|
||||
}
|
||||
|
||||
rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_PROCESS_CONFIG,
|
||||
&process_config);
|
||||
if (rc != 0) {
|
||||
pkderr("ssh_bind_options_set process config: %s\n", ssh_get_error(b));
|
||||
goto outclose;
|
||||
}
|
||||
|
||||
if (!ssh_fips_mode()) {
|
||||
/* Add methods not enabled by default */
|
||||
#define GEX_SHA1 "diffie-hellman-group-exchange-sha1"
|
||||
|
||||
@@ -261,7 +261,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
|
||||
f(client, ecdsa_256_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_256, teardown) \
|
||||
f(client, ecdsa_384_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_384, teardown) \
|
||||
f(client, ecdsa_521_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_521, teardown)
|
||||
#elif /* !defined(WITH_GEX) */
|
||||
#else /* !defined(WITH_GEX) */
|
||||
#define PKDTESTS_KEX_FIPS(f, client, kexcmd) \
|
||||
f(client, rsa_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256"), setup_rsa, teardown) \
|
||||
f(client, rsa_ecdh_sha2_nistp384, kexcmd("ecdh-sha2-nistp384"), setup_rsa, teardown) \
|
||||
|
||||
@@ -73,7 +73,9 @@ int run_server(struct server_state_st *state)
|
||||
ssh_bind sshbind = NULL;
|
||||
ssh_event event = NULL;
|
||||
|
||||
struct sigaction sa = {0};
|
||||
struct sigaction sa = {
|
||||
.sa_flags = 0
|
||||
};
|
||||
|
||||
int rc;
|
||||
|
||||
|
||||
@@ -473,6 +473,50 @@ static void torture_server_hostkey_mismatch(void **state)
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
}
|
||||
|
||||
static void torture_server_unknown_global_request(void **state)
|
||||
{
|
||||
struct test_server_st *tss = *state;
|
||||
struct torture_state *s = NULL;
|
||||
ssh_session session = NULL;
|
||||
ssh_channel channel;
|
||||
int rc;
|
||||
|
||||
assert_non_null(tss);
|
||||
|
||||
s = tss->state;
|
||||
assert_non_null(s);
|
||||
|
||||
session = s->ssh.session;
|
||||
assert_non_null(session);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
/* Using the default password for the server */
|
||||
rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD);
|
||||
assert_int_equal(rc, SSH_AUTH_SUCCESS);
|
||||
|
||||
/* Request asking for reply */
|
||||
rc = ssh_global_request(session, "unknown-request-00@test.com", NULL, 1);
|
||||
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||
|
||||
/* Request and don't ask for reply */
|
||||
rc = ssh_global_request(session, "another-bad-req-00@test.com", NULL, 0);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
/* Open channel to make sure the session is still working */
|
||||
channel = ssh_channel_new(session);
|
||||
assert_non_null(channel);
|
||||
|
||||
rc = ssh_channel_open_session(channel);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
ssh_channel_close(channel);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct CMUnitTest tests[] = {
|
||||
@@ -488,6 +532,9 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_server_hostkey_mismatch,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_server_unknown_global_request,
|
||||
session_setup,
|
||||
session_teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
@@ -657,9 +657,9 @@ static int session_setup(void **state)
|
||||
assert_non_null(s->ssh.session);
|
||||
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
assert_return_code(s->ssh.session, rc);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
|
||||
assert_return_code(s->ssh.session, rc);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
/* Make sure no other configuration options from system will get used */
|
||||
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b);
|
||||
assert_ssh_return_code(s->ssh.session, rc);
|
||||
|
||||
@@ -430,10 +430,7 @@ static size_t setup_hostkey_files(struct test_server_st *tss)
|
||||
|
||||
hostkey_files[0] = tss->rsa_hostkey;
|
||||
|
||||
#ifndef TEST_ALL_CRYPTO_COMBINATIONS
|
||||
goto end;
|
||||
#endif
|
||||
|
||||
#ifdef TEST_ALL_CRYPTO_COMBINATIONS
|
||||
hostkey_files[1] = tss->ecdsa_256_hostkey;
|
||||
hostkey_files[2] = tss->ecdsa_384_hostkey;
|
||||
hostkey_files[3] = tss->ecdsa_521_hostkey;
|
||||
@@ -448,8 +445,8 @@ static size_t setup_hostkey_files(struct test_server_st *tss)
|
||||
num_hostkey_files++;
|
||||
#endif
|
||||
}
|
||||
#endif /* TEST_ALL_CRYPTO_COMBINATIONS */
|
||||
|
||||
end:
|
||||
return num_hostkey_files;
|
||||
}
|
||||
|
||||
@@ -471,9 +468,6 @@ static void torture_server_config_hostkey(void **state)
|
||||
"HostKey %s\n",
|
||||
hostkey_files[i]);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
@@ -513,9 +507,6 @@ static void torture_server_config_ciphers(void **state)
|
||||
"HostKey %s\nCiphers %s\n",
|
||||
hostkey_files[i], ciphers);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -527,9 +518,6 @@ static void torture_server_config_ciphers(void **state)
|
||||
"HostKey %s\nCiphers %s\n",
|
||||
hostkey_files[i], tokens->tokens[j]);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -574,9 +562,6 @@ static void torture_server_config_macs(void **state)
|
||||
"HostKey %s\nMACs %s\n",
|
||||
hostkey_files[i], macs);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -588,9 +573,6 @@ static void torture_server_config_macs(void **state)
|
||||
"HostKey %s\nMACs %s\n",
|
||||
hostkey_files[i], tokens->tokens[j]);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -635,9 +617,6 @@ static void torture_server_config_kex(void **state)
|
||||
"HostKey %s\nKexAlgorithms %s\n",
|
||||
hostkey_files[i], kex);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -649,9 +628,6 @@ static void torture_server_config_kex(void **state)
|
||||
"HostKey %s\nKexAlgorithms %s\n",
|
||||
hostkey_files[i], tokens->tokens[j]);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -691,9 +667,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostKeyAlgorithms %s\n",
|
||||
hostkey_files[i], allowed);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
@@ -707,9 +680,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostkeyAlgorithms %s\n",
|
||||
tss->ed25519_hostkey, "ssh-ed25519");
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -719,9 +689,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostkeyAlgorithms %s\n",
|
||||
tss->rsa_hostkey, "ssh-rsa");
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
@@ -732,9 +699,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostkeyAlgorithms %s\n",
|
||||
tss->rsa_hostkey, "rsa-sha2-256");
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -744,9 +708,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostkeyAlgorithms %s\n",
|
||||
tss->rsa_hostkey, "rsa-sha2-512");
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -756,9 +717,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostkeyAlgorithms %s\n",
|
||||
tss->ecdsa_256_hostkey, "ecdsa-sha2-nistp256");
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -768,9 +726,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostkeyAlgorithms %s\n",
|
||||
tss->ecdsa_384_hostkey, "ecdsa-sha2-nistp384");
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -780,9 +735,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostkeyAlgorithms %s\n",
|
||||
tss->ecdsa_521_hostkey, "ecdsa-sha2-nistp521");
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
@@ -794,9 +746,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
|
||||
"HostKey %s\nHostkeyAlgorithms %s\n",
|
||||
tss->dsa_hostkey, "ssh-dss");
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
@@ -818,9 +767,6 @@ static void torture_server_config_unknown(void **state)
|
||||
"HostKey %s\nUnknownOption unknown-value1,unknown-value2\n",
|
||||
tss->rsa_hostkey);
|
||||
|
||||
rc = try_config_content(state, config_content, true);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = try_config_content(state, config_content, false);
|
||||
assert_int_equal(rc, 0);
|
||||
}
|
||||
|
||||
@@ -262,6 +262,8 @@ ssh_session torture_ssh_session(struct torture_state *s,
|
||||
int method;
|
||||
int rc;
|
||||
|
||||
bool process_config = false;
|
||||
|
||||
if (host == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -277,6 +279,10 @@ ssh_session torture_ssh_session(struct torture_state *s,
|
||||
}
|
||||
#endif /* WITH_PCAP */
|
||||
|
||||
if (ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
@@ -293,7 +299,8 @@ ssh_session torture_ssh_session(struct torture_state *s,
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity) < 0) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG,
|
||||
&process_config) < 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
||||
@@ -602,7 +602,12 @@ static const char torture_ecdsa521_testkey_cert[] =
|
||||
* ED25519 KEYS
|
||||
****************************************************************************/
|
||||
|
||||
static const char torture_ed25519_private_testkey[] =
|
||||
static const char torture_ed25519_private_pkcs8_testkey[] =
|
||||
"-----BEGIN PRIVATE KEY-----\n"
|
||||
"MC4CAQAwBQYDK2VwBCIEIGBhcqLe61tkqVjIHKEzwB3oINasSHWGbIWXQWcLPmGN\n"
|
||||
"-----END PRIVATE KEY-----\n";
|
||||
|
||||
static const char torture_ed25519_private_openssh_testkey[] =
|
||||
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
||||
"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n"
|
||||
"QyNTUxOQAAACAVlp8bgmIjsrzGC7ZIKBMhCpS1fpJTPgVOjYdz5gIqlwAAAJBzsDN1c7Az\n"
|
||||
@@ -611,16 +616,24 @@ static const char torture_ed25519_private_testkey[] =
|
||||
"lLV+klM+BU6Nh3PmAiqXAAAADGFyaXNAa2FsaXg4NgE=\n"
|
||||
"-----END OPENSSH PRIVATE KEY-----\n";
|
||||
|
||||
static const char torture_ed25519_private_testkey_passphrase[] =
|
||||
static const char torture_ed25519_private_openssh_testkey_passphrase[] =
|
||||
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
||||
"b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABB3FWpQcE\n"
|
||||
"KHKq6PcjkxjmKzAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIOGFVuOyZBL0T+NR\n"
|
||||
"C7qEV9qr6QiGhz2XSXrxuQoU84FgAAAAkBlOVfS5U7FxtBEtxfxQhZjrZAj2z9d4OfGRPl\n"
|
||||
"ZfCnAJNEM3BZ3XCabsujhMkqEs9eptRfj41X6NA8aSFs5JYT+JFVfg470FKtpyUmAibMIo\n"
|
||||
"JzI41zAncFd1x7bAgO5HBDe3xNsV159D+sXRkWB9Tzk0l4F8SZvInheIS7VSbqH7t1+yDB\n"
|
||||
"Y3GsmYTDstmicanQ==\n"
|
||||
"b3BlbnNzaC1rZXktdjEAAAAACmFlczEyOC1jYmMAAAAGYmNyeXB0AAAAGAAAABDYuz+a8i\n"
|
||||
"nb/BgGjQjQtvkUAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBWWnxuCYiOyvMYL\n"
|
||||
"tkgoEyEKlLV+klM+BU6Nh3PmAiqXAAAAkOBxqvzvPSns3TbhjkCayvANI66100OELnpDOm\n"
|
||||
"JBGgXr5q846NkAovH3pmJ4O7qzPLTQ/cm0+959VUODRhM1i96qBg5MTNtV33lf5Y57Klzu\n"
|
||||
"JegbiexcqkHIzriH42K0XSOEpfW8f/rTH7ffjbE/7l8HRNwf7AmcnxLx/d8J8FTBr+8aU7\n"
|
||||
"qMU3xAJ4ixnwhYFg==\n"
|
||||
"-----END OPENSSH PRIVATE KEY-----\n";
|
||||
|
||||
static const char torture_ed25519_private_pkcs8_testkey_passphrase[] =
|
||||
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n"
|
||||
"MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAie1RBk/ub+EwICCAAw\n"
|
||||
"DAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEECRLkPChQx/sZPYLdNJhxMUEQFLj\n"
|
||||
"7nelAdOx3WXIBbCOfOqg3aAn8C5cXPtIQ+fiui1V8wlXXV8RBiuDCC97ScLs91D5\n"
|
||||
"qQhQtw0vgfnq1um/izg=\n"
|
||||
"-----END ENCRYPTED PRIVATE KEY-----\n";
|
||||
|
||||
static const char torture_ed25519_public_testkey[] =
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBWWnxuCYiOyvMYLtkgoEyEKlLV+klM+"
|
||||
"BU6Nh3PmAiqX aris@kalix86";
|
||||
@@ -733,16 +746,19 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
|
||||
return torture_ed25519_public_testkey;
|
||||
} else if (with_passphrase) {
|
||||
if (format == 1) {
|
||||
return torture_ed25519_private_testkey_passphrase;
|
||||
return torture_ed25519_private_openssh_testkey_passphrase;
|
||||
}
|
||||
if (format == 2) {
|
||||
return torture_ed25519_private_pkcs8_testkey_passphrase;
|
||||
}
|
||||
/* ed25519 keys are not available in legacy PEM format */
|
||||
return NULL;
|
||||
}
|
||||
if (format == 1) {
|
||||
return torture_ed25519_private_testkey;
|
||||
return torture_ed25519_private_openssh_testkey;
|
||||
}
|
||||
/* ed25519 keys are not available in legacy PEM format */
|
||||
return NULL;
|
||||
return torture_ed25519_private_pkcs8_testkey;
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
return torture_dsa_testkey_cert;
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
|
||||
@@ -440,6 +440,8 @@ static void torture_config_unknown(void **state) {
|
||||
static void torture_config_match(void **state)
|
||||
{
|
||||
ssh_session session = *state;
|
||||
char *localuser = NULL;
|
||||
char config[1024];
|
||||
int ret = 0;
|
||||
|
||||
/* Without any settings we should get all-matched.com hostname */
|
||||
@@ -531,6 +533,19 @@ static void torture_config_match(void **state)
|
||||
assert_ssh_return_code(session, ret);
|
||||
assert_string_equal(session->opts.host, "canonical.com");
|
||||
|
||||
localuser = ssh_get_local_username();
|
||||
assert_non_null(localuser);
|
||||
snprintf(config, sizeof(config),
|
||||
"Match localuser %s\n"
|
||||
"\tHostName otherhost\n"
|
||||
"", localuser);
|
||||
free(localuser);
|
||||
torture_write_file(LIBSSH_TESTCONFIG10, config);
|
||||
torture_reset_config(session);
|
||||
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
|
||||
assert_ssh_return_code(session, ret);
|
||||
assert_string_equal(session->opts.host, "otherhost");
|
||||
|
||||
/* Try to create some invalid configurations */
|
||||
/* Missing argument to Match*/
|
||||
torture_write_file(LIBSSH_TESTCONFIG10,
|
||||
@@ -550,7 +565,7 @@ static void torture_config_match(void **state)
|
||||
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
|
||||
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
|
||||
|
||||
/* Missing argument to unsupported option localuser */
|
||||
/* Missing argument to option localuser */
|
||||
torture_write_file(LIBSSH_TESTCONFIG10,
|
||||
"Match localuser\n"
|
||||
"\tUser localuser2\n"
|
||||
@@ -559,7 +574,7 @@ static void torture_config_match(void **state)
|
||||
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
|
||||
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
|
||||
|
||||
/* Missing argument to option user*/
|
||||
/* Missing argument to option user */
|
||||
torture_write_file(LIBSSH_TESTCONFIG10,
|
||||
"Match user\n"
|
||||
"\tUser user2\n"
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#define TMP_FILE_NAME "/tmp/known_hosts_XXXXXX"
|
||||
|
||||
const char template[] = "temp_dir_XXXXXX";
|
||||
|
||||
static int setup_knownhosts_file(void **state)
|
||||
{
|
||||
char *tmp_file = NULL;
|
||||
@@ -369,6 +371,140 @@ static void torture_knownhosts_read_file(void **state)
|
||||
ssh_list_free(entry_list);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_get_algorithms_names(void **state)
|
||||
{
|
||||
const char *knownhosts_file = *state;
|
||||
ssh_session session;
|
||||
const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa";
|
||||
char *names = NULL;
|
||||
bool process_config = false;
|
||||
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
/* This makes sure the global configuration file is not processed */
|
||||
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
|
||||
|
||||
names = ssh_known_hosts_get_algorithms_names(session);
|
||||
assert_non_null(names);
|
||||
assert_string_equal(names, expect);
|
||||
|
||||
SAFE_FREE(names);
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_algorithms_wanted(void **state)
|
||||
{
|
||||
const char *knownhosts_file = *state;
|
||||
char *algo_list = NULL;
|
||||
ssh_session session;
|
||||
bool process_config = false;
|
||||
const char *wanted = "ecdsa-sha2-nistp384,ecdsa-sha2-nistp256,"
|
||||
"rsa-sha2-256,ecdsa-sha2-nistp521";
|
||||
const char *expect = "rsa-sha2-256,ecdsa-sha2-nistp384,"
|
||||
"ecdsa-sha2-nistp256,ecdsa-sha2-nistp521";
|
||||
int verbose = 4;
|
||||
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbose);
|
||||
|
||||
/* This makes sure the global configuration file is not processed */
|
||||
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
|
||||
|
||||
/* Set the wanted list of hostkeys, ordered by preference */
|
||||
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
|
||||
|
||||
algo_list = ssh_client_select_hostkeys(session);
|
||||
assert_non_null(algo_list);
|
||||
assert_string_equal(algo_list, expect);
|
||||
free(algo_list);
|
||||
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_algorithms_negative(UNUSED_PARAM(void **state))
|
||||
{
|
||||
const char *wanted = NULL;
|
||||
const char *expect = NULL;
|
||||
|
||||
char *algo_list = NULL;
|
||||
|
||||
char *cwd = NULL;
|
||||
char *tmp_dir = NULL;
|
||||
|
||||
bool process_config = false;
|
||||
int verbose = 4;
|
||||
int rc = 0;
|
||||
|
||||
ssh_session session;
|
||||
/* Create temporary directory */
|
||||
cwd = torture_get_current_working_dir();
|
||||
assert_non_null(cwd);
|
||||
|
||||
tmp_dir = torture_make_temp_dir(template);
|
||||
assert_non_null(tmp_dir);
|
||||
|
||||
rc = torture_change_dir(tmp_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbose);
|
||||
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
|
||||
/* Test with unknown key type in known_hosts */
|
||||
wanted = "rsa-sha2-256";
|
||||
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
|
||||
torture_write_file("unknown_key_type", "localhost unknown AAAABBBBCCCC");
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "unknown_key_type");
|
||||
algo_list = ssh_client_select_hostkeys(session);
|
||||
assert_non_null(algo_list);
|
||||
assert_string_equal(algo_list, wanted);
|
||||
SAFE_FREE(algo_list);
|
||||
|
||||
/* Test with unsupported, but existing types */
|
||||
wanted = "rsa-sha2-256-cert-v01@openssh.com,"
|
||||
"rsa-sha2-512-cert-v01@openssh.com";
|
||||
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
|
||||
algo_list = ssh_client_select_hostkeys(session);
|
||||
assert_null(algo_list);
|
||||
|
||||
/* In FIPS mode, test filtering keys not allowed */
|
||||
if (ssh_fips_mode()) {
|
||||
wanted = "ssh-ed25519,rsa-sha2-256,ssh-rsa";
|
||||
expect = "rsa-sha2-256";
|
||||
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
|
||||
torture_write_file("no_fips", LOCALHOST_DEFAULT_ED25519);
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "no_fips");
|
||||
algo_list = ssh_client_select_hostkeys(session);
|
||||
assert_non_null(algo_list);
|
||||
assert_string_equal(algo_list, expect);
|
||||
SAFE_FREE(algo_list);
|
||||
}
|
||||
|
||||
ssh_free(session);
|
||||
|
||||
/* Teardown */
|
||||
rc = torture_change_dir(cwd);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
rc = torture_rmdirs(tmp_dir);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
SAFE_FREE(tmp_dir);
|
||||
SAFE_FREE(cwd);
|
||||
}
|
||||
|
||||
#ifndef _WIN32 /* There is no /dev/null on Windows */
|
||||
static void torture_knownhosts_host_exists(void **state)
|
||||
{
|
||||
@@ -381,16 +517,22 @@ static void torture_knownhosts_host_exists(void **state)
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
|
||||
|
||||
/* This makes sure the system's known_hosts are not used */
|
||||
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "/dev/null");
|
||||
|
||||
found = ssh_session_has_known_hosts_entry(session);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
assert_true(found == SSH_KNOWN_HOSTS_OK);
|
||||
|
||||
/* This makes sure the check will not fail when the system's known_hosts is
|
||||
* not accessible*/
|
||||
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "./unaccessible");
|
||||
found = ssh_session_has_known_hosts_entry(session);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
|
||||
/* This makes sure the check will fail for an unknown host */
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
|
||||
found = ssh_session_has_known_hosts_entry(session);
|
||||
assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_UNKNOWN);
|
||||
|
||||
ssh_free(session);
|
||||
}
|
||||
@@ -405,27 +547,33 @@ static void torture_knownhosts_host_exists_global(void **state)
|
||||
assert_non_null(session);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
/* This makes sure the user's known_hosts are not used */
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
|
||||
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, knownhosts_file);
|
||||
|
||||
/* This makes sure the user's known_hosts are not used */
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
|
||||
found = ssh_session_has_known_hosts_entry(session);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
assert_true(found == SSH_KNOWN_HOSTS_OK);
|
||||
|
||||
/* This makes sure the check will not fail when the user's known_hosts is
|
||||
* not accessible*/
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "./unaccessible");
|
||||
found = ssh_session_has_known_hosts_entry(session);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
|
||||
|
||||
/* This makes sure the check will fail for an unknown host */
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
|
||||
found = ssh_session_has_known_hosts_entry(session);
|
||||
assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
|
||||
assert_int_equal(found, SSH_KNOWN_HOSTS_UNKNOWN);
|
||||
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void
|
||||
torture_knownhosts_algorithms(void **state)
|
||||
static void torture_knownhosts_algorithms(void **state)
|
||||
{
|
||||
const char *knownhosts_file = *state;
|
||||
char *algo_list = NULL;
|
||||
ssh_session session;
|
||||
bool process_config = false;
|
||||
const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,"
|
||||
"ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,"
|
||||
"ecdsa-sha2-nistp256"
|
||||
@@ -433,10 +581,15 @@ torture_knownhosts_algorithms(void **state)
|
||||
",ssh-dss"
|
||||
#endif
|
||||
;
|
||||
const char *expect_fips = "rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp521,"
|
||||
"ecdsa-sha2-nistp384,ecdsa-sha2-nistp256";
|
||||
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
/* This makes sure the global configuration file is not processed */
|
||||
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
|
||||
/* This makes sure the system's known_hosts are not used */
|
||||
@@ -444,18 +597,22 @@ torture_knownhosts_algorithms(void **state)
|
||||
|
||||
algo_list = ssh_client_select_hostkeys(session);
|
||||
assert_non_null(algo_list);
|
||||
assert_string_equal(algo_list, expect);
|
||||
if (ssh_fips_mode()) {
|
||||
assert_string_equal(algo_list, expect_fips);
|
||||
} else {
|
||||
assert_string_equal(algo_list, expect);
|
||||
}
|
||||
free(algo_list);
|
||||
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void
|
||||
torture_knownhosts_algorithms_global(void **state)
|
||||
static void torture_knownhosts_algorithms_global(void **state)
|
||||
{
|
||||
const char *knownhosts_file = *state;
|
||||
char *algo_list = NULL;
|
||||
ssh_session session;
|
||||
bool process_config = false;
|
||||
const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,"
|
||||
"ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,"
|
||||
"ecdsa-sha2-nistp256"
|
||||
@@ -463,10 +620,15 @@ torture_knownhosts_algorithms_global(void **state)
|
||||
",ssh-dss"
|
||||
#endif
|
||||
;
|
||||
const char *expect_fips = "rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp521,"
|
||||
"ecdsa-sha2-nistp384,ecdsa-sha2-nistp256";
|
||||
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
/* This makes sure the global configuration file is not processed */
|
||||
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
/* This makes sure the current-user's known hosts are not used */
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
|
||||
@@ -474,12 +636,17 @@ torture_knownhosts_algorithms_global(void **state)
|
||||
|
||||
algo_list = ssh_client_select_hostkeys(session);
|
||||
assert_non_null(algo_list);
|
||||
assert_string_equal(algo_list, expect);
|
||||
if (ssh_fips_mode()) {
|
||||
assert_string_equal(algo_list, expect_fips);
|
||||
} else {
|
||||
assert_string_equal(algo_list, expect);
|
||||
}
|
||||
free(algo_list);
|
||||
|
||||
ssh_free(session);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _WIN32 There is no /dev/null on Windows */
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
@@ -498,6 +665,13 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_read_file,
|
||||
setup_knownhosts_file_duplicate,
|
||||
teardown_knownhosts_file),
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_get_algorithms_names,
|
||||
setup_knownhosts_file,
|
||||
teardown_knownhosts_file),
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_algorithms_wanted,
|
||||
setup_knownhosts_file,
|
||||
teardown_knownhosts_file),
|
||||
cmocka_unit_test(torture_knownhosts_algorithms_negative),
|
||||
#ifndef _WIN32
|
||||
cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists,
|
||||
setup_knownhosts_file,
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#define TORTURE_TEST_DIR "/usr/local/bin/truc/much/.."
|
||||
|
||||
const char template[] = "temp_dir_XXXXXX";
|
||||
|
||||
static int setup(void **state)
|
||||
{
|
||||
@@ -192,6 +193,18 @@ static void torture_path_expand_known_hosts(void **state) {
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void torture_path_expand_percent(void **state) {
|
||||
ssh_session session = *state;
|
||||
char *tmp;
|
||||
|
||||
session->opts.sshdir = strdup("/home/guru/.ssh");
|
||||
|
||||
tmp = ssh_path_expand_escape(session, "%d/config%%1");
|
||||
assert_non_null(tmp);
|
||||
assert_string_equal(tmp, "/home/guru/.ssh/config%1");
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static void torture_timeout_elapsed(void **state){
|
||||
struct ssh_timestamp ts;
|
||||
(void) state;
|
||||
@@ -351,6 +364,143 @@ static void torture_ssh_analyze_banner(void **state) {
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void torture_ssh_dir_writeable(UNUSED_PARAM(void **state))
|
||||
{
|
||||
char *tmp_dir = NULL;
|
||||
int rc = 0;
|
||||
FILE *file = NULL;
|
||||
char buffer[256];
|
||||
|
||||
tmp_dir = torture_make_temp_dir(template);
|
||||
assert_non_null(tmp_dir);
|
||||
|
||||
rc = ssh_dir_writeable(tmp_dir);
|
||||
assert_int_equal(rc, 1);
|
||||
|
||||
/* Create a file */
|
||||
snprintf(buffer, sizeof(buffer), "%s/a", tmp_dir);
|
||||
|
||||
file = fopen(buffer, "w");
|
||||
assert_non_null(file);
|
||||
|
||||
fprintf(file, "Hello world!\n");
|
||||
fclose(file);
|
||||
|
||||
/* Negative test for checking a normal file */
|
||||
rc = ssh_dir_writeable(buffer);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
/* Negative test for non existent file */
|
||||
snprintf(buffer, sizeof(buffer), "%s/b", tmp_dir);
|
||||
rc = ssh_dir_writeable(buffer);
|
||||
assert_int_equal(rc, 0);
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Negative test for directory without write permission */
|
||||
rc = ssh_mkdir(buffer, 0400);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
rc = ssh_dir_writeable(buffer);
|
||||
assert_int_equal(rc, 0);
|
||||
#endif
|
||||
|
||||
torture_rmdirs(tmp_dir);
|
||||
|
||||
SAFE_FREE(tmp_dir);
|
||||
}
|
||||
|
||||
static void torture_ssh_mkdirs(UNUSED_PARAM(void **state))
|
||||
{
|
||||
char *tmp_dir = NULL;
|
||||
char *cwd = NULL;
|
||||
char buffer[256];
|
||||
|
||||
ssize_t count = 0;
|
||||
|
||||
int rc;
|
||||
|
||||
/* Get current working directory */
|
||||
cwd = torture_get_current_working_dir();
|
||||
assert_non_null(cwd);
|
||||
|
||||
/* Create a base disposable directory */
|
||||
tmp_dir = torture_make_temp_dir(template);
|
||||
assert_non_null(tmp_dir);
|
||||
|
||||
/* Create a single directory */
|
||||
count = snprintf(buffer, sizeof(buffer), "%s/a", tmp_dir);
|
||||
assert_return_code(count, errno);
|
||||
|
||||
rc = ssh_mkdirs(buffer, 0700);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
rc = ssh_dir_writeable(buffer);
|
||||
assert_int_equal(rc, 1);
|
||||
|
||||
/* Create directories recursively */
|
||||
count = snprintf(buffer, sizeof(buffer), "%s/b/c/d", tmp_dir);
|
||||
assert_return_code(count, errno);
|
||||
|
||||
rc = ssh_mkdirs(buffer, 0700);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
rc = ssh_dir_writeable(buffer);
|
||||
assert_int_equal(rc, 1);
|
||||
|
||||
/* Change directory */
|
||||
rc = torture_change_dir(tmp_dir);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
/* Create single local directory */
|
||||
rc = ssh_mkdirs("e", 0700);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
rc = ssh_dir_writeable("e");
|
||||
assert_int_equal(rc, 1);
|
||||
|
||||
/* Create local directories recursively */
|
||||
rc = ssh_mkdirs("f/g/h", 0700);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
rc = ssh_dir_writeable("f/g/h");
|
||||
assert_int_equal(rc, 1);
|
||||
|
||||
/* Negative test for creating "." directory */
|
||||
rc = ssh_mkdirs(".", 0700);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EINVAL);
|
||||
|
||||
/* Negative test for creating "/" directory */
|
||||
rc = ssh_mkdirs("/", 0700);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EINVAL);
|
||||
|
||||
/* Negative test for creating "" directory */
|
||||
rc = ssh_mkdirs("", 0700);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EINVAL);
|
||||
|
||||
/* Negative test for creating NULL directory */
|
||||
rc = ssh_mkdirs(NULL, 0700);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EINVAL);
|
||||
|
||||
/* Negative test for creating existing directory */
|
||||
rc = ssh_mkdirs("a", 0700);
|
||||
assert_int_equal(rc, -1);
|
||||
assert_int_equal(errno, EEXIST);
|
||||
|
||||
/* Return to original directory */
|
||||
rc = torture_change_dir(cwd);
|
||||
assert_return_code(rc, errno);
|
||||
|
||||
/* Cleanup */
|
||||
torture_rmdirs(tmp_dir);
|
||||
|
||||
SAFE_FREE(tmp_dir);
|
||||
SAFE_FREE(cwd);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
struct CMUnitTest tests[] = {
|
||||
@@ -365,9 +515,12 @@ int torture_run_tests(void) {
|
||||
#endif
|
||||
cmocka_unit_test_setup_teardown(torture_path_expand_escape, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_path_expand_known_hosts, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_path_expand_percent, setup, teardown),
|
||||
cmocka_unit_test(torture_timeout_elapsed),
|
||||
cmocka_unit_test(torture_timeout_update),
|
||||
cmocka_unit_test(torture_ssh_analyze_banner),
|
||||
cmocka_unit_test(torture_ssh_dir_writeable),
|
||||
cmocka_unit_test(torture_ssh_mkdirs),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
@@ -571,6 +571,7 @@ static void torture_options_config_host(void **state) {
|
||||
static void torture_options_config_match(void **state)
|
||||
{
|
||||
ssh_session session = *state;
|
||||
char *localuser = NULL;
|
||||
FILE *config = NULL;
|
||||
int rv;
|
||||
|
||||
@@ -665,11 +666,16 @@ static void torture_options_config_match(void **state)
|
||||
|
||||
session->opts.port = 0;
|
||||
|
||||
/* The Match localuser keyword is ignored */
|
||||
/* The Match localuser keyword */
|
||||
torture_reset_config(session);
|
||||
config = fopen("test_config", "w");
|
||||
assert_non_null(config);
|
||||
fputs("Match originalhost origin\n"
|
||||
fputs("Match localuser ", config);
|
||||
localuser = ssh_get_local_username();
|
||||
assert_non_null(localuser);
|
||||
fputs(localuser, config);
|
||||
free(localuser);
|
||||
fputs("\n"
|
||||
"\tPort 33\n"
|
||||
"Match all\n"
|
||||
"\tPort 34\n",
|
||||
@@ -678,7 +684,7 @@ static void torture_options_config_match(void **state)
|
||||
|
||||
rv = ssh_options_parse_config(session, "test_config");
|
||||
assert_ssh_return_code(session, rv);
|
||||
assert_int_equal(session->opts.port, 34);
|
||||
assert_int_equal(session->opts.port, 33);
|
||||
|
||||
session->opts.port = 0;
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ static void torture_pki_verify_mismatch(void **state)
|
||||
assert_int_equal(import_sig->type, key->type);
|
||||
assert_string_equal(import_sig->type_c, skey_attrs.sig_type_c);
|
||||
|
||||
rc = pki_signature_verify(session,
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
import_sig,
|
||||
pubkey,
|
||||
INPUT,
|
||||
@@ -374,7 +374,7 @@ static void torture_pki_verify_mismatch(void **state)
|
||||
assert_non_null(verify_pubkey);
|
||||
|
||||
/* Should gracefully fail, but not crash */
|
||||
rc = pki_signature_verify(session,
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
sign,
|
||||
verify_pubkey,
|
||||
INPUT,
|
||||
@@ -382,7 +382,7 @@ static void torture_pki_verify_mismatch(void **state)
|
||||
assert_true(rc != SSH_OK);
|
||||
|
||||
/* Try the same with the imported signature */
|
||||
rc = pki_signature_verify(session,
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
import_sig,
|
||||
verify_pubkey,
|
||||
INPUT,
|
||||
@@ -401,7 +401,7 @@ static void torture_pki_verify_mismatch(void **state)
|
||||
assert_string_equal(new_sig->type_c, skey_attrs.sig_type_c);
|
||||
|
||||
/* The verification should not work */
|
||||
rc = pki_signature_verify(session,
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
new_sig,
|
||||
verify_pubkey,
|
||||
INPUT,
|
||||
|
||||
@@ -168,6 +168,68 @@ static void torture_pki_dsa_import_privkey_base64(void **state)
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_dsa_import_privkey_base64_comment(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
ssh_key key = NULL;
|
||||
const char *passphrase = torture_get_testkey_passphrase();
|
||||
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||
const char *key_str = NULL;
|
||||
char *file_str = NULL;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
key_str = torture_get_testkey(SSH_KEYTYPE_DSS, 0);
|
||||
assert_non_null(key_str);
|
||||
|
||||
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str,
|
||||
passphrase,
|
||||
NULL,
|
||||
NULL,
|
||||
&key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
free(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_dsa_import_privkey_base64_whitespace(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
ssh_key key = NULL;
|
||||
const char *passphrase = torture_get_testkey_passphrase();
|
||||
const char *whitespace_str = " \n\t\t\t\t\t\n\n\n\n\n";
|
||||
const char *key_str = NULL;
|
||||
char *file_str = NULL;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
key_str = torture_get_testkey(SSH_KEYTYPE_DSS, 0);
|
||||
assert_non_null(key_str);
|
||||
|
||||
file_str_len = strlen(whitespace_str) + strlen(key_str) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", whitespace_str, key_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str,
|
||||
passphrase,
|
||||
NULL,
|
||||
NULL,
|
||||
&key);
|
||||
assert_true(rc == 0);
|
||||
|
||||
free(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static int test_sign_verify_data(ssh_key key,
|
||||
enum ssh_digest_e hash_type,
|
||||
const unsigned char *input,
|
||||
@@ -747,7 +809,7 @@ static void torture_pki_dsa_generate_key(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
@@ -761,7 +823,7 @@ static void torture_pki_dsa_generate_key(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
@@ -775,7 +837,7 @@ static void torture_pki_dsa_generate_key(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
@@ -806,7 +868,7 @@ static void torture_pki_dsa_cert_verify(void **state)
|
||||
|
||||
sign = pki_do_sign(privkey, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(privkey);
|
||||
@@ -833,6 +895,12 @@ int torture_run_tests(void)
|
||||
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
|
||||
setup_dsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64_comment,
|
||||
setup_dsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64_whitespace,
|
||||
setup_dsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
|
||||
setup_openssh_dsa_key,
|
||||
teardown),
|
||||
|
||||
@@ -241,6 +241,69 @@ static void torture_pki_ecdsa_import_privkey_base64(void **state)
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_ecdsa_import_privkey_base64_comment(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||
char *key_str = NULL, *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
const char *passphrase = torture_get_testkey_passphrase();
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
key_str = torture_pki_read_file(LIBSSH_ECDSA_TESTKEY);
|
||||
assert_non_null(key_str);
|
||||
|
||||
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(key);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
free(key_str);
|
||||
free(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_ecdsa_import_privkey_base64_whitespace(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *whitespace_str = " \n\t\t\t\t\t\n\n\n\n\n";
|
||||
char *key_str = NULL, *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
const char *passphrase = torture_get_testkey_passphrase();
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
key_str = torture_pki_read_file(LIBSSH_ECDSA_TESTKEY);
|
||||
assert_non_null(key_str);
|
||||
|
||||
file_str_len = strlen(whitespace_str) + strlen(key_str) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", whitespace_str, key_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(key);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
free(key_str);
|
||||
free(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
|
||||
static void torture_pki_ecdsa_publickey_from_privatekey(void **state)
|
||||
{
|
||||
int rc;
|
||||
@@ -483,7 +546,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ECDSA_P256);
|
||||
@@ -505,7 +568,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ECDSA_P256);
|
||||
@@ -526,7 +589,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA384);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ECDSA_P384);
|
||||
@@ -548,7 +611,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA384);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ECDSA_P384);
|
||||
@@ -569,7 +632,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA512);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ECDSA_P521);
|
||||
@@ -591,7 +654,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA512);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ECDSA_P521);
|
||||
@@ -633,7 +696,7 @@ static void torture_pki_ecdsa_cert_verify(void **state)
|
||||
|
||||
sign = pki_do_sign(privkey, INPUT, sizeof(INPUT), hash_type);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(privkey);
|
||||
@@ -904,6 +967,24 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
|
||||
setup_ecdsa_key_521,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
|
||||
setup_ecdsa_key_256,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
|
||||
setup_ecdsa_key_384,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
|
||||
setup_ecdsa_key_521,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_whitespace,
|
||||
setup_ecdsa_key_521,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_whitespace,
|
||||
setup_ecdsa_key_521,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_whitespace,
|
||||
setup_ecdsa_key_521,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
|
||||
setup_openssh_ecdsa_key_256,
|
||||
teardown),
|
||||
|
||||
@@ -149,6 +149,84 @@ static void torture_pki_ed25519_import_privkey_base64(void **state)
|
||||
|
||||
}
|
||||
|
||||
static void torture_pki_ed25519_import_privkey_base64_comment(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||
char *key_str = NULL, *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
const char *passphrase = torture_get_testkey_passphrase();
|
||||
enum ssh_keytypes_e type;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
key_str = torture_pki_read_file(LIBSSH_ED25519_TESTKEY);
|
||||
assert_non_null(key_str);
|
||||
|
||||
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(key);
|
||||
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ED25519);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_key_is_public(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
free(key_str);
|
||||
free(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
|
||||
}
|
||||
|
||||
static void torture_pki_ed25519_import_privkey_base64_whitespace(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *whitespace_str = " \n\t\t\t\t\t\n\n\n\n\n";
|
||||
char *key_str = NULL, *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
const char *passphrase = torture_get_testkey_passphrase();
|
||||
enum ssh_keytypes_e type;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
key_str = torture_pki_read_file(LIBSSH_ED25519_TESTKEY);
|
||||
assert_non_null(key_str);
|
||||
|
||||
file_str_len = strlen(whitespace_str) + strlen(key_str) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", whitespace_str, key_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(key);
|
||||
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ED25519);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_key_is_public(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
free(key_str);
|
||||
free(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
|
||||
}
|
||||
|
||||
static void torture_pki_ed25519_import_export_privkey_base64(void **state)
|
||||
{
|
||||
char *b64_key = NULL;
|
||||
@@ -339,19 +417,30 @@ static void torture_pki_ed25519_generate_pubkey_from_privkey(void **state)
|
||||
static void torture_pki_ed25519_generate_key(void **state)
|
||||
{
|
||||
int rc;
|
||||
ssh_key key = NULL;
|
||||
ssh_key key = NULL, pubkey = NULL;
|
||||
ssh_signature sign = NULL;
|
||||
enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
|
||||
const char *type_char = NULL;
|
||||
ssh_session session=ssh_new();
|
||||
uint8_t *raw_sig_data = NULL;
|
||||
(void) state;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
assert_non_null(session);
|
||||
|
||||
rc = ssh_pki_generate(SSH_KEYTYPE_ED25519, 256, &key);
|
||||
assert_true(rc == SSH_OK);
|
||||
assert_non_null(key);
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, HASH, 20, SSH_DIGEST_AUTO);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session,sign,key,HASH,20);
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, HASH, 20);
|
||||
assert_true(rc == SSH_OK);
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_ED25519);
|
||||
@@ -359,12 +448,19 @@ static void torture_pki_ed25519_generate_key(void **state)
|
||||
assert_true(strcmp(type_char, "ssh-ed25519") == 0);
|
||||
|
||||
/* try an invalid signature */
|
||||
(*sign->ed25519_sig)[3]^= 0xff;
|
||||
rc = pki_signature_verify(session,sign,key,HASH,20);
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
raw_sig_data = ssh_string_data(sign->raw_sig);
|
||||
#else
|
||||
raw_sig_data = (uint8_t *)sign->ed25519_sig;
|
||||
#endif
|
||||
assert_non_null(raw_sig_data);
|
||||
(raw_sig_data)[3]^= 0xff;
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, HASH, 20);
|
||||
assert_true(rc == SSH_ERROR);
|
||||
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
|
||||
ssh_free(session);
|
||||
}
|
||||
@@ -377,6 +473,13 @@ static void torture_pki_ed25519_cert_verify(void **state)
|
||||
ssh_session session=ssh_new();
|
||||
(void) state;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
assert_non_null(session);
|
||||
|
||||
rc = ssh_pki_import_privkey_file(LIBSSH_ED25519_TESTKEY,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -391,7 +494,7 @@ static void torture_pki_ed25519_cert_verify(void **state)
|
||||
|
||||
sign = pki_do_sign(privkey, HASH, 20, SSH_DIGEST_AUTO);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, cert, HASH, 20);
|
||||
rc = ssh_pki_signature_verify(session, sign, cert, HASH, 20);
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(privkey);
|
||||
@@ -517,10 +620,12 @@ static void torture_pki_ed25519_sign(void **state)
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
(void)state;
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
sig = ssh_signature_new();
|
||||
assert_non_null(sig);
|
||||
(void)state;
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0);
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
@@ -531,31 +636,157 @@ static void torture_pki_ed25519_sign(void **state)
|
||||
assert_true(rc == SSH_OK);
|
||||
assert_non_null(privkey);
|
||||
|
||||
sig->type = SSH_KEYTYPE_ED25519;
|
||||
rc = pki_ed25519_sign(privkey, sig, HASH, sizeof(HASH));
|
||||
assert_true(rc == SSH_OK);
|
||||
sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
|
||||
assert_non_null(sig);
|
||||
|
||||
blob = pki_signature_to_blob(sig);
|
||||
assert_non_null(blob);
|
||||
|
||||
assert_int_equal(ssh_string_len(blob), sizeof(ref_signature));
|
||||
assert_memory_equal(ssh_string_data(blob), ref_signature, sizeof(ref_signature));
|
||||
/* ssh_print_hexa("signature", ssh_string_data(blob), ssh_string_len(blob)); */
|
||||
assert_memory_equal(ssh_string_data(blob), ref_signature,
|
||||
sizeof(ref_signature));
|
||||
|
||||
ssh_signature_free(sig);
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_STRING_FREE(blob);
|
||||
|
||||
}
|
||||
|
||||
static void torture_pki_ed25519_sign_openssh_privkey_passphrase(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_signature sig = NULL;
|
||||
ssh_string blob = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
(void)state;
|
||||
|
||||
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 1);
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
torture_get_testkey_passphrase(),
|
||||
NULL,
|
||||
NULL,
|
||||
&privkey);
|
||||
assert_true(rc == SSH_OK);
|
||||
assert_non_null(privkey);
|
||||
|
||||
sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
|
||||
assert_non_null(sig);
|
||||
|
||||
blob = pki_signature_to_blob(sig);
|
||||
assert_non_null(blob);
|
||||
assert_int_equal(ssh_string_len(blob), sizeof(ref_signature));
|
||||
assert_memory_equal(ssh_string_data(blob), ref_signature,
|
||||
sizeof(ref_signature));
|
||||
|
||||
ssh_signature_free(sig);
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_STRING_FREE(blob);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
static void torture_pki_ed25519_sign_pkcs8_privkey(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_signature sig = NULL;
|
||||
ssh_string blob = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
(void)state;
|
||||
|
||||
keystring = torture_get_testkey(SSH_KEYTYPE_ED25519, 0);
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&privkey);
|
||||
assert_true(rc == SSH_OK);
|
||||
assert_non_null(privkey);
|
||||
|
||||
sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
|
||||
assert_non_null(sig);
|
||||
|
||||
blob = pki_signature_to_blob(sig);
|
||||
assert_non_null(blob);
|
||||
assert_int_equal(ssh_string_len(blob), sizeof(ref_signature));
|
||||
assert_memory_equal(ssh_string_data(blob), ref_signature,
|
||||
sizeof(ref_signature));
|
||||
|
||||
ssh_signature_free(sig);
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_STRING_FREE(blob);
|
||||
}
|
||||
|
||||
static void torture_pki_ed25519_sign_pkcs8_privkey_passphrase(void **state)
|
||||
{
|
||||
ssh_key privkey = NULL;
|
||||
ssh_signature sig = NULL;
|
||||
ssh_string blob = NULL;
|
||||
const char *keystring = NULL;
|
||||
int rc;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
(void)state;
|
||||
|
||||
keystring = torture_get_testkey(SSH_KEYTYPE_ED25519, 1);
|
||||
rc = ssh_pki_import_privkey_base64(keystring,
|
||||
torture_get_testkey_passphrase(),
|
||||
NULL,
|
||||
NULL,
|
||||
&privkey);
|
||||
assert_true(rc == SSH_OK);
|
||||
assert_non_null(privkey);
|
||||
|
||||
sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
|
||||
assert_non_null(sig);
|
||||
|
||||
blob = pki_signature_to_blob(sig);
|
||||
assert_non_null(blob);
|
||||
assert_int_equal(ssh_string_len(blob), sizeof(ref_signature));
|
||||
assert_memory_equal(ssh_string_data(blob), ref_signature,
|
||||
sizeof(ref_signature));
|
||||
|
||||
ssh_signature_free(sig);
|
||||
SSH_KEY_FREE(privkey);
|
||||
SSH_STRING_FREE(blob);
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_ED25519 */
|
||||
|
||||
static void torture_pki_ed25519_verify(void **state){
|
||||
ssh_key pubkey = NULL;
|
||||
ssh_signature sig = NULL;
|
||||
ssh_session session = NULL;
|
||||
ssh_string blob = ssh_string_new(ED25519_SIG_LEN);
|
||||
char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1);
|
||||
char *ptr = NULL;
|
||||
uint8_t *raw_sig_data = NULL;
|
||||
int rc;
|
||||
(void) state;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
/* remove trailing comment */
|
||||
ptr = strchr(pkey_ptr, ' ');
|
||||
if(ptr != NULL){
|
||||
@@ -569,20 +800,32 @@ static void torture_pki_ed25519_verify(void **state){
|
||||
sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO);
|
||||
assert_non_null(sig);
|
||||
|
||||
rc = pki_ed25519_verify(pubkey, sig, HASH, sizeof(HASH));
|
||||
rc = ssh_pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH));
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
/* Alter signature and expect verification error */
|
||||
#if defined(HAVE_OPENSSL_ED25519)
|
||||
raw_sig_data = ssh_string_data(sig->raw_sig);
|
||||
#else
|
||||
raw_sig_data = (uint8_t *)sig->ed25519_sig;
|
||||
#endif
|
||||
assert_non_null(raw_sig_data);
|
||||
(raw_sig_data)[3]^= 0xff;
|
||||
rc = ssh_pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH));
|
||||
assert_true(rc == SSH_ERROR);
|
||||
|
||||
ssh_signature_free(sig);
|
||||
/* alter signature and expect false result */
|
||||
|
||||
SSH_KEY_FREE(pubkey);
|
||||
SSH_STRING_FREE(blob);
|
||||
free(pkey_ptr);
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void torture_pki_ed25519_verify_bad(void **state){
|
||||
ssh_key pubkey = NULL;
|
||||
ssh_signature sig = NULL;
|
||||
ssh_session session = NULL;
|
||||
ssh_string blob = ssh_string_new(ED25519_SIG_LEN);
|
||||
char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1);
|
||||
char *ptr = NULL;
|
||||
@@ -590,6 +833,14 @@ static void torture_pki_ed25519_verify_bad(void **state){
|
||||
int i;
|
||||
(void) state;
|
||||
|
||||
/* Skip test if in FIPS mode */
|
||||
if (ssh_fips_mode()) {
|
||||
skip();
|
||||
}
|
||||
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
/* remove trailing comment */
|
||||
ptr = strchr(pkey_ptr, ' ');
|
||||
if(ptr != NULL){
|
||||
@@ -607,7 +858,7 @@ static void torture_pki_ed25519_verify_bad(void **state){
|
||||
sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO);
|
||||
assert_non_null(sig);
|
||||
|
||||
rc = pki_ed25519_verify(pubkey, sig, HASH, sizeof(HASH));
|
||||
rc = ssh_pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH));
|
||||
assert_true(rc == SSH_ERROR);
|
||||
ssh_signature_free(sig);
|
||||
|
||||
@@ -615,6 +866,7 @@ static void torture_pki_ed25519_verify_bad(void **state){
|
||||
SSH_KEY_FREE(pubkey);
|
||||
SSH_STRING_FREE(blob);
|
||||
free(pkey_ptr);
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state)
|
||||
@@ -730,6 +982,12 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ed25519_import_privkey_base64,
|
||||
setup_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ed25519_import_privkey_base64_comment,
|
||||
setup_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ed25519_import_privkey_base64_whitespace,
|
||||
setup_ed25519_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_ed25519_import_export_privkey_base64,
|
||||
setup_ed25519_key,
|
||||
teardown),
|
||||
@@ -754,6 +1012,11 @@ int torture_run_tests(void) {
|
||||
teardown),
|
||||
cmocka_unit_test(torture_pki_ed25519_import_privkey_base64_passphrase),
|
||||
cmocka_unit_test(torture_pki_ed25519_sign),
|
||||
cmocka_unit_test(torture_pki_ed25519_sign_openssh_privkey_passphrase),
|
||||
#ifdef HAVE_OPENSSL_ED25519
|
||||
cmocka_unit_test(torture_pki_ed25519_sign_pkcs8_privkey),
|
||||
cmocka_unit_test(torture_pki_ed25519_sign_pkcs8_privkey_passphrase),
|
||||
#endif
|
||||
cmocka_unit_test(torture_pki_ed25519_verify),
|
||||
cmocka_unit_test(torture_pki_ed25519_verify_bad),
|
||||
cmocka_unit_test(torture_pki_ed25519_privkey_dup),
|
||||
|
||||
@@ -213,6 +213,82 @@ static void torture_pki_rsa_import_privkey_base64(void **state)
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_rsa_import_privkey_base64_comment(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *comment_str = "#this is line-comment\n#this is another\n";
|
||||
char *key_str = NULL, *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
const char *passphrase = torture_get_testkey_passphrase();
|
||||
enum ssh_keytypes_e type;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
key_str = torture_pki_read_file(LIBSSH_RSA_TESTKEY);
|
||||
assert_non_null(key_str);
|
||||
|
||||
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(key);
|
||||
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_RSA);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_key_is_public(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
free(key_str);
|
||||
free(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_rsa_import_privkey_base64_whitespace(void **state)
|
||||
{
|
||||
int rc, file_str_len;
|
||||
const char *whitespace_str = " \n\t\t\t\t\t\n\n\n\n\n";
|
||||
char *key_str = NULL, *file_str = NULL;
|
||||
ssh_key key = NULL;
|
||||
const char *passphrase = torture_get_testkey_passphrase();
|
||||
enum ssh_keytypes_e type;
|
||||
|
||||
(void) state; /* unused */
|
||||
|
||||
key_str = torture_pki_read_file(LIBSSH_RSA_TESTKEY);
|
||||
assert_non_null(key_str);
|
||||
|
||||
file_str_len = strlen(whitespace_str) + strlen(key_str) + 1;
|
||||
file_str = malloc(file_str_len);
|
||||
assert_non_null(file_str);
|
||||
rc = snprintf(file_str, file_str_len, "%s%s", whitespace_str, key_str);
|
||||
assert_int_equal(rc, file_str_len - 1);
|
||||
|
||||
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(key);
|
||||
|
||||
type = ssh_key_type(key);
|
||||
assert_true(type == SSH_KEYTYPE_RSA);
|
||||
|
||||
rc = ssh_key_is_private(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
rc = ssh_key_is_public(key);
|
||||
assert_true(rc == 1);
|
||||
|
||||
free(key_str);
|
||||
free(file_str);
|
||||
SSH_KEY_FREE(key);
|
||||
}
|
||||
|
||||
static void torture_pki_rsa_publickey_from_privatekey(void **state)
|
||||
{
|
||||
int rc;
|
||||
@@ -468,21 +544,23 @@ static void torture_pki_rsa_generate_key(void **state)
|
||||
ssh_session session=ssh_new();
|
||||
(void) state;
|
||||
|
||||
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
|
||||
assert_true(rc == SSH_OK);
|
||||
assert_non_null(key);
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
key = NULL;
|
||||
pubkey = NULL;
|
||||
if (!ssh_fips_mode()) {
|
||||
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
|
||||
assert_true(rc == SSH_OK);
|
||||
assert_non_null(key);
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
key = NULL;
|
||||
pubkey = NULL;
|
||||
}
|
||||
|
||||
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key);
|
||||
assert_true(rc == SSH_OK);
|
||||
@@ -492,7 +570,7 @@ static void torture_pki_rsa_generate_key(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
@@ -508,7 +586,7 @@ static void torture_pki_rsa_generate_key(void **state)
|
||||
assert_non_null(pubkey);
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
@@ -547,9 +625,9 @@ static void torture_pki_rsa_sha2(void **state)
|
||||
/* Sign using old SHA1 digest */
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
assert_ssh_return_code(session, rc);
|
||||
ssh_signature_free(sign);
|
||||
}
|
||||
@@ -557,18 +635,18 @@ static void torture_pki_rsa_sha2(void **state)
|
||||
/* Sign using new SHA256 digest */
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
assert_ssh_return_code(session, rc);
|
||||
ssh_signature_free(sign);
|
||||
|
||||
/* Sign using rsa-sha2-512 algorithm */
|
||||
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA512);
|
||||
assert_non_null(sign);
|
||||
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
|
||||
assert_ssh_return_code(session, rc);
|
||||
ssh_signature_free(sign);
|
||||
|
||||
@@ -877,6 +955,12 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
|
||||
setup_rsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64_comment,
|
||||
setup_rsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64_whitespace,
|
||||
setup_rsa_key,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
|
||||
setup_openssh_rsa_key,
|
||||
teardown),
|
||||
|
||||
@@ -571,23 +571,25 @@ static void *thread_pki_rsa_generate_key(void *threadid)
|
||||
session = ssh_new();
|
||||
assert_non_null(session);
|
||||
|
||||
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
|
||||
assert_ssh_return_code(session, rc);
|
||||
assert_non_null(key);
|
||||
if (!ssh_fips_mode()) {
|
||||
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
|
||||
assert_ssh_return_code(session, rc);
|
||||
assert_non_null(key);
|
||||
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(pubkey);
|
||||
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
assert_non_null(pubkey);
|
||||
|
||||
sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
|
||||
rc = pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
ssh_signature_free(sign);
|
||||
SSH_KEY_FREE(key);
|
||||
SSH_KEY_FREE(pubkey);
|
||||
}
|
||||
|
||||
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key);
|
||||
assert_ssh_return_code(session, rc);
|
||||
@@ -600,7 +602,7 @@ static void *thread_pki_rsa_generate_key(void *threadid)
|
||||
sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
|
||||
rc = pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
ssh_signature_free(sign);
|
||||
@@ -618,7 +620,7 @@ static void *thread_pki_rsa_generate_key(void *threadid)
|
||||
sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
|
||||
assert_non_null(sign);
|
||||
|
||||
rc = pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
|
||||
rc = ssh_pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
ssh_signature_free(sign);
|
||||
|
||||
@@ -146,6 +146,126 @@ static void torture_tokens_sanity(UNUSED_PARAM(void **state))
|
||||
tokenize_compare_expected(",", single_colon, 1);
|
||||
}
|
||||
|
||||
static void torture_remove_duplicate(UNUSED_PARAM(void **state))
|
||||
{
|
||||
|
||||
const char *simple[] = {"a,a,b,b,c,c",
|
||||
"a,b,c,a,b,c",
|
||||
"a,b,c,c,b,a",
|
||||
"a,a,,b,b,,c,c",
|
||||
",a,a,b,b,c,c",
|
||||
"a,a,b,b,c,c,"};
|
||||
const char *empty[] = {"",
|
||||
",,,,,,,,,",
|
||||
NULL};
|
||||
char *ret = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
ret = ssh_remove_duplicates(simple[i]);
|
||||
assert_non_null(ret);
|
||||
assert_string_equal("a,b,c", ret);
|
||||
printf("simple[%d] resulted in '%s'\n", i, ret);
|
||||
SAFE_FREE(ret);
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ret = ssh_remove_duplicates(empty[i]);
|
||||
if (ret != NULL) {
|
||||
printf("empty[%d] resulted in '%s'\n", i, ret);
|
||||
}
|
||||
assert_null(ret);
|
||||
}
|
||||
|
||||
ret = ssh_remove_duplicates("a");
|
||||
assert_non_null(ret);
|
||||
assert_string_equal("a", ret);
|
||||
SAFE_FREE(ret);
|
||||
}
|
||||
|
||||
static void torture_append_without_duplicate(UNUSED_PARAM(void **state))
|
||||
{
|
||||
const char *s1[] = {"a,a,b,b,c,c",
|
||||
"a,b,c,a,b,c",
|
||||
"a,b,c,c,b,a",
|
||||
"a,a,,b,b,,c,c",
|
||||
",a,a,b,b,c,c",
|
||||
"a,a,b,b,c,c,"};
|
||||
const char *s2[] = {"a,a,b,b,c,c,d,d",
|
||||
"a,b,c,d,a,b,c,d",
|
||||
"a,b,c,d,d,c,b,a",
|
||||
"a,a,,b,b,,c,c,,d,d",
|
||||
",a,a,b,b,c,c,d,d",
|
||||
"a,a,b,b,c,c,d,d,",
|
||||
"d"};
|
||||
const char *empty[] = {"",
|
||||
",,,,,,,,,",
|
||||
NULL,
|
||||
NULL};
|
||||
char *ret = NULL;
|
||||
int i, j;
|
||||
|
||||
ret = ssh_append_without_duplicates("a", "a");
|
||||
assert_non_null(ret);
|
||||
assert_string_equal("a", ret);
|
||||
SAFE_FREE(ret);
|
||||
|
||||
ret = ssh_append_without_duplicates("a", "b");
|
||||
assert_non_null(ret);
|
||||
assert_string_equal("a,b", ret);
|
||||
SAFE_FREE(ret);
|
||||
|
||||
ret = ssh_append_without_duplicates("a", NULL);
|
||||
assert_non_null(ret);
|
||||
assert_string_equal("a", ret);
|
||||
SAFE_FREE(ret);
|
||||
|
||||
ret = ssh_append_without_duplicates(NULL, "b");
|
||||
assert_non_null(ret);
|
||||
assert_string_equal("b", ret);
|
||||
SAFE_FREE(ret);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
for (j = 0; j < 7; j++) {
|
||||
ret = ssh_append_without_duplicates(s1[i], s2[j]);
|
||||
assert_non_null(ret);
|
||||
printf("s1[%d] + s2[%d] resulted in '%s'\n", i, j, ret);
|
||||
assert_string_equal("a,b,c,d", ret);
|
||||
SAFE_FREE(ret);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
ret = ssh_append_without_duplicates(s1[i], empty[j]);
|
||||
assert_non_null(ret);
|
||||
printf("s1[%d] + empty[%d] resulted in '%s'\n", i, j, ret);
|
||||
assert_string_equal("a,b,c", ret);
|
||||
SAFE_FREE(ret);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (j = 0; j < 6; j++) {
|
||||
ret = ssh_append_without_duplicates(empty[i], s1[j]);
|
||||
assert_non_null(ret);
|
||||
printf("empty[%d] + s1[%d] resulted in '%s'\n", i, j, ret);
|
||||
assert_string_equal("a,b,c", ret);
|
||||
SAFE_FREE(ret);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
ret = ssh_append_without_duplicates(empty[i], empty[j]);
|
||||
if (ret != NULL) {
|
||||
printf("empty[%d] + empty[%d] resulted in '%s'\n", i, j, ret);
|
||||
}
|
||||
assert_null(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int torture_run_tests(void)
|
||||
{
|
||||
int rc;
|
||||
@@ -153,6 +273,8 @@ int torture_run_tests(void)
|
||||
cmocka_unit_test(torture_tokens_sanity),
|
||||
cmocka_unit_test(torture_find_matching),
|
||||
cmocka_unit_test(torture_find_all_matching),
|
||||
cmocka_unit_test(torture_remove_duplicate),
|
||||
cmocka_unit_test(torture_append_without_duplicate),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
Reference in New Issue
Block a user