Compare commits

..

32 Commits

Author SHA1 Message Date
Andreas Schneider
186e7b5ca4 kex: Fix zlib compression
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 747e7d05db)
2015-09-16 08:34:58 +02:00
Andreas Schneider
2197704693 Bump version to 0.7.2 2015-09-15 15:17:35 +02:00
Andreas Schneider
229eb8715d cmake: Use tar.xz source package generator
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 1f3a9105ff)
2015-09-15 15:17:35 +02:00
Andreas Schneider
1b18a06f8c kex: Prefer sha2 over sha1
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit b0f22fde62)
2015-09-15 15:09:21 +02:00
Andreas Schneider
91b513798e cmake: Handle libssh threas library correctly
This should fix the build on Windows and would not install pkg files.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 5b586fdfec)
2015-09-08 17:32:57 +02:00
Michael Wilder
25234e510a bignum: Fix OpenSSL crash in SAFE_FREE
Signed-off-by: Michael Wilder <wilder.michael@cimcor.com>
Reviewed-by: Andreas Schneider <asn@samba.org>
(cherry picked from commit 2f193b5cbb)
2015-09-08 17:32:40 +02:00
Andreas Schneider
d16eac5704 server: Fix return code check of ssh_buffer_pack()
Thanks to Andreas Gutschick <andreas.gutschick@mitel.com>

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 36d9b62f1f)
2015-08-18 09:12:47 +02:00
Andreas Schneider
46bff47975 doc: Fix typos in sftp tutorial
Thanks to Anthony Baker <AnthonyBaker@fico.com>

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit da4bebbe1e)
2015-08-18 09:05:45 +02:00
Andreas Schneider
f718b50b3f tests: Add checks for ssh_key_is_private()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit d54a1ab798)
2015-08-10 13:58:51 +02:00
Andreas Schneider
58b7d0f5d2 pki: Fix return values of ssh_key_is_(public|private)
Thanks to Kevin Haake <khaake@red-cocoa.com>

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit e1081796af)
2015-08-10 13:58:50 +02:00
Tilo Eckert
30d4581be5 sftp: Fix incorrect handling of received length fields
Signed-off-by: Tilo Eckert <tilo.eckert@flam.de>
2015-08-01 10:52:48 +03:00
Peter Volpe
83387f957f auth: Fix return status for ssh_userauth_agent()
BUG: https://red.libssh.org/issues/201

Return SSH_AUTH_DENIED instead of SSH_AUTH_ERROR when the provided agent
offers no public keys.

Signed-off-by: Peter Volpe <pvolpe@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit dc9c4d22ab)
2015-07-30 10:52:11 +02:00
Andreas Schneider
f3620bbbad cmake: Fix zlib include directory
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 728c2fbd01)
2015-07-03 12:36:53 +02:00
Andreas Schneider
b45933d30d cmake: Fix OpenSSL detection in non-standard path
This should fix the detection on Windows.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 613b71b385)
2015-07-03 11:40:04 +02:00
Andreas Schneider
1613ed556d cmake: Fail if can't find OpenSSL aes and des headers
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 70cc11618a)
2015-07-03 10:52:56 +02:00
Andreas Schneider
8f5b7b65eb include: Add stdarg.h so we can check for va_copy macro
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2015-06-30 09:59:21 +02:00
Andreas Schneider
053f72c671 Bump version to 0.7.1
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2015-06-30 09:34:28 +02:00
Tilo Eckert
63a8f333b8 SSH_AUTH_PARTIAL is now correctly passed to the caller of ssh_userauth_publickey_auto().
Implicitly fixed unsafe return code handling that could result in use-after-free.

Signed-off-by: Tilo Eckert <tilo.eckert@flam.de>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 0423057424)
2015-06-29 11:11:26 +02:00
Tilo Eckert
57fd8e3187 available auth_methods must be reset on partial authentication
Signed-off-by: Tilo Eckert <tilo.eckert@flam.de>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit cc25d747d4)
2015-06-29 11:11:25 +02:00
Peter Volpe
03972b16c9 channels: Fix exit-signal data unpacking
Signed-off-by: Peter Volpe <pvolpe@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 7637351065)
2015-06-29 09:50:28 +02:00
Peter Volpe
ac7ed82585 agent: Add ssh_set_agent_socket
Allow callers to specify their own socket
for an ssh agent.

Signed-off-by: Peter Volpe <pvolpe@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 7aeba71a92)
2015-06-29 09:47:35 +02:00
Seb Boving
196c2e9c1f Don't allocate a new identity list in the new session's options.
The previous list is not freed. Since the new session just got
created, an identity list is already allocated and empty.

Signed-off-by: Sebastien Boving <seb@google.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit e020dd8d59)
2015-06-24 18:36:10 +02:00
Douglas Heriot
1accbcb98b cmake: Do not use CMAKE_(SOURCE|BINARY)_DIR
(cherry picked from commit a65af1b3b8)
2015-06-24 18:36:08 +02:00
Tiamo Laitakari
342ae10f08 pki: Fix allocation of ed25519 public keys
Signed-off-by: Tiamo Laitakari <tiamo.laitakari@cs.helsinki.fi>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 5478de1a64)
2015-06-24 18:36:08 +02:00
Jordy Moos
eb98a780ed Documentation fix where unsigned is used where signed is expected
Signed-off-by: Jordy Moos <jordymoos@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit fa9fbb1d67)
2015-06-24 18:36:08 +02:00
Andreas Schneider
64233fa3bb misc: Correctly guard the sys/time.h include
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit ef751a26d0)
2015-06-24 18:36:08 +02:00
Andreas Schneider
cbf5cf4ac3 include: Add support for older MSVC versions
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 30a7229fc5)
2015-06-24 16:24:12 +02:00
Andreas Schneider
a3f3f9cb76 kex: Add comments to #if clauses
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 1d69e073af)
2015-06-24 16:24:08 +02:00
Aris Adamantiadis
5aeae08be0 channels: fix exit-status not correctly set 2015-06-03 16:41:19 +02:00
Mike DePaulo
64a658acaa Comment that ssh_forward_cancel() is deprecated.
Signed-off-by: Aris Adamantiadis <aris@badcode.be>
2015-05-29 11:30:32 +02:00
Mike DePaulo
361940a5d7 Reintroduce ssh_forward_listen() (Fixes: #194)
Signed-off-by: Aris Adamantiadis <aris@badcode.be>
2015-05-29 11:24:27 +02:00
Andreas Schneider
2721cbc8ee ChangeLog: Set release date for 0.7.0 2015-05-11 10:42:08 +02:00
247 changed files with 10340 additions and 26560 deletions

View File

@@ -1,4 +0,0 @@
{
"phabricator.uri" : "https://bugs.libssh.org/",
"history.immutable": true
}

13
.clang_complete Normal file
View File

@@ -0,0 +1,13 @@
-DWITH_SERVER=1
-DWITH_GSSAPI=1
-DWITH_ZLIB=1
-DWITH_SFTP=1
-DWITH_SSH1=1
-DWITH_PCAP=1
-DHAVE_ECDH=1
-DHAVE_ECC=1
-Iinclude/libssh
-Iinclude
-Ibuild
-Itests
-Isrc

4
.gitignore vendored
View File

@@ -3,7 +3,7 @@
.*
*.swp
*~$
obj
cscope.*
tags
/build
/obj*
build

View File

@@ -1,302 +0,0 @@
variables:
BUILD_IMAGES_PROJECT: libssh/build-images
FEDORA_BUILD: buildenv-fedora
CENTOS7_BUILD: buildenv-centos7
TUMBLEWEED_BUILD: buildenv-tumbleweed
MINGW_BUILD: buildenv-mingw
DEBIAN_CROSS_BUILD: buildenv-debian-cross
# torture_auth fails on centos7 docker images, so we don't use -DCLIENT_TESTING=ON
centos7/openssl_1.0.x/x86-64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
script:
- mkdir -p obj && cd obj && cmake3 -DUNIT_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
-DWITH_PCAP=ON .. && make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
fedora/openssl_1.1.x/x86-64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script:
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
# Address sanitizer doesn't mix well with LD_PRELOAD used in the testsuite
.fedora/address-sanitizer:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script:
- mkdir -p obj && cd obj && cmake
-DCMAKE_C_FLAGS="-O2 -g -fsanitize=address"
-DCMAKE_LINK_FLAGS="-fsanitize=address -static-libasan"
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
fedora/undefined-sanitizer:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script:
- mkdir -p obj && cd obj && cmake
-DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
&& make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
fedora/static-analysis:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script:
- export CCC_CC=clang
- export CCC_CXX=clang++
- mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. &&
scan-build --status-bugs -o scan make -j$(nproc)
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/scan
# That is a specific runner that we cannot enable universally.
# We restrict it to builds under the $BUILD_IMAGES_PROJECT project.
freebsd/x86-64:
image:
script:
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON .. &&
make && ctest --output-on-failure
tags:
- freebsd
except:
- tags
only:
- branches@libssh/libssh-mirror
- branches@cryptomilk/libssh-mirror
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
fedora/libgcrypt/x86-64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script:
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
-DWITH_GCRYPT=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
fedora/mbedtls/x86-64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script:
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
-DWITH_MBEDTLS=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
tumbleweed/openssl_1.1.x/x86-64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
script:
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
tumbleweed/openssl_1.1.x/x86:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
script:
- mkdir -p obj && cd obj && cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-m32.cmake
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
tumbleweed/undefined-sanitizer:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
script:
- mkdir -p obj && cd obj && cmake
-DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
&& make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
tumbleweed/static-analysis:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
script:
- export CCC_CC=clang
- export CCC_CXX=clang++
- mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. &&
scan-build --status-bugs -o scan make -j$(nproc)
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/scan
# Unit testing only, no client and pkd testing, because cwrap is not available
# for MinGW
mingw64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
script:
- Xvfb :1 -screen 0 1024x768x16 -ac +extension GLX +render -noreset -nolisten tcp &
- export DISPLAY=:1
- mkdir -p obj && cd obj && mingw64-cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON .. &&
make -j$(nproc)
- export WINEPATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
- ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
# Unit testing only, no client and pkd testing, because cwrap is not available
# for MinGW
mingw32:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
script:
- Xvfb :1 -screen 0 1024x768x16 -ac +extension GLX +render -noreset -nolisten tcp &
- export DISPLAY=:1
- mkdir -p obj && cd obj && mingw32-cmake -DCMAKE_BUILD_TYPE=Debug
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
-DUNIT_TESTING=ON .. &&
make -j$(nproc)
- export WINEPATH=/usr/i686-w64-mingw32/sys-root/mingw/bin
- ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
.Debian.cross.template: &Debian_cross_template
stage: test
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$DEBIAN_CROSS_BUILD
script:
- build=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
- host="${CI_JOB_NAME#*.cross.}"
- mkdir -p obj && cd obj && cmake
-DCMAKE_C_COMPILER="$(which $host-gcc)"
-DCMAKE_CXX_COMPILER="$(which $host-g++)"
-DCMAKE_BUILD_TYPE=Debug
-DUNIT_TESTING=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
-DWITH_PCAP=ON .. && make -j$(nproc)
- ctest --output-on-failure -j$(nproc)
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
Debian.cross.mips-linux-gnu:
<<: *Debian_cross_template

View File

@@ -1,11 +1,17 @@
cmake_minimum_required(VERSION 3.2.0)
cmake_policy(SET CMP0048 NEW)
project(libssh C)
project(libssh VERSION 0.8.0 LANGUAGES C)
# Required cmake version
cmake_minimum_required(VERSION 2.8.5)
# global needed variable
# global needed variables
set(APPLICATION_NAME ${PROJECT_NAME})
set(APPLICATION_VERSION_MAJOR "0")
set(APPLICATION_VERSION_MINOR "7")
set(APPLICATION_VERSION_PATCH "2")
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
# SOVERSION scheme: CURRENT.AGE.REVISION
# If there was an incompatible interface change:
# Increment CURRENT. Set AGE and REVISION to 0
@@ -13,7 +19,7 @@ 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.5.0")
set(LIBRARY_VERSION "4.4.0")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
@@ -43,27 +49,18 @@ if (WITH_GCRYPT)
if (NOT GCRYPT_FOUND)
message(FATAL_ERROR "Could not find GCrypt")
endif (NOT GCRYPT_FOUND)
elseif(WITH_MBEDTLS)
find_package(MbedTLS REQUIRED)
if (NOT MBEDTLS_FOUND)
message(FATAL_ERROR "Could not find mbedTLS")
endif (NOT MBEDTLS_FOUND)
else (WITH_GCRYPT)
find_package(OpenSSL)
if (NOT OPENSSL_FOUND)
find_package(GCrypt)
if (NOT GCRYPT_FOUND)
find_package(MbedTLS)
if (NOT MBEDTLS_FOUND)
message(FATAL_ERROR "Could not find OpenSSL, GCrypt or mbedTLS")
endif (NOT MBEDTLS_FOUND)
message(FATAL_ERROR "Could not find OpenSSL or GCrypt")
endif (NOT GCRYPT_FOUND)
endif (NOT OPENSSL_FOUND)
endif(WITH_GCRYPT)
# Find out if we have threading available
set(CMAKE_THREAD_PREFER_PTHREADS ON)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
if (WITH_GSSAPI)
@@ -77,17 +74,6 @@ if (WITH_NACL)
endif (NOT NACL_FOUND)
endif (WITH_NACL)
if (BSD OR SOLARIS OR OSX)
find_package(Argp)
endif (BSD OR SOLARIS OR OSX)
# Disable symbol versioning in non UNIX platforms
if (UNIX)
find_package(ABIMap)
else (UNIX)
set(WITH_SYMBOL_VERSIONING OFF)
endif (UNIX)
# config.h checks
include(ConfigureChecks.cmake)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
@@ -103,15 +89,30 @@ configure_file(libssh.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh.pc)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
DESTINATION
${LIB_INSTALL_DIR}/pkgconfig
COMPONENT
pkgconfig
)
if (LIBSSH_THREADS)
configure_file(libssh_threads.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
${CMAKE_CURRENT_BINARY_DIR}/libssh_threads.pc
DESTINATION
${LIB_INSTALL_DIR}/pkgconfig
COMPONENT
pkgconfig
)
endif (LIBSSH_THREADS)
endif (UNIX)
# cmake config files
set(LIBSSH_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
set(LIBSSH_THREADS_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
configure_file(${PROJECT_NAME}-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake @ONLY)
configure_file(${PROJECT_NAME}-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake @ONLY)
@@ -133,94 +134,32 @@ if (WITH_EXAMPLES)
add_subdirectory(examples)
endif (WITH_EXAMPLES)
if (UNIT_TESTING)
if (WITH_TESTING)
find_package(CMocka REQUIRED)
include(AddCMockaTest)
add_subdirectory(tests)
endif (UNIT_TESTING)
endif (WITH_TESTING)
### SOURCE PACKAGE
if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
# Get the current ABI version from source
get_filename_component(current_abi_path
"${CMAKE_SOURCE_DIR}/src/ABI/current"
ABSOLUTE)
# Check if the ABI version should be updated
file(READ ${current_abi_path} CURRENT_ABI_CONTENT)
string(STRIP "${CURRENT_ABI_CONTENT}" CURRENT_ABI_VERSION)
if (LIBRARY_VERSION VERSION_GREATER CURRENT_ABI_VERSION)
set(UPDATE_ABI TRUE)
endif ()
if (UPDATE_ABI)
message(STATUS "Library version bumped to ${LIBRARY_VERSION}: Updating ABI")
# Get the list of header files
get_file_list("${PROJECT_NAME}_header_list"
DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libssh"
FILES_PATTERNS "*.h")
# Extract the symbols marked as "LIBSSH_API" from the header files
extract_symbols(${PROJECT_NAME}.symbols
HEADERS_LIST_FILE "${PROJECT_NAME}_header_list"
FILTER_PATTERN "LIBSSH_API"
COPY_TO "${CMAKE_SOURCE_DIR}/src/ABI/${PROJECT_NAME}-${LIBRARY_VERSION}.symbols")
if (WITH_ABI_BREAK)
set(ALLOW_ABI_BREAK "BREAK_ABI")
endif()
# Target we can depend on in 'make dist'
set(_SYMBOL_TARGET "${PROJECT_NAME}.map")
# Set the path to the current map file
set(MAP_PATH "${CMAKE_SOURCE_DIR}/src/${_SYMBOL_TARGET}")
# Generate the symbol version map file
generate_map_file(${_SYMBOL_TARGET}
SYMBOLS "${PROJECT_NAME}.symbols"
RELEASE_NAME_VERSION ${PROJECT_NAME}_${LIBRARY_VERSION}
CURRENT_MAP ${MAP_PATH}
COPY_TO ${MAP_PATH}
FINAL
${ALLOW_ABI_BREAK})
# Write the current version to the source
file(WRITE ${current_abi_path} ${LIBRARY_VERSION})
endif(UPDATE_ABI)
endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET})
message(STATUS "********************************************")
message(STATUS "********** ${PROJECT_NAME} build options : **********")
message(STATUS "zlib support: ${WITH_ZLIB}")
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
message(STATUS "libmbedTLS support: ${WITH_MBEDTLS}")
message(STATUS "libnacl support: ${WITH_NACL}")
message(STATUS "SSH-1 support: ${WITH_SSH1}")
message(STATUS "SFTP support: ${WITH_SFTP}")
message(STATUS "Server support : ${WITH_SERVER}")
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
message(STATUS "With static library: ${WITH_STATIC_LIB}")
message(STATUS "Unit testing: ${UNIT_TESTING}")
message(STATUS "Client code testing: ${CLIENT_TESTING}")
set(_SERVER_TESTING OFF)
if (WITH_SERVER)
set(_SERVER_TESTING ${SERVER_TESTING})
endif()
message(STATUS "Server code testing: ${_SERVER_TESTING}")
message(STATUS "Unit testing: ${WITH_TESTING}")
message(STATUS "Client code Unit testing: ${WITH_CLIENT_TESTING}")
if (WITH_INTERNAL_DOC)
message(STATUS "Internal documentation generation")
else (WITH_INTERNAL_DOC)
message(STATUS "Public API documentation generation")
endif (WITH_INTERNAL_DOC)
message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
message(STATUS "Release is final: ${WITH_FINAL}")
message(STATUS "********************************************")

View File

@@ -1,19 +1,27 @@
### GENERAL SETTINGS
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH Library")
# For help take a look at:
# http://www.cmake.org/Wiki/CMake:CPackConfiguration
### general settings
set(CPACK_PACKAGE_NAME ${APPLICATION_NAME})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The SSH library")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
set(CPACK_PACKAGE_VENDOR "The SSH Library Development Team")
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
# SOURCE GENERATOR
### versions
set(CPACK_PACKAGE_VERSION_MAJOR ${APPLICATION_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${APPLICATION_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${APPLICATION_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
### source generator
set(CPACK_SOURCE_GENERATOR "TXZ")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;.gitignore;build;obj*;tags;cscope.*")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;/obj/;tags;cscope.*")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
### NSIS INSTALLER
if (WIN32)
set(CPACK_GENERATOR "ZIP")
@@ -38,6 +46,7 @@ set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
set(CPACK_COMPONENT_HEADERS_DESCRIPTION
"C/C++ header files for use with libssh")
set(CPACK_COMPONENT_HEADERS_DEPENDS libraries)
#set(CPACK_COMPONENT_APPLICATIONS_GROUP "Runtime")
set(CPACK_COMPONENT_LIBRARIES_GROUP "Development")
set(CPACK_COMPONENT_HEADERS_GROUP "Development")

View File

@@ -1,38 +1,6 @@
ChangeLog
==========
version 0.8.0 (released 2018-08-10)
* Removed support for deprecated SSHv1 protocol
* Added new connector API for clients
* Added new known_hosts parsing API
* Added support for OpenSSL 1.1
* Added support for chacha20-poly1305 cipher
* Added crypto backend for mbedtls crypto library
* Added ECDSA support with gcrypt backend
* Added advanced client and server testing using cwrap.org
* Added support for curve25519-sha256 alias
* Added support for global known_hosts file
* Added support for symbol versioning
* Improved ssh_config parsing
* Improved threading support
version 0.7.5 (released 2017-04-13)
* Fixed a memory allocation issue with buffers
* Fixed PKI on Windows
* Fixed some SSHv1 functions
* Fixed config hostname expansion
version 0.7.4 (released 2017-02-03)
* Added id_ed25519 to the default identity list
* Fixed sftp EOF packet handling
* Fixed ssh_send_banner() to confirm with RFC 4253
* Fixed some memory leaks
version 0.7.3 (released 2016-01-23)
* Fixed CVE-2016-0739
* Fixed ssh-agent on big endian
* Fixed some documentation issues
version 0.7.2 (released 2015-09-15)
* Fixed OpenSSL detection on Windows
* Fixed return status for ssh_userauth_agent()

View File

@@ -1,5 +1,4 @@
include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckSymbolExists)
include(CheckFunctionExists)
include(CheckLibraryExists)
@@ -42,32 +41,23 @@ if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
"void __attribute__((visibility(\"default\"))) test() {}
int main(void){ return 0; }
" WITH_VISIBILITY_HIDDEN)
unset(CMAKE_REQUIRED_FLAGS)
set(CMAKE_REQUIRED_FLAGS "")
endif (NOT GNUCC_VERSION EQUAL 34)
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2)
# HEADER FILES
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${ARGP_INCLUDE_DIR})
check_include_file(argp.h HAVE_ARGP_H)
unset(CMAKE_REQUIRED_INCLUDES)
check_include_file(pty.h HAVE_PTY_H)
check_include_file(utmp.h HAVE_UTMP_H)
check_include_file(termios.h HAVE_TERMIOS_H)
check_include_file(unistd.h HAVE_UNISTD_H)
check_include_file(stdint.h HAVE_STDINT_H)
check_include_file(util.h HAVE_UTIL_H)
check_include_file(libutil.h HAVE_LIBUTIL_H)
check_include_file(sys/time.h HAVE_SYS_TIME_H)
check_include_file(sys/utime.h HAVE_SYS_UTIME_H)
check_include_file(sys/param.h HAVE_SYS_PARAM_H)
check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
check_include_file(byteswap.h HAVE_BYTESWAP_H)
check_include_file(glob.h HAVE_GLOB_H)
if (WIN32)
check_include_file(io.h HAVE_IO_H)
check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H)
if (NOT HAVE_WSPIAPI_H)
message(STATUS "WARNING: Without wspiapi.h, this build will only work on Windows XP and newer versions")
@@ -99,40 +89,13 @@ if (OPENSSL_FOUND)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(EVP_aes_128_ctr HAVE_OPENSSL_EVP_AES_CTR)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(EVP_aes_128_cbc HAVE_OPENSSL_EVP_AES_CBC)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(CRYPTO_THREADID_set_callback HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(CRYPTO_ctr128_encrypt HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(EVP_CIPHER_CTX_new HAVE_OPENSSL_EVP_CIPHER_CTX_NEW)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
unset(CMAKE_REQUIRED_INCLUDES)
unset(CMAKE_REQUIRED_LIBRARIES)
endif()
if (CMAKE_HAVE_PTHREAD_H)
set(HAVE_PTHREAD_H 1)
endif (CMAKE_HAVE_PTHREAD_H)
if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS)
if (NOT WITH_GCRYPT)
if (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H)
set(HAVE_OPENSSL_ECC 1)
endif (HAVE_OPENSSL_EC_H AND HAVE_OPENSSL_ECDSA_H)
@@ -140,37 +103,22 @@ if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS)
if (HAVE_OPENSSL_ECC)
set(HAVE_ECC 1)
endif (HAVE_OPENSSL_ECC)
endif ()
if (NOT WITH_MBEDTLS)
set(HAVE_DSA 1)
endif (NOT WITH_MBEDTLS)
endif (NOT WITH_GCRYPT)
# FUNCTIONS
check_function_exists(isblank HAVE_ISBLANK)
check_function_exists(strncpy HAVE_STRNCPY)
check_function_exists(strtoull HAVE_STRTOULL)
check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
check_function_exists(memset_s HAVE_MEMSET_S)
if (HAVE_GLOB_H)
check_function_exists(glob HAVE_GLOB)
endif (HAVE_GLOB_H)
if (NOT WIN32)
check_function_exists(vsnprintf HAVE_VSNPRINTF)
check_function_exists(snprintf HAVE_SNPRINTF)
endif (NOT WIN32)
check_function_exists(vsnprintf HAVE_VSNPRINTF)
check_function_exists(snprintf HAVE_SNPRINTF)
if (WIN32)
check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF)
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
check_function_exists(_strtoui64 HAVE__STRTOUI64)
check_symbol_exists(_vsnprintf_s "stdio.h" HAVE__VSNPRINTF_S)
check_symbol_exists(_vsnprintf "stdio.h" HAVE__VSNPRINTF)
check_symbol_exists(_snprintf "stdio.h" HAVE__SNPRINTF)
check_symbol_exists(_snprintf_s "stdio.h" HAVE__SNPRINTF_S)
check_function_exists(_vsnprintf_s HAVE__VSNPRINTF_S)
check_function_exists(_vsnprintf HAVE__VSNPRINTF)
check_function_exists(_snprintf HAVE__SNPRINTF)
check_function_exists(_snprintf_s HAVE__SNPRINTF_S)
if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
check_symbol_exists(ntohll winsock2.h HAVE_NTOHLL)
@@ -181,14 +129,10 @@ if (WIN32)
check_symbol_exists(poll "winsock2.h;ws2tcpip.h" HAVE_SELECT)
# The getaddrinfo function is defined to the WspiapiGetAddrInfo inline function
check_symbol_exists(getaddrinfo "winsock2.h;ws2tcpip.h" HAVE_GETADDRINFO)
unset(CMAKE_REQUIRED_LIBRARIES)
set(CMAKE_REQUIRED_LIBRARIES)
endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
check_function_exists(_strtoui64 HAVE__STRTOUI64)
set(HAVE_SELECT TRUE)
check_symbol_exists(SecureZeroMemory "windows.h" HAVE_SECURE_ZERO_MEMORY)
else (WIN32)
check_function_exists(poll HAVE_POLL)
check_function_exists(select HAVE_SELECT)
@@ -205,13 +149,13 @@ if (UNIX)
check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET)
if (HAVE_LIBSOCKET)
set(HAVE_GETADDRINFO TRUE)
set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} socket)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket)
endif (HAVE_LIBSOCKET)
# libnsl/inet_pton (Solaris)
check_library_exists(nsl inet_pton "" HAVE_LIBNSL)
if (HAVE_LIBNSL)
set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} nsl)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl)
endif (HAVE_LIBNSL)
# librt
@@ -220,15 +164,16 @@ if (UNIX)
check_library_exists(rt clock_gettime "" HAVE_CLOCK_GETTIME)
if (HAVE_LIBRT OR HAVE_CLOCK_GETTIME)
set(_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} rt)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} rt)
endif (HAVE_LIBRT OR HAVE_CLOCK_GETTIME)
check_library_exists(util forkpty "" HAVE_LIBUTIL)
check_function_exists(cfmakeraw HAVE_CFMAKERAW)
check_function_exists(strtoull HAVE_STRTOULL)
check_function_exists(__strtoull HAVE___STRTOULL)
endif (UNIX)
set(LIBSSH_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
set(LIBSSH_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
# LIBRARIES
if (OPENSSL_FOUND)
@@ -238,16 +183,11 @@ endif (OPENSSL_FOUND)
if (GCRYPT_FOUND)
set(HAVE_LIBGCRYPT 1)
if (GCRYPT_VERSION VERSION_GREATER "1.4.6")
set(HAVE_GCRYPT_ECC 1)
set(HAVE_ECC 1)
#set(HAVE_GCRYPT_ECC 1)
#set(HAVE_ECC 1)
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
endif (GCRYPT_FOUND)
if (MBEDTLS_FOUND)
set(HAVE_LIBMBEDCRYPTO 1)
set(HAVE_ECC 1)
endif (MBEDTLS_FOUND)
if (CMAKE_USE_PTHREADS_INIT)
set(HAVE_PTHREAD 1)
endif (CMAKE_USE_PTHREADS_INIT)
@@ -267,33 +207,6 @@ int main(void) {
return 0;
}" HAVE_MSC_THREAD_LOCAL_STORAGE)
check_c_source_compiles("
#define FALL_THROUGH __attribute__((fallthrough))
enum direction_e {
UP = 0,
DOWN,
};
int main(void) {
enum direction_e key = UP;
int i = 10;
int j = 0;
switch (key) {
case UP:
i = 5;
FALL_THROUGH;
case DOWN:
j = i * 2;
break;
default:
break;
}
return 0;
}" HAVE_FALLTHROUGH_ATTRIBUTE)
check_c_source_compiles("
#include <string.h>
@@ -301,7 +214,7 @@ int main(void)
{
char buf[] = \"This is some content\";
memset(buf, '\\\\0', sizeof(buf)); __asm__ volatile(\"\" : : \"g\"(&buf) : \"memory\");
memset(buf, '\\\\0', sizeof(buf)); __asm__ volatile(\"\" : : \"r\"(&buf) : \"memory\");
return 0;
}" HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
@@ -333,19 +246,10 @@ int main(void) {
}" HAVE_COMPILER__FUNCTION__)
check_c_source_compiles("
void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits)
__attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)));
int main(void) { return 0; }" HAVE_GCC_BOUNDED_ATTRIBUTE)
if (WITH_DEBUG_CRYPTO)
set(DEBUG_CRYPTO 1)
endif (WITH_DEBUG_CRYPTO)
if (WITH_DEBUG_PACKET)
set(DEBUG_PACKET 1)
endif (WITH_DEBUG_PACKET)
if (WITH_DEBUG_CALLTRACE)
set(DEBUG_CALLTRACE 1)
endif (WITH_DEBUG_CALLTRACE)

View File

@@ -1,24 +1,19 @@
option(WITH_GSSAPI "Build with GSSAPI support" ON)
option(WITH_ZLIB "Build with ZLIB support" ON)
option(WITH_SSH1 "Build with SSH1 support" OFF)
option(WITH_SFTP "Build with SFTP support" ON)
option(WITH_SERVER "Build with SSH server support" ON)
option(WITH_STATIC_LIB "Build with a static library" OFF)
option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
option(WITH_DEBUG_PACKET "Build with packet debug output" OFF)
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
option(WITH_PCAP "Compile with Pcap generation support" ON)
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
option(UNIT_TESTING "Build with unit tests" OFF)
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
option(WITH_TESTING "Build with unit tests" OFF)
option(WITH_CLIENT_TESTING "Build with client tests; requires a running sshd" OFF)
option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
option(WITH_EXAMPLES "Build examples" ON)
option(WITH_NACL "Build with libnacl (curve25519)" ON)
option(WITH_SYMBOL_VERSIONING "Build with symbol versioning" ON)
option(WITH_ABI_BREAK "Allow ABI break" OFF)
option(FUZZ_TESTING "Build with fuzzer for the server" OFF)
option(WITH_NACL "Build with libnacl (curve25519" ON)
if (WITH_ZLIB)
set(WITH_LIBZ ON)
else (WITH_ZLIB)
@@ -26,17 +21,13 @@ else (WITH_ZLIB)
endif (WITH_ZLIB)
if(WITH_BENCHMARKS)
set(UNIT_TESTING ON)
set(WITH_TESTING ON)
endif(WITH_BENCHMARKS)
if (UNIT_TESTING)
if (WITH_TESTING)
set(WITH_STATIC_LIB ON)
endif (UNIT_TESTING)
endif (WITH_TESTING)
if (WITH_NACL)
set(WITH_NACL ON)
endif (WITH_NACL)
if (WITH_ABI_BREAK)
set(WITH_SYMBOL_VERSIONING ON)
endif (WITH_ABI_BREAK)
endif (WITH_NACL)

20
INSTALL
View File

@@ -14,10 +14,6 @@ or
optional:
- [libz](http://www.zlib.net) >= 1.2
- [socket_wrapper](https://cwrap.org/) >= 1.1.5
- [nss_wrapper](https://cwrap.org/) >= 1.1.2
- [uid_wrapper](https://cwrap.org/) >= 1.2.0
- [pam_wrapper](https://cwrap.org/) >= 1.0.1
Note that these version numbers are version we know works correctly. If you
build and run libssh successfully with an older version, please let us know.
@@ -35,27 +31,13 @@ First, you need to configure the compilation, using CMake. Go inside the
GNU/Linux, MacOS X, MSYS/MinGW:
cmake -DUNIT_TESTING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
make
On Windows you should choose a makefile gernerator with -G or use
cmake-gui.exe ..
To enable additional client tests against a local OpenSSH server, add the
compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH
server package and some wrapper libraries (see optional requirements) to
be installed.
If you're interested in server testing, then a OpenSSH client should be
installed on the system and if possible also dropbear. Once that is done
enable server support with -DWITH_SERVER=ON and enable testing of it with
-DSERVER_TESTING=ON.
## Testing build
make test
### CMake standard options
Here is a list of the most interesting options provided out of the box by
CMake.

125
README
View File

@@ -33,11 +33,130 @@ If you ask yourself how to compile libssh, please read INSTALL before anything.
http://www.libssh.org
4* Contributing
4* API Changes !
-_-_-_-_-_-_-_-_-_
Please read the file 'SubmittingPatches' next to this README file. It explains
our copyright policy and how you should send patches for upstream inclusion.
Changes between 0.4 and 0.5
---------------------------
We use the ssh_ prefix as namespace for every function now. There is a legacy.h
which could be used to get the old function names.
Changes between 0.3 and 0.4
---------------------------
We changed libssh to be typesafe now:
SSH_SESSION *session -> ssh_session session
SFTP_SESSION *sftp -> sftp_session sftp
CHANNEL *channel -> ssh_channel channel
STRING *string -> ssh_string string
...
The options structure has been removed and there is a new function. This
function can set all available options now. You can find the enum in the
header file and it is documented. Example:
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
5* Copyright policy
-_-_-_-_-_-_-_-_-_-_
libssh is a project with distributed copyright ownership, which means we prefer
the copyright on parts of libssh to be held by individuals rather than
corporations if possible. There are historical legal reasons for this, but one
of the best ways to explain it is that its much easier to work with
individuals who have ownership than corporate legal departments if we ever need
to make reasonable compromises with people using and working with libssh.
We track the ownership of every part of libssh via git, our source code control
system, so we know the provenance of every piece of code that is committed to
libssh.
So if possible, if youre doing libssh changes on behalf of a company who
normally owns all the work you do please get them to assign personal copyright
ownership of your changes to you as an individual, that makes things very easy
for us to work with and avoids bringing corporate legal departments into the
picture.
If you cant do this we can still accept patches from you owned by your
employer under a standard employment contract with corporate copyright
ownership. It just requires a simple set-up process first.
We use a process very similar to the way things are done in the Linux Kernel
community, so it should be very easy to get a sign off from your corporate
legal department. The only changes weve made are to accommodate the license we
use, which is LGPLv2 (or later) whereas the Linux kernel uses GPLv2.
The process is called signing.
How to sign your work
----------------------
Once you have permission to contribute to libssh from your employer, simply
email a copy of the following text from your corporate email address to:
contributing@libssh.org
--------------------------------------------------------------------------
libssh Developer's Certificate of Origin. Version 1.0
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the appropriate
version of the GNU General Public License; or
(b) The contribution is based upon previous work that, to the best of
my knowledge, is covered under an appropriate open source license
and I have the right under that license to submit that work with
modifications, whether created in whole or in part by me, under
the GNU General Public License, in the appropriate version; or
(c) The contribution was provided directly to me by some other
person who certified (a) or (b) and I have not modified it.
(d) I understand and agree that this project and the contribution are
public and that a record of the contribution (including all
metadata and personal information I submit with it, including my
sign-off) is maintained indefinitely and may be redistributed
consistent with the libssh Team's policies and the requirements of
the GNU GPL where they are relevant.
(e) I am granting this work to this project 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 the option of the project) any later version.
http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------
We will maintain a copy of that email as a record that you have the rights to
contribute code to libssh under the required licenses whilst working for the
company where the email came from.
Then when sending in a patch via the normal mechanisms described above, add a
line that states:
Signed-off-by: Random J Developer <random@developer.example.org>
using your real name and the email address you sent the original email you used
to send the libssh Developers Certificate of Origin to us (sorry, no
pseudonyms or anonymous contributions.)
Thats it! Such code can then quite happily contain changes that have copyright
messages such as:
(c) Example Corporation.
and can be merged into the libssh codebase in the same way as patches from any
other individual. You dont need to send in a copy of the libssh Developers
Certificate of Origin for each patch, or inside each patch. Just the sign-off
message is all that is required once weve received the initial email.
Have fun and happy libssh hacking!

View File

@@ -287,27 +287,6 @@ Good Examples:
return rc;
}
Initialize pointers
-------------------
All pointer variables MUST be initialized to NULL. History has
demonstrated that uninitialized pointer variables have lead to various
bugs and security issues.
Pointers MUST be initialized even if the assignment directly follows
the declaration, like pointer2 in the example below, because the
instructions sequence may change over time.
Good Example:
char *pointer1 = NULL;
char *pointer2 = NULL;
pointer2 = some_func2();
...
pointer1 = some_func1();
Typedefs
---------

View File

@@ -1,11 +0,0 @@
mbedTLS and libssh in multithreaded applications
==================================================
To use libssh with mbedTLS in a multithreaded application, mbedTLS has to be
built with threading support enabled.
If threading support is not available and multi threading is used, ssh_init
will fail.
More information about building mbedTLS with threading support can be found
in the mbedTLS documentation.

View File

@@ -1,44 +0,0 @@
[![pipeline status](https://gitlab.com/libssh/libssh-mirror/badges/master/pipeline.svg)](https://gitlab.com/libssh/libssh-mirror/commits/master)
```
_ _ _ _
(_) (_) (_) (_)
(_) _ (_) _ _ _ _ _ (_) _
(_) (_) (_)(_) _ (_)(_) (_)(_) (_)(_) _
(_) (_) (_) (_) _ (_) _ (_) (_) (_)
(_) (_) (_)(_)(_) (_)(_) (_)(_) (_) (_).org
The SSH library
```
# Why?
Why not ? :) I've began to work on my own implementation of the ssh protocol
because i didn't like the currently public ones.
Not any allowed you to import and use the functions as a powerful library,
and so i worked on a library-based SSH implementation which was non-existing
in the free and open source software world.
# How/Who?
If you downloaded this file, you must know what it is : a library for
accessing ssh client services through C libraries calls in a simple manner.
Everybody can use this software under the terms of the LGPL - see the COPYING
file
If you ask yourself how to compile libssh, please read INSTALL before anything.
# Where ?
https://www.libssh.org
# Contributing
Please read the file 'SubmittingPatches' next to this README file. It explains
our copyright policy and how you should send patches for upstream inclusion.
Have fun and happy libssh hacking!
The libssh Team

View File

@@ -1,9 +1,9 @@
How to contribute a patch to libssh
====================================
Please checkout the libssh source code using git. Change the code and then
use "git format-patch" to create a patch. The patch should be signed (see
below) and send it to libssh@libssh.org, or attach it to a bug report at
Simple, just make the code change, and email it as either a "diff -u"
change, or as a "git format-patch" change against the original source
code to libssh@libssh.org, or attach it to a bug report at
https://red.libssh.org/
For larger code changes, breaking the changes up into a set of simple

View File

@@ -23,16 +23,8 @@ if(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW)
set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address" CACHE STRING "Address sanitizer executable linker flags")
endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW)
if (CMAKE_CROSSCOMPILING)
if (WIN32)
find_program(WINE_EXECUTABLE
NAMES wine)
set(TARGET_SYSTEM_EMULATOR ${WINE_EXECUTABLE})
endif()
endif()
function (ADD_CMOCKA_TEST _testName _testSource)
add_executable(${_testName} ${_testSource})
target_link_libraries(${_testName} ${ARGN})
add_test(${_testName} ${TARGET_SYSTEM_EMULATOR} ${CMAKE_CURRENT_BINARY_DIR}/${_testName}${CMAKE_EXECUTABLE_SUFFIX})
add_test(${_testName} ${CMAKE_CURRENT_BINARY_DIR}/${_testName})
endfunction (ADD_CMOCKA_TEST)

View File

@@ -1,88 +0,0 @@
#
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
#.rst:
# ExtractSymbols
# --------------
#
# This is a helper script for FindABImap.cmake.
#
# Extract symbols from header files and output a list to a file.
# This script is run in build time to extract symbols from the provided header
# files. This way, symbols added or removed can be checked and used to update
# the symbol version script.
#
# All symbols followed by the character ``'('`` are extracted. If a
# ``FILTER_PATTERN`` is provided, only the lines containing the given string are
# considered.
#
# Expected defined variables
# --------------------------
#
# ``HEADERS_LIST_FILE``:
# Required, expects a file containing the list of header files to be parsed.
#
# ``OUTPUT_PATH``:
# Required, expects the output file path.
#
# Optionally defined variables
# ----------------------------
#
# ``FILTER_PATTERN``:
# Expects a string. Only lines containing the given string will be considered
# when extracting symbols.
#
if (NOT DEFINED OUTPUT_PATH)
message(SEND_ERROR "OUTPUT_PATH not defined")
endif()
if (NOT DEFINED HEADERS_LIST_FILE)
message(SEND_ERROR "HEADERS not defined")
endif()
file(READ ${HEADERS_LIST_FILE} HEADERS_LIST)
set(symbols)
foreach(header ${HEADERS_LIST})
# Filter only lines containing the FILTER_PATTERN
file(STRINGS ${header} contain_filter
REGEX "^.*${FILTER_PATTERN}.*[(]"
)
# Remove function-like macros
foreach(line ${contain_filter})
if (NOT ${line} MATCHES ".*#[ ]*define")
list(APPEND not_macro ${line})
endif()
endforeach()
set(functions)
# Get only the function names followed by '('
foreach(line ${not_macro})
string(REGEX MATCHALL "[a-zA-Z0-9_]+[ ]*[(]" func ${line})
list(APPEND functions ${func})
endforeach()
set(extracted_symbols)
# Remove '('
foreach(line ${functions})
string(REGEX REPLACE "[(]" "" symbol ${line})
string(STRIP "${symbol}" symbol)
list(APPEND extracted_symbols ${symbol})
endforeach()
list(APPEND symbols ${extracted_symbols})
endforeach()
list(REMOVE_DUPLICATES symbols)
file(WRITE ${OUTPUT_PATH} "${symbols}")

View File

@@ -1,394 +0,0 @@
#
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
#.rst:
# FindABIMap
# ----------
#
# This file provides functions to generate the symbol version script. It uses
# the ``abimap`` tool to generate and update the linker script file. It can be
# installed by calling::
#
# $ pip install abimap
#
# The ``function generate_map_file`` generates a symbol version script
# containing the provided symbols. It defines a custom command which sets
# ``target_name`` as its ``OUTPUT``.
#
# The experimental function ``extract_symbols()`` is provided as a simple
# parser to extract the symbols from C header files. It simply extracts symbols
# followed by an opening '``(``'. It is recommended to use a filter pattern to
# select the lines to be considered. It defines a custom command which sets
# ``target_name`` as its output.
#
# The helper function ``get_files_list()`` is provided to find files given a
# name pattern. It defines a custom command which sets ``target_name`` as its
# output.
#
# Functions provided
# ------------------
#
# ::
#
# generate_map_file(target_name
# RELEASE_NAME_VERSION release_name
# SYMBOLS symbols_file
# [CURRENT_MAP cur_map]
# [FINAL]
# [BREAK_ABI]
# [COPY_TO output]
# )
#
# ``target_name``:
# Required, expects the name of the file to receive the generated symbol
# version script. It should be added as a dependency for the library. Use the
# linker option ``--version-script filename`` to add the version information
# to the symbols when building the library.
#
# ``RELEASE_NAME_VERSION``:
# Required, expects a string containing the name and version information to be
# added to the symbols in the format ``lib_name_1_2_3``.
#
# ``SYMBOLS``:
# Required, expects a file containing the list of symbols to be added to the
# symbol version script.
#
# ``CURRENT_MAP``:
# Optional. If given, the new set of symbols will be checked against the
# ones contained in the ``cur_map`` file and updated properly. If an
# incompatible change is detected and ``BREAK_ABI`` is not defined, the build
# will fail.
#
# ``FINAL``:
# Optional. If given, will provide the ``--final`` option to ``abimap`` tool,
# which will mark the modified release in the symbol version script with a
# special comment, preventing later changes. This option should be set when
# creating a library release and the resulting map file should be stored with
# the source code.
#
# ``BREAK_ABI``:
# Optional. If provided, will use ``abimap`` ``--allow-abi-break`` option, which
# accepts incompatible changes to the set of symbols. This is necessary if any
# previously existing symbol were removed.
#
# ``COPY_TO``:
# Optional, expects a string containing the path to where the generated
# map file will be copied.
#
# Example:
#
# .. code-block:: cmake
#
# find_package(ABIMap)
# generate_map_file("lib.map"
# RELEASE_NAME_VERSION "lib_1_0_0"
# SYMBOLS "symbol1;symbol2"
# )
#
# This example would result in the symbol version script to be created in
# ``${CMAKE_CURRENT_BINARY_DIR}/lib.map`` containing the provided symbols.
#
# ::
#
# get_files_list(target_name
# DIRECTORIES dir1 [dir2 ...]
# FILES_PATTERNS exp1 [exp2 ...]
# [COPY_TO output]
# )
#
# ``target_name``:
# Required, expects the name of the target to be created. A file named after
# the string given in ``target_name`` will be created in
# ``${CMAKE_CURRENT_BINARY_DIR}`` to receive the list of files found.
#
# ``DIRECTORIES``:
# Required, expects a list of directories paths. Only absolute paths are
# supported.
#
# ``FILES_PATTERN``:
# Required, expects a list of matching expressions to find the files to be
# considered.
#
# ``COPY_TO``:
# Optional, expects a string containing the path to where the file containing
# the list of files will be copied.
#
# This command searches the directories provided in ``DIRECTORIES`` for files
# matching any of the patterns provided in ``FILES_PATTERNS``. The obtained list
# is written to the path specified by ``output``.
#
# Example:
#
# .. code-block:: cmake
#
# find_package(ABIMap)
# get_files_list(target
# DIRECTORIES "/include/mylib"
# FILES_PATTERNS "*.h"
# COPY_TO "my_list.txt"
# )
#
# Consider that ``/include/mylib`` contains 3 files, ``h1.h``, ``h2.h``, and
# ``h3.hpp``
#
# Will result in a file ``my_list.txt`` containing::
#
# ``h1.h;h2.h``
#
# ::
#
# extract_symbols(target_name
# HEADERS_LIST_FILE headers_list
# [FILTER_PATTERN pattern]
# [COPY_TO output]
# )
#
# ``target_name``:
# Required, expects the name of the target to be created. A file named after
# the string given in ``target_name`` will be created in
# ``${CMAKE_CURRENT_BINARY_DIR}`` to receive the list of symbols.
#
# ``HEADERS_LIST_FILE``:
# Required, expects a path to a file containing the list of header files to be
# parsed.
#
# ``FILTER_PATTERN``:
# Optional, expects a string. Only the lines containing the filter pattern
# will be considered.
#
# ``COPY_TO``:
# Optional, expects a string containing the path to where the file containing
# the found symbols will be copied.
#
# This command extracts the symbols from the files listed in
# ``headers_list`` and write them on the ``output`` file. If ``pattern``
# is provided, then only the lines containing the string given in ``pattern``
# will be considered. It is recommended to provide a ``FILTER_PATTERN`` to mark
# the lines containing exported function declaration, since this function is
# experimental and can return wrong symbols when parsing the header files.
#
# Example:
#
# .. code-block:: cmake
#
# find_package(ABIMap)
# extract_symbols("lib.symbols"
# HEADERS_LIST_FILE "headers_list"
# FILTER_PATTERN "API_FUNCTION"
# )
#
# Where headers_list contains::
#
# header1.h;header2.h
#
# Where ``header1.h`` contains::
#
# API_FUNCTION int exported_func1(int a, int b);
#
# ``header2.h`` contains::
#
# API_FUNCTION int exported_func2(int a);
#
# int private_func2(int b);
#
# Will result in a file ``lib.symbols`` in ``${CMAKE_CURRENT_BINARY_DIR}`` containing::
#
# ``exported_func1;exported_func2``
#
# Search for python which is required
find_package(PythonInterp REQUIRED)
# Search for abimap tool used to generate the map files
find_program(ABIMAP_EXECUTABLE NAMES abimap DOC "path to the abimap executable")
mark_as_advanced(ABIMAP_EXECUTABLE)
if (NOT ABIMAP_EXECUTABLE AND UNIX)
message(STATUS "Could not find `abimap` in PATH."
" It can be found in PyPI as `abimap`"
" (try `pip install abimap`)")
else ()
set(ABIMAP_FOUND TRUE)
endif ()
# Define helper scripts
set(_EXTRACT_SYMBOLS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/ExtractSymbols.cmake)
set(_GENERATE_MAP_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/GenerateMap.cmake)
set(_GET_FILES_LIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/GetFilesList.cmake)
function(get_file_list _TARGET_NAME)
set(one_value_arguments
COPY_TO
)
set(multi_value_arguments
DIRECTORIES
FILES_PATTERNS
)
cmake_parse_arguments(_get_files_list
""
"${one_value_arguments}"
"${multi_value_arguments}"
${ARGN}
)
# The DIRS argument is required
if (NOT DEFINED _get_files_list_DIRECTORIES)
message(FATAL_ERROR "No directories paths provided. Provide a list of"
" directories paths containing header files."
)
endif()
# The FILES_PATTERNS argument is required
if (NOT DEFINED _get_files_list_FILES_PATTERNS)
message(FATAL_ERROR "No matching expressions provided. Provide a list"
" of matching patterns for the header files."
)
endif()
get_filename_component(_get_files_list_OUTPUT_PATH
"${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
ABSOLUTE
)
add_custom_command(
OUTPUT ${_TARGET_NAME}
COMMAND ${CMAKE_COMMAND}
-DOUTPUT_PATH="${_get_files_list_OUTPUT_PATH}"
-DDIRECTORIES="${_get_files_list_DIRECTORIES}"
-DFILES_PATTERNS="${_get_files_list_FILES_PATTERNS}"
-P ${_GET_FILES_LIST_SCRIPT}
COMMENT
"Searching for files"
)
if (DEFINED _get_files_list_COPY_TO)
# Copy the generated file back to the COPY_TO
add_custom_target(copy_headers_list_${TARGET_NAME} ALL
COMMAND
${CMAKE_COMMAND} -E copy_if_different ${_TARGET_NAME} ${_get_files_list_COPY_TO}
DEPENDS "${_TARGET_NAME}"
COMMENT "Copying ${_TARGET_NAME} to ${_get_files_list_COPY_TO}"
)
endif()
endfunction()
function(extract_symbols _TARGET_NAME)
set(one_value_arguments
FILTER_PATTERN
HEADERS_LIST_FILE
COPY_TO
)
set(multi_value_arguments
)
cmake_parse_arguments(_extract_symbols
""
"${one_value_arguments}"
"${multi_value_arguments}"
${ARGN}
)
# The HEADERS_LIST_FILE argument is required
if (NOT DEFINED _extract_symbols_HEADERS_LIST_FILE)
message(FATAL_ERROR "No header files given. Provide a list of header"
" files containing exported symbols."
)
endif()
get_filename_component(_extract_symbols_OUTPUT_PATH
"${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
ABSOLUTE
)
add_custom_target(${_TARGET_NAME}
COMMAND ${CMAKE_COMMAND}
-DOUTPUT_PATH="${_extract_symbols_OUTPUT_PATH}"
-DHEADERS_LIST_FILE="${_extract_symbols_HEADERS_LIST_FILE}"
-DFILTER_PATTERN=${_extract_symbols_FILTER_PATTERN}
-P ${_EXTRACT_SYMBOLS_SCRIPT}
DEPENDS ${_extract_symbols_HEADERS_LIST_FILE}
COMMENT "Extracting symbols from headers")
if (DEFINED _extract_symbols_COPY_TO)
file(READ "${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}" SYMBOL_CONTENT)
string(REPLACE ";" "\n" SYMBOL_CONTENT_NEW "${SYMBOL_CONTENT}")
file(WRITE "${_extract_symbols_COPY_TO}" "${SYMBOL_CONTENT_NEW}")
endif()
endfunction()
function(generate_map_file _TARGET_NAME)
set(options
FINAL
BREAK_ABI
)
set(one_value_arguments
RELEASE_NAME_VERSION
SYMBOLS
CURRENT_MAP
COPY_TO
)
set(multi_value_arguments
)
cmake_parse_arguments(_generate_map_file
"${options}"
"${one_value_arguments}"
"${multi_value_arguments}"
${ARGN}
)
if (NOT DEFINED _generate_map_file_SYMBOLS)
message(FATAL_ERROR "No symbols file provided."
)
endif()
if (NOT DEFINED _generate_map_file_RELEASE_NAME_VERSION)
message(FATAL_ERROR "Release name and version not provided."
" (e.g. libname_1_0_0"
)
endif()
# Set generated map file path
get_filename_component(_generate_map_file_OUTPUT_PATH
"${CMAKE_CURRENT_BINARY_DIR}/${_TARGET_NAME}"
ABSOLUTE
)
add_custom_command(
OUTPUT ${_TARGET_NAME}
COMMAND ${CMAKE_COMMAND}
-DABIMAP_EXECUTABLE=${ABIMAP_EXECUTABLE}
-DSYMBOLS="${_generate_map_file_SYMBOLS}"
-DCURRENT_MAP=${_generate_map_file_CURRENT_MAP}
-DOUTPUT_PATH="${_generate_map_file_OUTPUT_PATH}"
-DFINAL=${_generate_map_file_FINAL}
-DBREAK_ABI=${_generate_map_file_BREAK_ABI}
-DRELEASE_NAME_VERSION=${_generate_map_file_RELEASE_NAME_VERSION}
-P ${_GENERATE_MAP_SCRIPT}
DEPENDS ${_generate_map_file_SYMBOLS}
COMMENT "Generating the map ${_TARGET_NAME}"
)
if (DEFINED _generate_map_file_COPY_TO)
# Copy the generated map back to the COPY_TO
add_custom_target(copy_map_${_TARGET_NAME} ALL
COMMAND
${CMAKE_COMMAND} -E copy_if_different ${_TARGET_NAME} ${_generate_map_file_COPY_TO}
DEPENDS "${_TARGET_NAME}"
COMMENT "Copying ${_TARGET_NAME} to ${_generate_map_file_COPY_TO}"
)
endif()
endfunction()

View File

@@ -1,66 +1,60 @@
# - Try to find ARGP
# - Try to find Argp
# Once done this will define
#
# ARGP_ROOT_DIR - Set this variable to the root installation of ARGP
# ARGP_FOUND - system has Argp
# ARGP_INCLUDE_DIRS - the Argp include directory
# ARGP_LIBRARIES - Link these to use Argp
# ARGP_DEFINITIONS - Compiler switches required for using Argp
#
# Read-Only variables:
# ARGP_FOUND - system has ARGP
# ARGP_INCLUDE_DIR - the ARGP include directory
# ARGP_LIBRARIES - Link these to use ARGP
# ARGP_DEFINITIONS - Compiler switches required for using ARGP
# Copyright (c) 2010 Andreas Schneider <asn@cryptomilk.org>
#
#=============================================================================
# Copyright (c) 2011-2016 Andreas Schneider <asn@cryptomilk.org>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
set(_ARGP_ROOT_HINTS
)
set(_ARGP_ROOT_PATHS
"$ENV{PROGRAMFILES}/argp"
)
if (ARGP_LIBRARIES AND ARGP_INCLUDE_DIRS)
# in cache already
set(ARGP_FOUND TRUE)
else (ARGP_LIBRARIES AND ARGP_INCLUDE_DIRS)
find_path(ARGP_ROOT_DIR
find_path(ARGP_INCLUDE_DIR
NAMES
include/argp.h
HINTS
${_ARGP_ROOT_HINTS}
argp.h
PATHS
${_ARGP_ROOT_PATHS}
)
mark_as_advanced(ARGP_ROOT_DIR)
find_path(ARGP_INCLUDE_DIR
NAMES
argp.h
PATHS
${ARGP_ROOT_DIR}/include
)
find_library(ARGP_LIBRARY
NAMES
argp
PATHS
${ARGP_ROOT_DIR}/lib
)
if (ARGP_LIBRARY)
set(ARGP_LIBRARIES
${ARGP_LIBRARIES}
${ARGP_LIBRARY}
/usr/include
/usr/local/include
/opt/local/include
/sw/include
)
endif (ARGP_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ARGP DEFAULT_MSG ARGP_LIBRARIES ARGP_INCLUDE_DIR)
find_library(ARGP_LIBRARY
NAMES
argp
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
)
set(ARGP_INCLUDE_DIRS
${ARGP_INCLUDE_DIR}
)
if (ARGP_LIBRARY)
set(ARGP_LIBRARIES
${ARGP_LIBRARIES}
${ARGP_LIBRARY}
)
endif (ARGP_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Argp DEFAULT_MSG ARGP_LIBRARIES ARGP_INCLUDE_DIRS)
# show the ARGP_INCLUDE_DIRS and ARGP_LIBRARIES variables only in the advanced view
mark_as_advanced(ARGP_INCLUDE_DIRS ARGP_LIBRARIES)
endif (ARGP_LIBRARIES AND ARGP_INCLUDE_DIRS)
# show the ARGP_INCLUDE_DIR and ARGP_LIBRARIES variables only in the advanced view
mark_as_advanced(ARGP_INCLUDE_DIR ARGP_LIBRARIES)

View File

@@ -35,8 +35,6 @@ find_path(GCRYPT_INCLUDE_DIR
gcrypt.h
HINTS
${_GCRYPT_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
include
)
find_library(GCRYPT_LIBRARY
@@ -46,15 +44,13 @@ find_library(GCRYPT_LIBRARY
libgcrypt-11
HINTS
${_GCRYPT_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
lib
)
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY})
if (GCRYPT_INCLUDE_DIR)
file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]")
file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+.[0-9]+.[0-9]+\"")
string(REGEX REPLACE "^.*GCRYPT_VERSION.*([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" GCRYPT_VERSION "${_gcrypt_version_str}")
string(REGEX REPLACE "^.*GCRYPT_VERSION.*([0-9]+.[0-9]+.[0-9]+).*" "\\1" GCRYPT_VERSION "${_gcrypt_version_str}")
endif (GCRYPT_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)

View File

@@ -54,8 +54,7 @@ if (UNIX)
OUTPUT_VARIABLE
_GSSAPI_VENDOR_STRING)
if ((_GSSAPI_VENDOR_STRING MATCHES ".*Massachusetts.*") OR (_GSSAPI_VENDOR_STRING
MATCHES ".*MITKerberosShim.*"))
if (_GSSAPI_VENDOR_STRING MATCHES ".*Massachusetts.*")
set(GSSAPI_FLAVOR_MIT TRUE)
else()
execute_process(

View File

@@ -1,104 +0,0 @@
# - Try to find mbedTLS
# Once done this will define
#
# MBEDTLS_FOUND - system has mbedTLS
# MBEDTLS_INCLUDE_DIRS - the mbedTLS include directory
# MBEDTLS_LIBRARIES - Link these to use mbedTLS
# MBEDTLS_DEFINITIONS - Compiler switches required for using mbedTLS
#=============================================================================
# Copyright (c) 2017 Sartura d.o.o.
#
# Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
#
set(_MBEDTLS_ROOT_HINTS
$ENV{MBEDTLS_ROOT_DIR}
${MBEDTLS_ROOT_DIR})
set(_MBEDTLS_ROOT_PATHS
"$ENV{PROGRAMFILES}/libmbedtls")
set(_MBEDTLS_ROOT_HINTS_AND_PATHS
HINTS ${_MBEDTLS_ROOT_HINTS}
PATHS ${_MBEDTLS_ROOT_PATHS})
find_path(MBEDTLS_INCLUDE_DIR
NAMES
mbedtls/config.h
HINTS
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
include
)
find_library(MBEDTLS_SSL_LIBRARY
NAMES
mbedtls
HINTS
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
lib
)
find_library(MBEDTLS_CRYPTO_LIBRARY
NAMES
mbedcrypto
HINTS
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
lib
)
find_library(MBEDTLS_X509_LIBRARY
NAMES
mbedx509
HINTS
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES
lib
)
set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
${MBEDTLS_X509_LIBRARY})
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
endif ()
include(FindPackageHandleStandardArgs)
if (MBEDTLS_VERSION)
find_package_handle_standard_args(MbedTLS
REQUIRED_VARS
MBEDTLS_INCLUDE_DIR
MBEDTLS_LIBRARIES
VERSION_VAR
MBEDTLS_VERSION
FAIL_MESSAGE
"Could NOT find mbedTLS, try to set the path to mbedTLS root folder
in the system variable MBEDTLS_ROOT_DIR"
)
else (MBEDTLS_VERSION)
find_package_handle_standard_args(MBedTLS
"Could NOT find mbedTLS, try to set the path to mbedLS root folder in
the system variable MBEDTLS_ROOT_DIR"
MBEDTLS_INCLUDE_DIR
MBEDTLS_LIBRARIES)
endif (MBEDTLS_VERSION)
# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view
mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES)

View File

@@ -1,118 +0,0 @@
#
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
#.rst:
# GenerateMap
# -----------
#
# This is a helper script for FindABImap.cmake.
#
# Generates a symbols version script using the abimap tool.
# This script is run in build time to use the correct command depending on the
# existence of the file provided ``CURRENT_MAP``.
#
# If the file exists, the ``abimap update`` subcommand is used to update the
# existing map. Otherwise, the ``abimap new`` subcommand is used to create a new
# map file.
#
# If the file provided in ``CURRENT_MAP`` exists, it is copied to the
# ``OUTPUT_PATH`` before updating.
# This is required because ``abimap`` do not generate output if no symbols were
# changed when updating an existing file.
#
# Expected defined variables
# --------------------------
#
# ``SYMBOLS``:
# Required file containing the symbols to be used as input. Usually this is
# the ``OUTPUT`` generated by ``extract_symbols()`` function provided in
# FindABImap.cmake
#
# ``RELEASE_NAME_VERSION``:
# Required, expects the library name and version information to be added to
# the symbols in the format ``library_name_1_2_3``
#
# ``CURRENT_MAP``:
# Required, expects the path to the current map file (or the path were it
# should be)
#
# ``OUTPUT_PATH``:
# Required, expects the output file path.
#
# ``ABIMAP_EXECUTABLE``:
# Required, expects the path to the ``abimap`` tool.
#
# Optionally defined variables
# ----------------------------
#
# ``FINAL``:
# If defined, will mark the modified set of symbols in the symbol version
# script as final, preventing later changes using ``abimap``.
#
# ``BREAK_ABI``:
# If defined, the build will not fail if symbols were removed.
# If defined and a symbol is removed, a new release is created containing
# all symbols from all released versions. This makes an incompatible release.
#
if (NOT DEFINED RELEASE_NAME_VERSION)
message(SEND_ERROR "RELEASE_NAME_VERSION not defined")
endif()
if (NOT DEFINED SYMBOLS)
message(SEND_ERROR "SYMBOLS not defined")
endif()
if (NOT DEFINED CURRENT_MAP)
message(SEND_ERROR "CURRENT_MAP not defined")
endif()
if (NOT DEFINED OUTPUT_PATH)
message(SEND_ERROR "OUTPUT_PATH not defined")
endif()
if (NOT ABIMAP_EXECUTABLE)
message(SEND_ERROR "ABIMAP_EXECUTABLE not defined")
endif()
set(ARGS_LIST)
if (FINAL)
list(APPEND ARGS_LIST "--final")
endif()
if (EXISTS ${CURRENT_MAP})
if (BREAK_ABI)
list(APPEND ARGS_LIST "--allow-abi-break")
endif()
execute_process(
COMMAND
${CMAKE_COMMAND} -E copy_if_different ${CURRENT_MAP} ${OUTPUT_PATH}
COMMAND
${ABIMAP_EXECUTABLE} update ${ARGS_LIST}
-r ${RELEASE_NAME_VERSION}
-i ${SYMBOLS}
-o ${OUTPUT_PATH}
${CURRENT_MAP}
RESULT_VARIABLE result
)
else ()
execute_process(
COMMAND
${ABIMAP_EXECUTABLE} new ${ARGS_LIST}
-r ${RELEASE_NAME_VERSION}
-i ${SYMBOLS}
-o ${OUTPUT_PATH}
RESULT_VARIABLE result
)
endif()
if (NOT "${result}" STREQUAL "0")
message(SEND_ERROR "Map generation failed")
endif()

View File

@@ -1,59 +0,0 @@
#
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
#.rst:
# GetFilesList
# ------------
#
# This is a helper script for FindABImap.cmake.
#
# Search in the provided directories for files matching the provided pattern.
# The list of files is then written to the output file.
#
# Expected defined variables
# --------------------------
#
# ``DIRECTORIES``:
# Required, expects a list of directories paths.
#
# ``FILES_PATTERNS``:
# Required, expects a list of patterns to be used to search files
#
# ``OUTPUT_PATH``:
# Required, expects the output file path.
if (NOT DEFINED DIRECTORIES)
message(SEND_ERROR "DIRECTORIES not defined")
endif()
if (NOT DEFINED FILES_PATTERNS)
message(SEND_ERROR "FILES_PATTERNS not defined")
endif()
if (NOT DEFINED OUTPUT_PATH)
message(SEND_ERROR "OUTPUT_PATH not defined")
endif()
string(REPLACE " " ";" DIRECTORIES_LIST "${DIRECTORIES}")
string(REPLACE " " ";" FILES_PATTERNS_LIST "${FILES_PATTERNS}")
# Create the list of expressions for the files
set(glob_expressions)
foreach(dir ${DIRECTORIES_LIST})
foreach(exp ${FILES_PATTERNS_LIST})
list(APPEND glob_expressions
"${dir}/${exp}"
)
endforeach()
endforeach()
# Create the list of files
file(GLOB files ${glob_expressions})
# Write to the output
file(WRITE ${OUTPUT_PATH} "${files}")

View File

@@ -1,23 +0,0 @@
set(CMAKE_C_FLAGS "-m32" CACHE STRING "C compiler flags" FORCE)
set(CMAKE_CXX_FLAGS "-m32" CACHE STRING "C++ compiler flags" FORCE)
set(LIB32 /usr/lib) # Fedora
if(EXISTS /usr/lib32)
set(LIB32 /usr/lib32) # Arch, Solus
endif()
set(CMAKE_SYSTEM_LIBRARY_PATH ${LIB32} CACHE STRING "system library search path" FORCE)
set(CMAKE_LIBRARY_PATH ${LIB32} CACHE STRING "library search path" FORCE)
# this is probably unlikely to be needed, but just in case
set(CMAKE_EXE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "executable linker flags" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "shared library linker flags" FORCE)
set(CMAKE_MODULE_LINKER_FLAGS "-m32 -L${LIB32}" CACHE STRING "module linker flags" FORCE)
# on Fedora and Arch and similar, point pkgconfig at 32 bit .pc files. We have
# to include the regular system .pc files as well (at the end), because some
# are not always present in the 32 bit directory
if(EXISTS ${LIB32}/pkgconfig)
set(ENV{PKG_CONFIG_LIBDIR} ${LIB32}/pkgconfig:/usr/share/pkgconfig:/usr/lib/pkgconfig:/usr/lib64/pkgconfig)
endiF()

View File

@@ -20,9 +20,6 @@
/* Define to 1 if you have the <aprpa/inet.h> header file. */
#cmakedefine HAVE_ARPA_INET_H 1
/* Define to 1 if you have the <glob.h> header file. */
#cmakedefine HAVE_GLOB_H 1
/* Define to 1 if you have the <pty.h> header file. */
#cmakedefine HAVE_PTY_H 1
@@ -38,21 +35,12 @@
/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/utime.h> header file. */
#cmakedefine HAVE_SYS_UTIME_H 1
/* Define to 1 if you have the <io.h> header file. */
#cmakedefine HAVE_IO_H 1
/* Define to 1 if you have the <termios.h> header file. */
#cmakedefine HAVE_TERMIOS_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H 1
/* Define to 1 if you have the <openssl/aes.h> header file. */
#cmakedefine HAVE_OPENSSL_AES_H 1
@@ -86,26 +74,8 @@
/* Define to 1 if you have eliptic curve cryptography */
#cmakedefine HAVE_ECC 1
/* Define to 1 if you have DSA */
#cmakedefine HAVE_DSA 1
/*************************** FUNCTIONS ***************************/
/* Define to 1 if you have the `EVP_aes128_ctr' function. */
#cmakedefine HAVE_OPENSSL_EVP_AES_CTR 1
/* Define to 1 if you have the `EVP_aes128_cbc' function. */
#cmakedefine HAVE_OPENSSL_EVP_AES_CBC 1
/* Define to 1 if you have the `CRYPTO_THREADID_set_callback' function. */
#cmakedefine HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK 1
/* Define to 1 if you have the `CRYPTO_ctr128_encrypt' function. */
#cmakedefine HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT 1
/* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */
#cmakedefine HAVE_OPENSSL_EVP_CIPHER_CTX_NEW 1
/* Define to 1 if you have the `snprintf' function. */
#cmakedefine HAVE_SNPRINTF 1
@@ -160,18 +130,6 @@
/* Define to 1 if you have the `_strtoui64' function. */
#cmakedefine HAVE__STRTOUI64 1
/* Define to 1 if you have the `glob' function. */
#cmakedefine HAVE_GLOB 1
/* Define to 1 if you have the `explicit_bzero' function. */
#cmakedefine HAVE_EXPLICIT_BZERO 1
/* Define to 1 if you have the `memset_s' function. */
#cmakedefine HAVE_MEMSET_S 1
/* Define to 1 if you have the `SecureZeroMemory' function. */
#cmakedefine HAVE_SECURE_ZERO_MEMORY 1
/*************************** LIBRARIES ***************************/
/* Define to 1 if you have the `crypto' library (-lcrypto). */
@@ -180,9 +138,6 @@
/* Define to 1 if you have the `gcrypt' library (-lgcrypt). */
#cmakedefine HAVE_LIBGCRYPT 1
/* Define to 1 if you have the 'mbedTLS' library (-lmbedtls). */
#cmakedefine HAVE_LIBMBEDCRYPTO 1
/* Define to 1 if you have the `pthread' library (-lpthread). */
#cmakedefine HAVE_PTHREAD 1
@@ -191,16 +146,12 @@
#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1
#cmakedefine HAVE_MSC_THREAD_LOCAL_STORAGE 1
#cmakedefine HAVE_FALLTHROUGH_ATTRIBUTE 1
#cmakedefine HAVE_GCC_VOLATILE_MEMORY_PROTECTION 1
#cmakedefine HAVE_GCC_NARG_MACRO 1
#cmakedefine HAVE_COMPILER__FUNC__ 1
#cmakedefine HAVE_COMPILER__FUNCTION__ 1
#cmakedefine HAVE_GCC_BOUNDED_ATTRIBUTE 1
/* Define to 1 if you want to enable GSSAPI */
#cmakedefine WITH_GSSAPI 1
@@ -210,15 +161,15 @@
/* Define to 1 if you want to enable SFTP */
#cmakedefine WITH_SFTP 1
/* Define to 1 if you want to enable SSH1 */
#cmakedefine WITH_SSH1 1
/* Define to 1 if you want to enable server support */
#cmakedefine WITH_SERVER 1
/* Define to 1 if you want to enable debug output for crypto functions */
#cmakedefine DEBUG_CRYPTO 1
/* Define to 1 if you want to enable debug output for packet functions */
#cmakedefine DEBUG_PACKET 1
/* Define to 1 if you want to enable pcap output support (experimental) */
#cmakedefine WITH_PCAP 1

View File

@@ -46,7 +46,7 @@ The ssh_userauth_publickey_auto() function also tries to authenticate using the
SSH agent, if you have one running, or the "none" method otherwise.
If you wish to authenticate with public key by your own, follow these steps:
- Retrieve the public key with ssh_pki_import_pubkey_file().
- Retrieve the public key with ssh_import_pubkey_file().
- Offer the public key to the SSH server using ssh_userauth_try_publickey().
If the return value is SSH_AUTH_SUCCESS, the SSH server accepts to
authenticate using the public key and you can go to the next step.
@@ -305,7 +305,7 @@ int test_several_auth_methods(ssh_session session)
int method, rc;
rc = ssh_userauth_none(session, NULL);
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_ERROR) {
if (rc != SSH_AUTH_SUCCESS) {
return rc;
}

View File

@@ -158,7 +158,7 @@ you just connected to is known and safe to use (remember, SSH is about security
authentication).
There are two ways of doing this:
- The first way (recommended) is to use the ssh_session_is_known_server()
- The first way (recommended) is to use the ssh_is_server_known()
function. This function will look into the known host file
(~/.ssh/known_hosts on UNIX), look for the server hostname's pattern,
and determine whether this host is present or not in the list.
@@ -185,89 +185,74 @@ examples/ directory:
int verify_knownhost(ssh_session session)
{
enum ssh_known_hosts_e state;
unsigned char *hash = NULL;
ssh_key srv_pubkey = NULL;
size_t hlen;
char buf[10];
char *hexa;
char *p;
int cmp;
int rc;
int state, hlen;
unsigned char *hash = NULL;
char *hexa;
char buf[10];
rc = ssh_get_server_publickey(session, &srv_pubkey);
if (rc < 0) {
state = ssh_is_server_known(session);
hlen = ssh_get_pubkey_hash(session, &hash);
if (hlen < 0)
return -1;
switch (state)
{
case SSH_SERVER_KNOWN_OK:
break; /* ok */
case SSH_SERVER_KNOWN_CHANGED:
fprintf(stderr, "Host key for server changed: it is now:\n");
ssh_print_hexa("Public key hash", hash, hlen);
fprintf(stderr, "For security reasons, connection will be stopped\n");
free(hash);
return -1;
case SSH_SERVER_FOUND_OTHER:
fprintf(stderr, "The host key for this server was not found but an other"
"type of key exists.\n");
fprintf(stderr, "An attacker might change the default server key to"
"confuse your client into thinking the key does not exist\n");
free(hash);
return -1;
case SSH_SERVER_FILE_NOT_FOUND:
fprintf(stderr, "Could not find known host file.\n");
fprintf(stderr, "If you accept the host key here, the file will be"
"automatically created.\n");
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
case SSH_SERVER_NOT_KNOWN:
hexa = ssh_get_hexa(hash, hlen);
fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
fprintf(stderr, "Public key hash: %s\n", hexa);
free(hexa);
if (fgets(buf, sizeof(buf), stdin) == NULL)
{
free(hash);
return -1;
}
rc = ssh_get_publickey_hash(srv_pubkey,
SSH_PUBLICKEY_HASH_SHA1,
&hash,
&hlen);
ssh_key_free(srv_pubkey);
if (rc < 0) {
}
if (strncasecmp(buf, "yes", 3) != 0)
{
free(hash);
return -1;
}
}
if (ssh_write_knownhost(session) < 0)
{
fprintf(stderr, "Error %s\n", strerror(errno));
free(hash);
return -1;
}
break;
state = ssh_session_is_known_server(session);
switch (state) {
case SSH_KNOWN_HOSTS_OK:
/* OK */
case SSH_SERVER_ERROR:
fprintf(stderr, "Error %s", ssh_get_error(session));
free(hash);
return -1;
}
break;
case SSH_KNOWN_HOSTS_CHANGED:
fprintf(stderr, "Host key for server changed: it is now:\n");
ssh_print_hexa("Public key hash", hash, hlen);
fprintf(stderr, "For security reasons, connection will be stopped\n");
ssh_clean_pubkey_hash(&hash);
return -1;
case SSH_KNOWN_HOSTS_OTHER:
fprintf(stderr, "The host key for this server was not found but an other"
"type of key exists.\n");
fprintf(stderr, "An attacker might change the default server key to"
"confuse your client into thinking the key does not exist\n");
ssh_clean_pubkey_hash(&hash);
return -1;
case SSH_KNOWN_HOSTS_NOT_FOUND:
fprintf(stderr, "Could not find known host file.\n");
fprintf(stderr, "If you accept the host key here, the file will be"
"automatically created.\n");
/* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */
case SSH_KNOWN_HOSTS_UNKNOWN:
hexa = ssh_get_hexa(hash, hlen);
fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
fprintf(stderr, "Public key hash: %s\n", hexa);
ssh_string_free_char(hexa);
ssh_clean_pubkey_hash(&hash);
p = fgets(buf, sizeof(buf), stdin);
if (p == NULL) {
return -1;
}
cmp = strncasecmp(buf, "yes", 3);
if (cmp != 0) {
return -1;
}
rc = ssh_session_update_known_hosts(session);
if (rc < 0) {
fprintf(stderr, "Error %s\n", strerror(errno));
return -1;
}
break;
case SSH_KNOWN_HOSTS_ERROR:
fprintf(stderr, "Error %s", ssh_get_error(session));
ssh_clean_pubkey_hash(&hash);
return -1;
}
ssh_clean_pubkey_hash(&hash);
return 0;
free(hash);
return 0;
}
@endcode
@@ -275,10 +260,9 @@ int verify_knownhost(ssh_session session)
@see ssh_disconnect
@see ssh_get_error
@see ssh_get_error_code
@see ssh_get_server_publickey
@see ssh_get_publickey_hash
@see ssh_session_is_known_server
@see ssh_session_update_known_hosts
@see ssh_get_pubkey_hash
@see ssh_is_server_known
@see ssh_write_knownhost
@subsection auth Authenticating the user

View File

@@ -19,16 +19,16 @@ the interesting functions as you go.
The libssh library provides:
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
- <strong>Hostkey Types</strong>: <i>ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521</i>, ssh-dss, ssh-rsa
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc, none
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256@libssh.org, ecdh-sha2-nistp256</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
- <strong>Hostkey Types</strong>: <i>ecdsa-sha2-nistp256</i>, ssh-dss, ssh-rsa
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, des-cbc-ssh1, blowfish-cbc, none
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
- <strong>MAC hashes</strong>: hmac-sha1, hmac-sha2-256, hmac-sha2-384, hmac-sha2-512, hmac-md5, none
- <strong>MAC hashes</strong>: hmac-sha1, none
- <strong>Authentication</strong>: none, password, public-key, hostbased, keyboard-interactive, <i>gssapi-with-mic</i>
- <strong>Channels</strong>: shell, exec (incl. SCP wrapper), direct-tcpip, subsystem, <i>auth-agent-req@openssh.com</i>
- <strong>Global Requests</strong>: tcpip-forward, forwarded-tcpip
- <strong>Channel Requests</strong>: x11, pty, <i>exit-status, signal, exit-signal, keepalive@openssh.com, auth-agent-req@openssh.com</i>
- <strong>Subsystems</strong>: sftp(version 3), <i>OpenSSH Extensions</i>
- <strong>Subsystems</strong>: sftp(version 3), publickey(version 2), <i>OpenSSH Extensions</i>
- <strong>SFTP</strong>: <i>statvfs@openssh.com, fstatvfs@openssh.com</i>
- <strong>Thread-safe</strong>: Just don't share sessions
- <strong>Non-blocking</strong>: it can be used both blocking and non-blocking

View File

@@ -11,9 +11,9 @@ include_directories(
${CMAKE_BINARY_DIR}
)
if (ARGP_INCLUDE_DIR)
include_directories(${ARGP_INCLUDE_DIR})
endif()
if (BSD OR SOLARIS OR OSX)
find_package(Argp)
endif (BSD OR SOLARIS OR OSX)
if (UNIX AND NOT WIN32)
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
@@ -30,27 +30,27 @@ if (UNIX AND NOT WIN32)
target_link_libraries(samplesftp ${LIBSSH_SHARED_LIBRARY})
endif (WITH_SFTP)
add_executable(ssh-client ssh_client.c ${examples_SRCS})
target_link_libraries(ssh-client ${LIBSSH_SHARED_LIBRARY})
add_executable(samplessh sample.c ${examples_SRCS})
target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY})
if (WITH_SERVER AND (ARGP_LIBRARY OR HAVE_ARGP_H))
if (WITH_SERVER)
if (HAVE_LIBUTIL)
add_executable(ssh_server_fork ssh_server_fork.c)
target_link_libraries(ssh_server_fork ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY} util)
target_link_libraries(ssh_server_fork ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES} util)
endif (HAVE_LIBUTIL)
if (WITH_GSSAPI AND GSSAPI_FOUND)
add_executable(samplesshd-cb samplesshd-cb.c)
target_link_libraries(samplesshd-cb ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
target_link_libraries(samplesshd-cb ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES})
add_executable(proxy proxy.c)
target_link_libraries(proxy ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
target_link_libraries(proxy ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES})
endif (WITH_GSSAPI AND GSSAPI_FOUND)
add_executable(samplesshd-kbdint samplesshd-kbdint.c)
target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES})
endif()
endif (WITH_SERVER)
endif (UNIX AND NOT WIN32)
add_executable(exec exec.c ${examples_SRCS})

View File

@@ -17,14 +17,11 @@ 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libssh/priv.h"
#include <libssh/libssh.h>
#include "examples_common.h"
@@ -34,14 +31,16 @@ clients must be made or how a client should react.
int verify_knownhost(ssh_session session){
char *hexa;
enum ssh_known_hosts_e state;
int state;
char buf[10];
unsigned char *hash = NULL;
size_t hlen;
ssh_key srv_pubkey;
int rc;
rc = ssh_get_server_publickey(session, &srv_pubkey);
state=ssh_is_server_known(session);
rc = ssh_get_publickey(session, &srv_pubkey);
if (rc < 0) {
return -1;
}
@@ -55,28 +54,25 @@ int verify_knownhost(ssh_session session){
return -1;
}
state = ssh_session_is_known_server(session);
switch(state){
case SSH_KNOWN_HOSTS_OK:
case SSH_SERVER_KNOWN_OK:
break; /* ok */
case SSH_KNOWN_HOSTS_CHANGED:
case SSH_SERVER_KNOWN_CHANGED:
fprintf(stderr,"Host key for server changed : server's one is now :\n");
ssh_print_hexa("Public key hash",hash, hlen);
ssh_clean_pubkey_hash(&hash);
fprintf(stderr,"For security reason, connection will be stopped\n");
return -1;
case SSH_KNOWN_HOSTS_OTHER:
case SSH_SERVER_FOUND_OTHER:
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
fprintf(stderr,"An attacker might change the default server key to confuse your client"
"into thinking the key does not exist\n"
"We advise you to rerun the client with -d or -r for more safety.\n");
return -1;
case SSH_KNOWN_HOSTS_NOT_FOUND:
case SSH_SERVER_FILE_NOT_FOUND:
fprintf(stderr,"Could not find known host file. If you accept the host key here,\n");
fprintf(stderr,"the file will be automatically created.\n");
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
FALL_THROUGH;
case SSH_SERVER_NOT_KNOWN:
hexa = ssh_get_hexa(hash, hlen);
fprintf(stderr,"The server is unknown. Do you trust the host key ?\n");
@@ -104,7 +100,7 @@ int verify_knownhost(ssh_session session){
}
break;
case SSH_KNOWN_HOSTS_ERROR:
case SSH_SERVER_ERROR:
ssh_clean_pubkey_hash(&hash);
fprintf(stderr,"%s",ssh_get_error(session));
return -1;

523
examples/sample.c Normal file
View File

@@ -0,0 +1,523 @@
/* 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.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
#include <sys/ioctl.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <libssh/callbacks.h>
#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include "examples_common.h"
#define MAXCMD 10
static char *host;
static char *user;
static char *cmds[MAXCMD];
static struct termios terminal;
static char *pcap_file=NULL;
static char *proxycommand;
static int auth_callback(const char *prompt, char *buf, size_t len,
int echo, int verify, void *userdata) {
(void) verify;
(void) userdata;
return ssh_getpass(prompt, buf, len, echo, verify);
}
struct ssh_callbacks_struct cb = {
.auth_function=auth_callback,
.userdata=NULL
};
static void add_cmd(char *cmd){
int n;
for (n = 0; (n < MAXCMD) && cmds[n] != NULL; n++);
if (n == MAXCMD) {
return;
}
cmds[n]=strdup(cmd);
}
static void usage(){
fprintf(stderr,"Usage : ssh [options] [login@]hostname\n"
"sample client - libssh-%s\n"
"Options :\n"
" -l user : log in as user\n"
" -p port : connect to port\n"
" -d : use DSS to verify host public key\n"
" -r : use RSA to verify host public key\n"
#ifdef WITH_PCAP
" -P file : create a pcap debugging file\n"
#endif
#ifndef _WIN32
" -T proxycommand : command to execute as a socket proxy\n"
#endif
,
ssh_version(0));
exit(0);
}
static int opts(int argc, char **argv){
int i;
// for(i=0;i<argc;i++)
// printf("%d : %s\n",i,argv[i]);
/* insert your own arguments here */
while((i=getopt(argc,argv,"T:P:"))!=-1){
switch(i){
case 'P':
pcap_file=optarg;
break;
#ifndef _WIN32
case 'T':
proxycommand=optarg;
break;
#endif
default:
fprintf(stderr,"unknown option %c\n",optopt);
usage();
}
}
if(optind < argc)
host=argv[optind++];
while(optind < argc)
add_cmd(argv[optind++]);
if(host==NULL)
usage();
return 0;
}
#ifndef HAVE_CFMAKERAW
static void cfmakeraw(struct termios *termios_p){
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;
}
#endif
static void do_cleanup(int i) {
/* unused variable */
(void) i;
tcsetattr(0,TCSANOW,&terminal);
}
static void do_exit(int i) {
/* unused variable */
(void) i;
do_cleanup(0);
exit(0);
}
ssh_channel chan;
int signal_delayed=0;
static void sigwindowchanged(int i){
(void) i;
signal_delayed=1;
}
static void setsignal(void){
signal(SIGWINCH, sigwindowchanged);
signal_delayed=0;
}
static void sizechanged(void){
struct winsize win = { 0, 0, 0, 0 };
ioctl(1, TIOCGWINSZ, &win);
ssh_channel_change_pty_size(chan,win.ws_col, win.ws_row);
// printf("Changed pty size\n");
setsignal();
}
/* There are two flavors of select loop: the one based on
* ssh_select and the one based on channel_select.
* The ssh_select one permits you to give your own file descriptors to
* follow. It is thus a complete select loop.
* The second one only selects on channels. It is simplier to use
* but doesn't permit you to fill in your own file descriptor. It is
* more adapted if you can't use ssh_select as a main loop (because
* you already have another main loop system).
*/
#ifdef USE_CHANNEL_SELECT
/* channel_select base main loop, with a standard select(2)
*/
static void select_loop(ssh_session session,ssh_channel channel){
fd_set fds;
struct timeval timeout;
char buffer[4096];
ssh_buffer readbuf=ssh_buffer_new();
ssh_channel channels[2];
int lus;
int eof=0;
int maxfd;
int ret;
while(channel){
/* when a signal is caught, ssh_select will return
* with SSH_EINTR, which means it should be started
* again. It lets you handle the signal the faster you
* can, like in this window changed example. Of course, if
* your signal handler doesn't call libssh at all, you're
* free to handle signals directly in sighandler.
*/
do{
FD_ZERO(&fds);
if(!eof)
FD_SET(0,&fds);
timeout.tv_sec=30;
timeout.tv_usec=0;
FD_SET(ssh_get_fd(session),&fds);
maxfd=ssh_get_fd(session)+1;
ret=select(maxfd,&fds,NULL,NULL,&timeout);
if(ret==EINTR)
continue;
if(FD_ISSET(0,&fds)){
lus=read(0,buffer,sizeof(buffer));
if(lus)
ssh_channel_write(channel,buffer,lus);
else {
eof=1;
ssh_channel_send_eof(channel);
}
}
if(FD_ISSET(ssh_get_fd(session),&fds)){
ssh_set_fd_toread(session);
}
channels[0]=channel; // set the first channel we want to read from
channels[1]=NULL;
ret=ssh_channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll
if(signal_delayed)
sizechanged();
} while (ret==EINTR || ret==SSH_EINTR);
// we already looked for input from stdin. Now, we are looking for input from the channel
if(channel && ssh_channel_is_closed(channel)){
ssh_channel_free(channel);
channel=NULL;
channels[0]=NULL;
}
if(channels[0]){
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)>0){
lus=channel_read_buffer(channel,readbuf,0,0);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if(lus==0){
ssh_channel_free(channel);
channel=channels[0]=NULL;
} else
if (write(1,ssh_buffer_get_begin(readbuf),lus) < 0) {
fprintf(stderr, "Error writing to buffer\n");
return;
}
}
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)>0){ /* stderr */
lus=channel_read_buffer(channel,readbuf,0,1);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if(lus==0){
ssh_channel_free(channel);
channel=channels[0]=NULL;
} else
if (write(2,ssh_buffer_get_begin(readbuf),lus) < 0) {
fprintf(stderr, "Error writing to buffer\n");
return;
}
}
}
if(channel && ssh_channel_is_closed(channel)){
ssh_channel_free(channel);
channel=NULL;
}
}
ssh_buffer_free(readbuf);
}
#else /* CHANNEL_SELECT */
static void select_loop(ssh_session session,ssh_channel channel){
fd_set fds;
struct timeval timeout;
char buffer[4096];
/* channels will be set to the channels to poll.
* outchannels will contain the result of the poll
*/
ssh_channel channels[2], outchannels[2];
int lus;
int eof=0;
int maxfd;
unsigned int r;
int ret;
while(channel){
do{
int fd;
FD_ZERO(&fds);
if(!eof)
FD_SET(0,&fds);
timeout.tv_sec=30;
timeout.tv_usec=0;
fd = ssh_get_fd(session);
if (fd < 0) {
fprintf(stderr, "Error getting fd\n");
return;
}
FD_SET(fd, &fds);
maxfd = fd + 1;
channels[0]=channel; // set the first channel we want to read from
channels[1]=NULL;
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
if(signal_delayed)
sizechanged();
if(ret==EINTR)
continue;
if(FD_ISSET(0,&fds)){
lus=read(0,buffer,sizeof(buffer));
if(lus)
ssh_channel_write(channel,buffer,lus);
else {
eof=1;
ssh_channel_send_eof(channel);
}
}
if(channel && ssh_channel_is_closed(channel)){
ssh_channel_free(channel);
channel=NULL;
channels[0]=NULL;
}
if(outchannels[0]){
while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,0))!=0){
lus=ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),0);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if(lus==0){
ssh_channel_free(channel);
channel=channels[0]=NULL;
} else
if (write(1,buffer,lus) < 0) {
fprintf(stderr, "Error writing to buffer\n");
return;
}
}
while(channel && ssh_channel_is_open(channel) && (r = ssh_channel_poll(channel,1))!=0){ /* stderr */
lus=ssh_channel_read(channel,buffer,sizeof(buffer) > r ? r : sizeof(buffer),1);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if(lus==0){
ssh_channel_free(channel);
channel=channels[0]=NULL;
} else
if (write(2,buffer,lus) < 0) {
fprintf(stderr, "Error writing to buffer\n");
return;
}
}
}
if(channel && ssh_channel_is_closed(channel)){
ssh_channel_free(channel);
channel=NULL;
}
} while (ret==EINTR || ret==SSH_EINTR);
}
}
#endif
static void shell(ssh_session session){
ssh_channel channel;
struct termios terminal_local;
int interactive=isatty(0);
channel = ssh_channel_new(session);
if(interactive){
tcgetattr(0,&terminal_local);
memcpy(&terminal,&terminal_local,sizeof(struct termios));
}
if(ssh_channel_open_session(channel)){
printf("error opening channel : %s\n",ssh_get_error(session));
return;
}
chan=channel;
if(interactive){
ssh_channel_request_pty(channel);
sizechanged();
}
if(ssh_channel_request_shell(channel)){
printf("Requesting shell : %s\n",ssh_get_error(session));
return;
}
if(interactive){
cfmakeraw(&terminal_local);
tcsetattr(0,TCSANOW,&terminal_local);
setsignal();
}
signal(SIGTERM,do_cleanup);
select_loop(session,channel);
if(interactive)
do_cleanup(0);
}
static void batch_shell(ssh_session session){
ssh_channel channel;
char buffer[1024];
int i,s=0;
for(i=0;i<MAXCMD && cmds[i];++i) {
s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
free(cmds[i]);
cmds[i] = NULL;
}
channel=ssh_channel_new(session);
ssh_channel_open_session(channel);
if(ssh_channel_request_exec(channel,buffer)){
printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
return;
}
select_loop(session,channel);
}
static int client(ssh_session session){
int auth=0;
char *banner;
int state;
if (user)
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0)
return -1;
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
return -1;
if (proxycommand != NULL){
if(ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand))
return -1;
}
ssh_options_parse_config(session, NULL);
if(ssh_connect(session)){
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
return -1;
}
state=verify_knownhost(session);
if (state != 0)
return -1;
ssh_userauth_none(session, NULL);
banner=ssh_get_issue_banner(session);
if(banner){
printf("%s\n",banner);
free(banner);
}
auth=authenticate_console(session);
if(auth != SSH_AUTH_SUCCESS){
return -1;
}
if(!cmds[0])
shell(session);
else
batch_shell(session);
return 0;
}
ssh_pcap_file pcap;
void set_pcap(ssh_session session);
void set_pcap(ssh_session session){
if(!pcap_file)
return;
pcap=ssh_pcap_file_new();
if(!pcap)
return;
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
printf("Error opening pcap file\n");
ssh_pcap_file_free(pcap);
pcap=NULL;
return;
}
ssh_set_pcap_file(session,pcap);
}
void cleanup_pcap(void);
void cleanup_pcap(){
if(pcap)
ssh_pcap_file_free(pcap);
pcap=NULL;
}
int main(int argc, char **argv){
ssh_session session;
session = ssh_new();
ssh_callbacks_init(&cb);
ssh_set_callbacks(session,&cb);
if(ssh_options_getopt(session, &argc, argv)) {
fprintf(stderr, "error parsing command line :%s\n",
ssh_get_error(session));
usage();
}
opts(argc,argv);
signal(SIGTERM, do_exit);
set_pcap(session);
client(session);
ssh_disconnect(session);
ssh_free(session);
cleanup_pcap();
ssh_finalize();
return 0;
}

View File

@@ -22,12 +22,9 @@ program.
#include <libssh/libssh.h>
#include "examples_common.h"
static int verbosity = 0;
static const char *createcommand =
"rm -fr /tmp/libssh_tests && mkdir /tmp/libssh_tests && "
"cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
static char *host = NULL;
int verbosity=0;
const char *createcommand="rm -fr /tmp/libssh_tests && mkdir /tmp/libssh_tests && cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
char *host=NULL;
static void usage(const char *argv0){
fprintf(stderr,"Usage : %s [options] host\n"
"sample tiny scp downloader client - libssh-%s\n"

View File

@@ -3,7 +3,7 @@
#include <libssh/libssh.h>
#include "examples_common.h"
#define LIMIT 0x100000000UL
#define LIMIT 0x100000000
int main(void) {
ssh_session session;

View File

@@ -1,356 +0,0 @@
/* 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.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
#include <sys/ioctl.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <libssh/callbacks.h>
#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include "examples_common.h"
#define MAXCMD 10
static char *host;
static char *user;
static char *cmds[MAXCMD];
static struct termios terminal;
static char *pcap_file=NULL;
static char *proxycommand;
static int auth_callback(const char *prompt, char *buf, size_t len,
int echo, int verify, void *userdata) {
(void) verify;
(void) userdata;
return ssh_getpass(prompt, buf, len, echo, verify);
}
struct ssh_callbacks_struct cb = {
.auth_function=auth_callback,
.userdata=NULL
};
static void add_cmd(char *cmd){
int n;
for (n = 0; (n < MAXCMD) && cmds[n] != NULL; n++);
if (n == MAXCMD) {
return;
}
cmds[n]=strdup(cmd);
}
static void usage(void)
{
fprintf(stderr,
"Usage : ssh [options] [login@]hostname\n"
"sample client - libssh-%s\n"
"Options :\n"
" -l user : log in as user\n"
" -p port : connect to port\n"
" -d : use DSS to verify host public key\n"
" -r : use RSA to verify host public key\n"
#ifdef WITH_PCAP
" -P file : create a pcap debugging file\n"
#endif
#ifndef _WIN32
" -T proxycommand : command to execute as a socket proxy\n"
#endif
"\n",
ssh_version(0));
exit(0);
}
static int opts(int argc, char **argv){
int i;
// for(i=0;i<argc;i++)
// printf("%d : %s\n",i,argv[i]);
/* insert your own arguments here */
while((i=getopt(argc,argv,"T:P:"))!=-1){
switch(i){
case 'P':
pcap_file=optarg;
break;
#ifndef _WIN32
case 'T':
proxycommand=optarg;
break;
#endif
default:
fprintf(stderr,"unknown option %c\n",optopt);
usage();
}
}
if(optind < argc)
host=argv[optind++];
while(optind < argc)
add_cmd(argv[optind++]);
if(host==NULL)
usage();
return 0;
}
#ifndef HAVE_CFMAKERAW
static void cfmakeraw(struct termios *termios_p){
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;
}
#endif
static void do_cleanup(int i) {
/* unused variable */
(void) i;
tcsetattr(0,TCSANOW,&terminal);
}
static void do_exit(int i) {
/* unused variable */
(void) i;
do_cleanup(0);
exit(0);
}
ssh_channel chan;
int signal_delayed=0;
static void sigwindowchanged(int i){
(void) i;
signal_delayed=1;
}
static void setsignal(void){
signal(SIGWINCH, sigwindowchanged);
signal_delayed=0;
}
static void sizechanged(void){
struct winsize win = { 0, 0, 0, 0 };
ioctl(1, TIOCGWINSZ, &win);
ssh_channel_change_pty_size(chan,win.ws_col, win.ws_row);
// printf("Changed pty size\n");
setsignal();
}
static void select_loop(ssh_session session,ssh_channel channel){
ssh_connector connector_in, connector_out, connector_err;
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_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_event_add_connector(event, connector_out);
/* stderr */
connector_err = ssh_connector_new(session);
ssh_connector_set_out_fd(connector_err, 2);
ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
ssh_event_add_connector(event, connector_err);
while(ssh_channel_is_open(channel)){
if(signal_delayed)
sizechanged();
ssh_event_dopoll(event, 60000);
}
ssh_event_remove_connector(event, connector_in);
ssh_event_remove_connector(event, connector_out);
ssh_event_remove_connector(event, connector_err);
ssh_connector_free(connector_in);
ssh_connector_free(connector_out);
ssh_connector_free(connector_err);
ssh_event_free(event);
ssh_channel_free(channel);
}
static void shell(ssh_session session){
ssh_channel channel;
struct termios terminal_local;
int interactive=isatty(0);
channel = ssh_channel_new(session);
if(interactive){
tcgetattr(0,&terminal_local);
memcpy(&terminal,&terminal_local,sizeof(struct termios));
}
if(ssh_channel_open_session(channel)){
printf("error opening channel : %s\n",ssh_get_error(session));
return;
}
chan=channel;
if(interactive){
ssh_channel_request_pty(channel);
sizechanged();
}
if(ssh_channel_request_shell(channel)){
printf("Requesting shell : %s\n",ssh_get_error(session));
return;
}
if(interactive){
cfmakeraw(&terminal_local);
tcsetattr(0,TCSANOW,&terminal_local);
setsignal();
}
signal(SIGTERM,do_cleanup);
select_loop(session,channel);
if(interactive)
do_cleanup(0);
}
static void batch_shell(ssh_session session){
ssh_channel channel;
char buffer[1024];
int i,s=0;
for(i=0;i<MAXCMD && cmds[i];++i) {
s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
free(cmds[i]);
cmds[i] = NULL;
}
channel=ssh_channel_new(session);
ssh_channel_open_session(channel);
if(ssh_channel_request_exec(channel,buffer)){
printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
return;
}
select_loop(session,channel);
}
static int client(ssh_session session){
int auth=0;
char *banner;
int state;
if (user)
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0)
return -1;
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
return -1;
if (proxycommand != NULL){
if(ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, proxycommand))
return -1;
}
ssh_options_parse_config(session, NULL);
if(ssh_connect(session)){
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
return -1;
}
state=verify_knownhost(session);
if (state != 0)
return -1;
ssh_userauth_none(session, NULL);
banner=ssh_get_issue_banner(session);
if(banner){
printf("%s\n",banner);
free(banner);
}
auth=authenticate_console(session);
if(auth != SSH_AUTH_SUCCESS){
return -1;
}
if(!cmds[0])
shell(session);
else
batch_shell(session);
return 0;
}
ssh_pcap_file pcap;
void set_pcap(ssh_session session);
void set_pcap(ssh_session session){
if(!pcap_file)
return;
pcap=ssh_pcap_file_new();
if(!pcap)
return;
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
printf("Error opening pcap file\n");
ssh_pcap_file_free(pcap);
pcap=NULL;
return;
}
ssh_set_pcap_file(session,pcap);
}
void cleanup_pcap(void);
void cleanup_pcap(){
if(pcap)
ssh_pcap_file_free(pcap);
pcap=NULL;
}
int main(int argc, char **argv){
ssh_session session;
session = ssh_new();
ssh_callbacks_init(&cb);
ssh_set_callbacks(session,&cb);
if(ssh_options_getopt(session, &argc, argv)) {
fprintf(stderr, "error parsing command line :%s\n",
ssh_get_error(session));
usage();
}
opts(argc,argv);
signal(SIGTERM, do_exit);
set_pcap(session);
client(session);
ssh_disconnect(session);
ssh_free(session);
cleanup_pcap();
ssh_finalize();
return 0;
}

View File

@@ -14,9 +14,9 @@ The goal is to show the API in action.
#include "config.h"
#include <libssh/callbacks.h>
#include <libssh/poll.h>
#include <libssh/server.h>
#include <poll.h>
#ifdef HAVE_ARGP_H
#include <argp.h>
#endif
@@ -621,7 +621,6 @@ int main(int argc, char **argv) {
ssh_session session;
ssh_event event;
struct sigaction sa;
int rc;
/* Set up SIGCHLD handler. */
sa.sa_handler = sigchld_handler;
@@ -632,17 +631,8 @@ int main(int argc, char **argv) {
return 1;
}
rc = ssh_init();
if (rc < 0) {
fprintf(stderr, "ssh_init failed\n");
return 1;
}
ssh_init();
sshbind = ssh_bind_new();
if (sshbind == NULL) {
fprintf(stderr, "ssh_bind_new failed\n");
return 1;
}
#ifdef HAVE_ARGP_H
argp_parse(&argp, argc, argv, 0, 0, sshbind);

View File

@@ -15,6 +15,13 @@ if (WITH_SFTP)
)
endif (WITH_SFTP)
if (WITH_SSH1)
set(libssh_HDRS
${libssh_HDRS}
ssh1.h
)
endif (WITH_SSH1)
if (WITH_SERVER)
set(libssh_HDRS
${libssh_HDRS}

View File

@@ -81,16 +81,16 @@ struct ssh_agent_struct {
*
* @return An allocated ssh agent structure or NULL on error.
*/
struct ssh_agent_struct *ssh_agent_new(struct ssh_session_struct *session);
struct ssh_agent_struct *agent_new(struct ssh_session_struct *session);
void ssh_agent_close(struct ssh_agent_struct *agent);
void agent_close(struct ssh_agent_struct *agent);
/**
* @brief Free an allocated ssh agent structure.
*
* @param agent The ssh agent structure to free.
*/
void ssh_agent_free(struct ssh_agent_struct *agent);
void agent_free(struct ssh_agent_struct *agent);
/**
* @brief Check if the ssh agent is running.
@@ -99,7 +99,7 @@ void ssh_agent_free(struct ssh_agent_struct *agent);
*
* @return 1 if it is running, 0 if not.
*/
int ssh_agent_is_running(struct ssh_session_struct *session);
int agent_is_running(struct ssh_session_struct *session);
int ssh_agent_get_ident_count(struct ssh_session_struct *session);
@@ -115,3 +115,4 @@ ssh_string ssh_agent_sign_data(ssh_session session,
#endif
#endif /* __AGENT_H */
/* vim: set ts=2 sw=2 et cindent: */

View File

@@ -49,6 +49,20 @@ ssh_kbdint ssh_kbdint_new(void);
void ssh_kbdint_clean(ssh_kbdint kbd);
void ssh_kbdint_free(ssh_kbdint kbd);
#ifdef WITH_SSH1
void ssh_auth1_handler(ssh_session session, uint8_t type);
/* auth1.c */
int ssh_userauth1_none(ssh_session session, const char *username);
int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
int type, ssh_string pubkey);
int ssh_userauth1_password(ssh_session session, const char *username,
const char *password);
#endif
/** @internal
* States of authentication in the client-side. They describe
* what was the last response from the server
@@ -90,6 +104,8 @@ enum ssh_auth_service_state_e {
SSH_AUTH_SERVICE_ACCEPTED,
/** Access to service denied (fatal) */
SSH_AUTH_SERVICE_DENIED,
/** Specific to SSH1 */
SSH_AUTH_SERVICE_USER_SENT
};
#endif /* AUTH_H_ */

View File

@@ -23,12 +23,11 @@
#include "libssh/libcrypto.h"
#include "libssh/libgcrypt.h"
#include "libssh/libmbedcrypto.h"
bignum ssh_make_string_bn(ssh_string string);
void ssh_make_string_bn_inplace(ssh_string string, bignum bnout);
ssh_string ssh_make_bignum_string(bignum num);
void ssh_print_bignum(const char *which, const bignum num);
bignum make_string_bn(ssh_string string);
void make_string_bn_inplace(ssh_string string, bignum bnout);
ssh_string make_bignum_string(bignum num);
void ssh_print_bignum(const char *which,bignum num);
#endif /* BIGNUM_H_ */

View File

@@ -53,7 +53,7 @@
typedef struct BlowfishContext {
uint32_t S[4][256]; /* S-Boxes */
uint32_t P[BLF_N + 2]; /* Subkeys */
} ssh_blf_ctx;
} blf_ctx;
/* Raw access to customized Blowfish
* blf_key is just:
@@ -61,24 +61,24 @@ typedef struct BlowfishContext {
* Blowfish_expand0state( state, key, keylen )
*/
void Blowfish_encipher(ssh_blf_ctx *, uint32_t *, uint32_t *);
void Blowfish_decipher(ssh_blf_ctx *, uint32_t *, uint32_t *);
void Blowfish_initstate(ssh_blf_ctx *);
void Blowfish_expand0state(ssh_blf_ctx *, const uint8_t *, uint16_t);
void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *);
void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *);
void Blowfish_initstate(blf_ctx *);
void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t);
void Blowfish_expandstate
(ssh_blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t);
(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t);
/* Standard Blowfish */
void ssh_blf_key(ssh_blf_ctx *, const uint8_t *, uint16_t);
void ssh_blf_enc(ssh_blf_ctx *, uint32_t *, uint16_t);
void ssh_blf_dec(ssh_blf_ctx *, uint32_t *, uint16_t);
void blf_key(blf_ctx *, const uint8_t *, uint16_t);
void blf_enc(blf_ctx *, uint32_t *, uint16_t);
void blf_dec(blf_ctx *, uint32_t *, uint16_t);
void ssh_blf_ecb_encrypt(ssh_blf_ctx *, uint8_t *, uint32_t);
void ssh_blf_ecb_decrypt(ssh_blf_ctx *, uint8_t *, uint32_t);
void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t);
void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t);
void ssh_blf_cbc_encrypt(ssh_blf_ctx *, uint8_t *, uint8_t *, uint32_t);
void ssh_blf_cbc_decrypt(ssh_blf_ctx *, uint8_t *, uint8_t *, uint32_t);
void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t);
void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t);
/* Converts uint8_t to uint32_t */
uint32_t Blowfish_stream2word(const uint8_t *, uint16_t , uint16_t *);

View File

@@ -41,17 +41,18 @@ struct ssh_buffer_struct {
#define SSH_BUFFER_PACK_END ((uint32_t) 0x4f65feb3)
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
LIBSSH_API void *ssh_buffer_get_begin(ssh_buffer buffer);
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
LIBSSH_API ssh_buffer ssh_buffer_new(void);
void ssh_buffer_set_secure(ssh_buffer buffer);
int ssh_buffer_add_ssh_string(ssh_buffer buffer, ssh_string string);
int ssh_buffer_add_u8(ssh_buffer buffer, uint8_t data);
int ssh_buffer_add_u16(ssh_buffer buffer, uint16_t data);
int ssh_buffer_add_u32(ssh_buffer buffer, uint32_t data);
int ssh_buffer_add_u64(ssh_buffer buffer, uint64_t data);
int buffer_add_ssh_string(ssh_buffer buffer, ssh_string string);
int buffer_add_u8(ssh_buffer buffer, uint8_t data);
int buffer_add_u16(ssh_buffer buffer, uint16_t data);
int buffer_add_u32(ssh_buffer buffer, uint32_t data);
int buffer_add_u64(ssh_buffer buffer, uint64_t data);
int ssh_buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len);
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len);
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len);
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer, uint32_t len);
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
const char *format,
int argc,
@@ -73,19 +74,27 @@ int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
#define ssh_buffer_unpack(buffer, format, ...) \
_ssh_buffer_unpack((buffer), (format), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, SSH_BUFFER_PACK_END)
int ssh_buffer_prepend_data(ssh_buffer buffer, const void *data, uint32_t len);
int ssh_buffer_add_buffer(ssh_buffer buffer, ssh_buffer source);
int buffer_prepend_data(ssh_buffer buffer, const void *data, uint32_t len);
int buffer_add_buffer(ssh_buffer buffer, ssh_buffer source);
int ssh_buffer_reinit(ssh_buffer buffer);
/* buffer_get_rest returns a pointer to the current position into the buffer */
void *buffer_get_rest(ssh_buffer buffer);
/* buffer_get_rest_len returns the number of bytes which can be read */
uint32_t buffer_get_rest_len(ssh_buffer buffer);
/* buffer_read_*() returns the number of bytes read, except for ssh strings */
int ssh_buffer_get_u8(ssh_buffer buffer, uint8_t *data);
int ssh_buffer_get_u32(ssh_buffer buffer, uint32_t *data);
int ssh_buffer_get_u64(ssh_buffer buffer, uint64_t *data);
int buffer_get_u8(ssh_buffer buffer, uint8_t *data);
int buffer_get_u32(ssh_buffer buffer, uint32_t *data);
int buffer_get_u64(ssh_buffer buffer, uint64_t *data);
/* ssh_buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
ssh_string ssh_buffer_get_ssh_string(ssh_buffer buffer);
/* ssh_buffer_pass_bytes acts as if len bytes have been read (used for padding) */
uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
uint32_t buffer_get_data(ssh_buffer buffer, void *data, uint32_t requestedlen);
/* buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
ssh_string buffer_get_ssh_string(ssh_buffer buffer);
/* gets a string out of a SSH-1 mpint */
ssh_string buffer_get_mpint(ssh_buffer buffer);
/* buffer_pass_bytes acts as if len bytes have been read (used for padding) */
uint32_t buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
uint32_t buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
#endif /* BUFFER_H_ */

View File

@@ -124,18 +124,6 @@ typedef void (*ssh_global_request_callback) (ssh_session session,
typedef ssh_channel (*ssh_channel_open_request_x11_callback) (ssh_session session,
const char * originator_address, int originator_port, void *userdata);
/**
* @brief Handles an SSH new channel open "auth-agent" request. This happens when the server
* sends back an "auth-agent" connection attempt. This is a client-side API
* @param session current session handler
* @param userdata Userdata to be passed to the callback function.
* @returns a valid ssh_channel handle if the request is to be allowed
* @returns NULL if the request should not be allowed
* @warning The channel pointer returned by this callback must be closed by the application.
*/
typedef ssh_channel (*ssh_channel_open_request_auth_agent_callback) (ssh_session session,
void *userdata);
/**
* The structure to replace libssh functions with appropriate callbacks.
*/
@@ -166,9 +154,6 @@ struct ssh_callbacks_struct {
/** This function will be called when an incoming X11 request is received.
*/
ssh_channel_open_request_x11_callback channel_open_request_x11_function;
/** This function will be called when an incoming "auth-agent" request is received.
*/
ssh_channel_open_request_auth_agent_callback channel_open_request_auth_agent_function;
};
typedef struct ssh_callbacks_struct *ssh_callbacks;
@@ -435,69 +420,6 @@ typedef struct ssh_socket_callbacks_struct *ssh_socket_callbacks;
((p)-> c != NULL) \
)
/**
* @internal
*
* @brief Iterate through a list of callback structures
*
* This tests for their validity and executes them. The userdata argument is
* automatically passed through.
*
* @param list list of callbacks
*
* @param cbtype type of the callback
*
* @param c callback name
*
* @param va_args parameters to be passed
*/
#define ssh_callbacks_execute_list(list, cbtype, c, ...) \
do { \
struct ssh_iterator *i = ssh_list_get_iterator(list); \
cbtype cb; \
while (i != NULL){ \
cb = ssh_iterator_value(cbtype, i); \
if (ssh_callbacks_exists(cb, c)) \
cb-> c (__VA_ARGS__, cb->userdata); \
i = i->next; \
} \
} while(0)
/**
* @internal
*
* @brief iterate through a list of callback structures.
*
* This tests for their validity and give control back to the calling code to
* execute them. Caller can decide to break the loop or continue executing the
* callbacks with different parameters
*
* @code
* ssh_callbacks_iterate(channel->callbacks, ssh_channel_callbacks,
* channel_eof_function){
* rc = ssh_callbacks_iterate_exec(session, channel);
* if (rc != SSH_OK){
* break;
* }
* }
* ssh_callbacks_iterate_end();
* @endcode
*/
#define ssh_callbacks_iterate(_cb_list, _cb_type, _cb_name) \
do { \
struct ssh_iterator *_cb_i = ssh_list_get_iterator(_cb_list); \
_cb_type _cb; \
for (; _cb_i != NULL; _cb_i = _cb_i->next) { \
_cb = ssh_iterator_value(_cb_type, _cb_i); \
if (ssh_callbacks_exists(_cb, _cb_name))
#define ssh_callbacks_iterate_exec(_cb_name, ...) \
_cb->_cb_name(__VA_ARGS__, _cb->userdata)
#define ssh_callbacks_iterate_end() \
} \
} while(0)
/** @brief Prototype for a packet callback, to be called when a new packet arrives
* @param session The current session of the packet
* @param type packet type (see ssh2.h)
@@ -757,22 +679,6 @@ typedef int (*ssh_channel_subsystem_request_callback) (ssh_session session,
const char *subsystem,
void *userdata);
/**
* @brief SSH channel write will not block (flow control).
*
* @param channel the channel
*
* @param[in] bytes size of the remote window in bytes. Writing as much data
* will not block.
*
* @param[in] userdata Userdata to be passed to the callback function.
*
* @returns 0 default return value (other return codes may be added in future).
*/
typedef int (*ssh_channel_write_wontblock_callback) (ssh_session session,
ssh_channel channel,
size_t bytes,
void *userdata);
struct ssh_channel_callbacks_struct {
/** DON'T SET THIS use ssh_callbacks_init() instead. */
@@ -837,10 +743,6 @@ struct ssh_channel_callbacks_struct {
* (like sftp).
*/
ssh_channel_subsystem_request_callback channel_subsystem_request_function;
/** This function will be called when the channel write is guaranteed
* not to block.
*/
ssh_channel_write_wontblock_callback channel_write_wontblock_function;
};
typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
@@ -865,46 +767,10 @@ typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
* @param cb The callback structure itself.
*
* @return SSH_OK on success, SSH_ERROR on error.
* @warning this function will not replace existing callbacks but set the
* new one atop of them.
*/
LIBSSH_API int ssh_set_channel_callbacks(ssh_channel channel,
ssh_channel_callbacks cb);
/**
* @brief Add channel callback functions
*
* This function will add channel callback functions to the channel callback
* list.
* Callbacks missing from a callback structure will be probed in the next
* on the list.
*
* @param channel The channel to set the callback structure.
*
* @param cb The callback structure itself.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
* @see ssh_set_channel_callbacks
*/
LIBSSH_API int ssh_add_channel_callbacks(ssh_channel channel,
ssh_channel_callbacks cb);
/**
* @brief Remove a channel callback.
*
* The channel has been added with ssh_add_channel_callbacks or
* ssh_set_channel_callbacks in this case.
*
* @param channel The channel to remove the callback structure from.
*
* @param cb The callback structure to remove
*
* @returns SSH_OK on success, SSH_ERROR on error.
*/
LIBSSH_API int ssh_remove_channel_callbacks(ssh_channel channel,
ssh_channel_callbacks cb);
/** @} */
/** @group libssh_threads

View File

@@ -1,41 +0,0 @@
/* $OpenBSD: chacha.h,v 1.3 2014/05/02 03:27:54 djm Exp $ */
/*
chacha-merged.c version 20080118
D. J. Bernstein
Public domain.
*/
#ifndef CHACHA_H
#define CHACHA_H
struct chacha_ctx {
uint32_t input[16];
};
#define CHACHA_MINKEYLEN 16
#define CHACHA_NONCELEN 8
#define CHACHA_CTRLEN 8
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
#define CHACHA_BLOCKLEN 64
void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits)
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
__attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN)))
#endif
;
void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr)
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
__attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN)))
__attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN)))
#endif
;
void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m,
uint8_t *c, uint32_t bytes)
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
__attribute__((__bounded__(__buffer__, 2, 4)))
__attribute__((__bounded__(__buffer__, 3, 4)))
#endif
;
#endif /* CHACHA_H */

View File

@@ -71,10 +71,10 @@ struct ssh_channel_struct {
ssh_buffer stdout_buffer;
ssh_buffer stderr_buffer;
void *userarg;
int version;
int exit_status;
enum ssh_channel_request_state_e request_state;
struct ssh_list *callbacks; /* list of ssh_channel_callbacks */
ssh_channel_callbacks callbacks;
/* counters */
ssh_counter counter;
};
@@ -99,5 +99,20 @@ int ssh_channel_flush(ssh_channel channel);
uint32_t ssh_channel_new_id(ssh_session session);
ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id);
void ssh_channel_do_free(ssh_channel channel);
#ifdef WITH_SSH1
SSH_PACKET_CALLBACK(ssh_packet_data1);
SSH_PACKET_CALLBACK(ssh_packet_close1);
SSH_PACKET_CALLBACK(ssh_packet_exist_status1);
/* channels1.c */
int channel_open_session1(ssh_channel channel);
int channel_request_pty_size1(ssh_channel channel, const char *terminal,
int cols, int rows);
int channel_change_pty_size1(ssh_channel channel, int cols, int rows);
int channel_request_shell1(ssh_channel channel);
int channel_request_exec1(ssh_channel channel, const char *cmd);
int channel_write1(ssh_channel channel, const void *data, int len);
ssh_channel ssh_get_channel1(ssh_session session);
#endif
#endif /* CHANNELS_H_ */

View File

@@ -55,38 +55,14 @@ enum ssh_key_exchange_e {
SSH_KEX_DH_GROUP14_SHA1,
/* ecdh-sha2-nistp256 */
SSH_KEX_ECDH_SHA2_NISTP256,
/* ecdh-sha2-nistp384 */
SSH_KEX_ECDH_SHA2_NISTP384,
/* ecdh-sha2-nistp521 */
SSH_KEX_ECDH_SHA2_NISTP521,
/* curve25519-sha256@libssh.org */
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG,
/* curve25519-sha256 */
SSH_KEX_CURVE25519_SHA256
};
enum ssh_cipher_e {
SSH_NO_CIPHER=0,
SSH_BLOWFISH_CBC,
SSH_3DES_CBC,
SSH_AES128_CBC,
SSH_AES192_CBC,
SSH_AES256_CBC,
SSH_AES128_CTR,
SSH_AES192_CTR,
SSH_AES256_CTR
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG
};
struct ssh_crypto_struct {
bignum e,f,x,k,y;
#ifdef HAVE_ECDH
#ifdef HAVE_OPENSSL_ECC
EC_KEY *ecdh_privkey;
#elif defined HAVE_GCRYPT_ECC
gcry_sexp_t ecdh_privkey;
#elif defined HAVE_LIBMBEDCRYPTO
mbedtls_ecp_keypair *ecdh_privkey;
#endif
ssh_string ecdh_client_pubkey;
ssh_string ecdh_server_pubkey;
#endif
@@ -109,7 +85,8 @@ struct ssh_crypto_struct {
struct ssh_cipher_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
enum ssh_hmac_e in_hmac, out_hmac; /* the MAC algorithms used */
ssh_key server_pubkey;
ssh_string server_pubkey;
const char *server_pubkey_type;
int do_compress_out; /* idem */
int do_compress_in; /* don't set them, set the option instead */
int delayed_compress_in; /* Use of zlib@openssh.org */
@@ -127,24 +104,14 @@ struct ssh_crypto_struct {
struct ssh_cipher_struct {
const char *name; /* ssh name of the algorithm */
unsigned int blocksize; /* blocksize of the algo */
enum ssh_cipher_e ciphertype;
uint32_t lenfield_blocksize; /* blocksize of the packet length field */
size_t keylen; /* length of the key structure */
unsigned int keylen; /* length of the key structure */
#ifdef HAVE_LIBGCRYPT
gcry_cipher_hd_t *key;
#elif defined HAVE_LIBCRYPTO
struct ssh_3des_key_schedule *des3_key;
struct ssh_aes_key_schedule *aes_key;
const EVP_CIPHER *cipher;
EVP_CIPHER_CTX *ctx;
#elif defined HAVE_LIBMBEDCRYPTO
mbedtls_cipher_context_t encrypt_ctx;
mbedtls_cipher_context_t decrypt_ctx;
mbedtls_cipher_type_t type;
void *key; /* a key buffer allocated for the algo */
void *IV;
#endif
struct chacha20_poly1305_keysched *chacha20_schedule;
unsigned int keysize; /* bytes of key used. != keylen */
size_t tag_size; /* overhead required for tag */
/* sets the new key for immediate use */
int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
@@ -152,15 +119,7 @@ struct ssh_cipher_struct {
unsigned long len);
void (*decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
unsigned long len);
void (*aead_encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
size_t len, uint8_t *mac, uint64_t seq);
int (*aead_decrypt_length)(struct ssh_cipher_struct *cipher, void *in,
uint8_t *out, size_t len, uint64_t seq);
int (*aead_decrypt)(struct ssh_cipher_struct *cipher, void *complete_packet, uint8_t *out,
size_t encrypted_size, uint64_t seq);
void (*cleanup)(struct ssh_cipher_struct *cipher);
};
const struct ssh_cipher_struct *ssh_get_chacha20poly1305_cipher(void);
/* vim: set ts=2 sw=2 et cindent: */
#endif /* _CRYPTO_H_ */

View File

@@ -25,37 +25,27 @@
#include "libssh/crypto.h"
int ssh_dh_generate_e(ssh_session session);
int ssh_dh_generate_f(ssh_session session);
int ssh_dh_generate_x(ssh_session session);
int ssh_dh_generate_y(ssh_session session);
int dh_generate_e(ssh_session session);
int dh_generate_f(ssh_session session);
int dh_generate_x(ssh_session session);
int dh_generate_y(ssh_session session);
int ssh_dh_init(void);
void ssh_dh_finalize(void);
int ssh_crypto_init(void);
void ssh_crypto_finalize(void);
ssh_string ssh_dh_get_e(ssh_session session);
ssh_string ssh_dh_get_f(ssh_session session);
int ssh_dh_import_f(ssh_session session,ssh_string f_string);
int ssh_dh_import_e(ssh_session session, ssh_string e_string);
int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
int ssh_dh_build_k(ssh_session session);
ssh_string dh_get_e(ssh_session session);
ssh_string dh_get_f(ssh_session session);
int dh_import_f(ssh_session session,ssh_string f_string);
int dh_import_e(ssh_session session, ssh_string e_string);
void dh_import_pubkey(ssh_session session,ssh_string pubkey_string);
int dh_build_k(ssh_session session);
int ssh_client_dh_init(ssh_session session);
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet);
ssh_key ssh_dh_get_current_server_publickey(ssh_session session);
int ssh_dh_get_current_server_publickey_blob(ssh_session session,
ssh_string *pubkey_blob);
ssh_key ssh_dh_get_next_server_publickey(ssh_session session);
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
ssh_string *pubkey_blob);
int ssh_make_sessionid(ssh_session session);
int make_sessionid(ssh_session session);
/* add data for the final cookie */
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
int ssh_hashbufout_add_cookie(ssh_session session);
int ssh_generate_session_keys(ssh_session session);
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
int hashbufout_add_cookie(ssh_session session);
int generate_session_keys(ssh_session session);
#endif /* DH_H_ */

View File

@@ -33,20 +33,8 @@
#endif /* HAVE_OPENSSL_ECDH_H */
#endif /* HAVE_LIBCRYPTO */
#ifdef HAVE_GCRYPT_ECC
#define HAVE_ECDH 1
#endif
#ifdef HAVE_LIBMBEDCRYPTO
#define HAVE_ECDH 1
#endif
/* Common functions. */
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
/* Backend-specific functions. */
int ssh_client_ecdh_init(ssh_session session);
int ecdh_build_k(ssh_session session);
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
#ifdef WITH_SERVER
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet);

View File

@@ -28,7 +28,7 @@ typedef struct
fe25519 t;
} ge25519;
extern const ge25519 ge25519_base;
const ge25519 ge25519_base;
int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]);

View File

@@ -32,14 +32,16 @@ struct ssh_kex_struct {
};
SSH_PACKET_CALLBACK(ssh_packet_kexinit);
#ifdef WITH_SSH1
SSH_PACKET_CALLBACK(ssh_packet_publickey1);
#endif
int ssh_send_kex(ssh_session session, int server_kex);
void ssh_list_kex(struct ssh_kex_struct *kex);
int ssh_set_client_kex(ssh_session session);
int set_client_kex(ssh_session session);
int ssh_kex_select_methods(ssh_session session);
int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name);
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list);
char **ssh_space_tokenize(const char *chain);
int verify_existing_algo(int algo, const char *name);
char **space_tokenize(const char *chain);
int ssh_get_kex1(ssh_session session);
char *ssh_find_matching(const char *in_d, const char *what_d);
const char *ssh_kex_get_supported_method(uint32_t algo);

View File

@@ -34,9 +34,6 @@ struct ssh_public_key_struct {
#elif HAVE_LIBCRYPTO
DSA *dsa_pub;
RSA *rsa_pub;
#elif HAVE_LIBMBEDCRYPTO
mbedtls_pk_context *rsa_pub;
void *dsa_pub;
#endif
};
@@ -48,9 +45,6 @@ struct ssh_private_key_struct {
#elif defined HAVE_LIBCRYPTO
DSA *dsa_priv;
RSA *rsa_priv;
#elif HAVE_LIBMBEDCRYPTO
mbedtls_pk_context *rsa_priv;
void *dsa_priv;
#endif
};

View File

@@ -19,9 +19,9 @@
*/
#ifndef SSH_KNOWNHOSTS_H_
#define SSH_KNOWNHOSTS_H_
#ifndef KNOWNHOSTS_H_
#define KNOWNHOSTS_H_
struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
char **ssh_knownhosts_algorithms(ssh_session session);
#endif /* SSH_KNOWNHOSTS_H_ */
#endif /* KNOWNHOSTS_H_ */

View File

@@ -30,13 +30,15 @@
#include <openssl/sha.h>
#include <openssl/md5.h>
#include <openssl/hmac.h>
#ifdef HAVE_OPENSSL_ECC
#include <openssl/evp.h>
#endif
typedef EVP_MD_CTX* SHACTX;
typedef EVP_MD_CTX* SHA256CTX;
typedef EVP_MD_CTX* SHA384CTX;
typedef EVP_MD_CTX* SHA512CTX;
typedef EVP_MD_CTX* MD5CTX;
typedef SHA_CTX* SHACTX;
typedef SHA256_CTX* SHA256CTX;
typedef SHA512_CTX* SHA384CTX;
typedef SHA512_CTX* SHA512CTX;
typedef MD5_CTX* MD5CTX;
typedef HMAC_CTX* HMACCTX;
#ifdef HAVE_ECC
typedef EVP_MD_CTX *EVPCTX;
@@ -67,18 +69,13 @@ typedef BIGNUM* bignum;
typedef BN_CTX* bignum_CTX;
#define bignum_new() BN_new()
#define bignum_safe_free(num) do { \
if ((num) != NULL) { \
BN_clear_free((num)); \
(num)=NULL; \
} \
} while(0)
#define bignum_free(num) BN_clear_free(num)
#define bignum_set_word(bn,n) BN_set_word(bn,n)
#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
#define bignum_bn2dec(num) BN_bn2dec(num)
#define bignum_dec2bn(bn,data) BN_dec2bn(data,bn)
#define bignum_bn2hex(num) BN_bn2hex(num)
#define bignum_rand(rnd, bits) BN_rand(rnd, bits, 0, 1)
#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom)
#define bignum_ctx_new() BN_CTX_new()
#define bignum_ctx_free(num) BN_CTX_free(num)
#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
@@ -88,6 +85,20 @@ typedef BN_CTX* bignum_CTX;
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
SHA256CTX sha256_init(void);
void sha256_update(SHA256CTX c, const void *data, unsigned long len);
void sha256_final(unsigned char *md, SHA256CTX c);
SHA384CTX sha384_init(void);
void sha384_update(SHA384CTX c, const void *data, unsigned long len);
void sha384_final(unsigned char *md, SHA384CTX c);
SHA512CTX sha512_init(void);
void sha512_update(SHA512CTX c, const void *data, unsigned long len);
void sha512_final(unsigned char *md, SHA512CTX c);
struct ssh_cipher_struct *ssh_get_ciphertab(void);
#endif /* HAVE_LIBCRYPTO */
#endif /* LIBCRYPTO_H_ */

View File

@@ -32,7 +32,7 @@ typedef gcry_md_hd_t SHA384CTX;
typedef gcry_md_hd_t SHA512CTX;
typedef gcry_md_hd_t MD5CTX;
typedef gcry_md_hd_t HMACCTX;
typedef gcry_md_hd_t EVPCTX;
typedef void *EVPCTX;
#define SHA_DIGEST_LENGTH 20
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#define MD5_DIGEST_LEN 16
@@ -51,26 +51,16 @@ typedef gcry_md_hd_t EVPCTX;
typedef gcry_mpi_t bignum;
/* Constants for curves. */
#define NID_gcrypt_nistp256 0
#define NID_gcrypt_nistp384 1
#define NID_gcrypt_nistp521 2
/* missing gcrypt functions */
int ssh_gcry_dec2bn(bignum *bn, const char *data);
char *ssh_gcry_bn2dec(bignum bn);
int my_gcry_dec2bn(bignum *bn, const char *data);
char *my_gcry_bn2dec(bignum bn);
#define bignum_new() gcry_mpi_new(0)
#define bignum_safe_free(num) do { \
if ((num) != NULL) { \
gcry_mpi_release((num)); \
(num)=NULL; \
} \
} while (0)
#define bignum_free(num) gcry_mpi_release(num)
#define bignum_set_word(bn,n) gcry_mpi_set_ui(bn,n)
#define bignum_bin2bn(bn,datalen,data) gcry_mpi_scan(data,GCRYMPI_FMT_USG,bn,datalen,NULL)
#define bignum_bn2dec(num) ssh_gcry_bn2dec(num)
#define bignum_dec2bn(num, data) ssh_gcry_dec2bn(data, num)
#define bignum_bn2dec(num) my_gcry_bn2dec(num)
#define bignum_dec2bn(num, data) my_gcry_dec2bn(data, num)
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
#define bignum_hex2bn(num,datalen,data) gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,datalen,NULL)
#define bignum_rand(num,bits) gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
@@ -81,16 +71,8 @@ char *ssh_gcry_bn2dec(bignum bn);
#define bignum_bn2bin(num,datalen,data) gcry_mpi_print(GCRYMPI_FMT_USG,data,datalen,NULL,num)
#define bignum_cmp(num1,num2) gcry_mpi_cmp(num1,num2)
/* Helper functions for data conversions. */
/* Extract an MPI from the given s-expression SEXP named NAME which is
encoded using INFORMAT and store it in a newly allocated ssh_string
encoded using OUTFORMAT. */
ssh_string ssh_sexp_extract_mpi(const gcry_sexp_t sexp,
const char *name,
enum gcry_mpi_format informat,
enum gcry_mpi_format outformat);
#endif /* HAVE_LIBGCRYPT */
struct ssh_cipher_struct *ssh_get_ciphertab(void);
#endif /* LIBGCRYPT_H_ */

View File

@@ -1,113 +0,0 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2017 Sartura d.o.o.
*
* Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#ifndef LIBMBEDCRYPTO_H_
#define LIBMBEDCRYPTO_H_
#include "config.h"
#ifdef HAVE_LIBMBEDCRYPTO
#include <mbedtls/md.h>
#include <mbedtls/bignum.h>
#include <mbedtls/pk.h>
#include <mbedtls/cipher.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
typedef mbedtls_md_context_t *SHACTX;
typedef mbedtls_md_context_t *SHA256CTX;
typedef mbedtls_md_context_t *SHA384CTX;
typedef mbedtls_md_context_t *SHA512CTX;
typedef mbedtls_md_context_t *MD5CTX;
typedef mbedtls_md_context_t *HMACCTX;
typedef mbedtls_md_context_t *EVPCTX;
#define SHA_DIGEST_LENGTH 20
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#define MD5_DIGEST_LEN 16
#define SHA256_DIGEST_LENGTH 32
#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH
#define SHA384_DIGEST_LENGTH 48
#define SHA384_DIGEST_LEN SHA384_DIGEST_LENGTH
#define SHA512_DIGEST_LENGTH 64
#define SHA512_DIGEST_LEN SHA512_DIGEST_LENGTH
#ifndef EVP_MAX_MD_SIZE
#define EVP_MAX_MD_SIZE 64
#endif
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
typedef mbedtls_mpi *bignum;
/* Constants for curves */
#define NID_mbedtls_nistp256 0
#define NID_mbedtls_nistp384 1
#define NID_mbedtls_nistp521 2
struct mbedtls_ecdsa_sig {
bignum r;
bignum s;
};
bignum ssh_mbedcry_bn_new(void);
void ssh_mbedcry_bn_free(bignum num);
char *ssh_mbedcry_bn2num(bignum num, int radix);
int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
#define bignum_new() ssh_mbedcry_bn_new()
#define bignum_safe_free(num) do { \
if ((num) != NULL) { \
ssh_mbedcry_bn_free(num); \
(num)=NULL; \
} \
} while(0)
#define bignum_set_word(bn, n) mbedtls_mpi_lset(bn, n) /* TODO fix
overflow/underflow */
#define bignum_bin2bn(data, datalen, bn) mbedtls_mpi_read_binary(bn, data, \
datalen)
#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10)
#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data)
#define bignum_bn2hex(num) ssh_mbedcry_bn2num(num, 16)
#define bignum_rand(rnd, bits) ssh_mbedcry_rand((rnd), (bits), 0, 1)
#define bignum_mod_exp(dest, generator, exp, modulo, ctx) \
mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL)
#define bignum_num_bytes(num) mbedtls_mpi_size(num)
#define bignum_num_bits(num) mbedtls_mpi_bitlen(num)
#define bignum_is_bit_set(num, bit) ssh_mbedcry_is_bit_set(num, bit)
#define bignum_bn2bin(num, ptr) mbedtls_mpi_write_binary(num, ptr, \
mbedtls_mpi_size(num))
#define bignum_cmp(num1, num2) mbedtls_mpi_cmp_mpi(num1, num2)
mbedtls_entropy_context ssh_mbedtls_entropy;
mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
int ssh_mbedtls_random(void *where, int len, int strong);
ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const
mbedtls_ecp_point *p);
#endif /* HAVE_LIBMBEDCRYPTO */
#endif /* LIBMBEDCRYPTO_H_ */

View File

@@ -58,7 +58,6 @@
#else /* _MSC_VER */
#include <unistd.h>
#include <inttypes.h>
#include <sys/types.h>
#endif /* _MSC_VER */
#ifdef _WIN32
@@ -79,7 +78,7 @@
/* libssh version */
#define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 7
#define LIBSSH_VERSION_MICRO 90
#define LIBSSH_VERSION_MICRO 2
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
LIBSSH_VERSION_MINOR, \
@@ -123,7 +122,6 @@ typedef struct ssh_scp_struct* ssh_scp;
typedef struct ssh_session_struct* ssh_session;
typedef struct ssh_string_struct* ssh_string;
typedef struct ssh_event_struct* ssh_event;
typedef struct ssh_connector_struct * ssh_connector;
typedef void* ssh_gssapi_creds;
/* Socket type */
@@ -190,8 +188,7 @@ enum ssh_channel_type_e {
SSH_CHANNEL_SESSION,
SSH_CHANNEL_DIRECT_TCPIP,
SSH_CHANNEL_FORWARDED_TCPIP,
SSH_CHANNEL_X11,
SSH_CHANNEL_AUTH_AGENT
SSH_CHANNEL_X11
};
enum ssh_channel_requests_e {
@@ -209,7 +206,6 @@ enum ssh_global_requests_e {
SSH_GLOBAL_REQUEST_UNKNOWN=0,
SSH_GLOBAL_REQUEST_TCPIP_FORWARD,
SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD,
SSH_GLOBAL_REQUEST_KEEPALIVE
};
enum ssh_publickey_state_e {
@@ -238,15 +234,6 @@ enum ssh_server_known_e {
SSH_SERVER_FILE_NOT_FOUND
};
enum ssh_known_hosts_e {
SSH_KNOWN_HOSTS_ERROR = -2,
SSH_KNOWN_HOSTS_NOT_FOUND = -1,
SSH_KNOWN_HOSTS_UNKNOWN = 0,
SSH_KNOWN_HOSTS_OK,
SSH_KNOWN_HOSTS_CHANGED,
SSH_KNOWN_HOSTS_OTHER,
};
#ifndef MD5_DIGEST_LEN
#define MD5_DIGEST_LEN 16
#endif
@@ -266,9 +253,7 @@ enum ssh_keytypes_e{
SSH_KEYTYPE_RSA,
SSH_KEYTYPE_RSA1,
SSH_KEYTYPE_ECDSA,
SSH_KEYTYPE_ED25519,
SSH_KEYTYPE_DSS_CERT01,
SSH_KEYTYPE_RSA_CERT01
SSH_KEYTYPE_ED25519
};
enum ssh_keycmp_e {
@@ -276,16 +261,6 @@ enum ssh_keycmp_e {
SSH_KEY_CMP_PRIVATE
};
#define SSH_ADDRSTRLEN 46
struct ssh_knownhosts_entry {
char *hostname;
char *unparsed;
ssh_key publickey;
char *comment;
};
/* Error return codes */
#define SSH_OK 0 /* No error */
#define SSH_ERROR -1 /* Error of some kind */
@@ -370,12 +345,6 @@ enum ssh_options_e {
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
SSH_OPTIONS_HMAC_C_S,
SSH_OPTIONS_HMAC_S_C,
SSH_OPTIONS_PASSWORD_AUTH,
SSH_OPTIONS_PUBKEY_AUTH,
SSH_OPTIONS_KBDINT_AUTH,
SSH_OPTIONS_GSSAPI_AUTH,
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
SSH_OPTIONS_NODELAY,
};
enum {
@@ -399,15 +368,6 @@ enum ssh_scp_request_types {
SSH_SCP_REQUEST_WARNING
};
enum ssh_connector_flags_e {
/** Only the standard stream of the channel */
SSH_CONNECTOR_STDOUT = 1,
/** Only the exception stream of the channel */
SSH_CONNECTOR_STDERR = 2,
/** Merge both standard and exception streams */
SSH_CONNECTOR_BOTH = 3
};
LIBSSH_API int ssh_blocking_flush(ssh_session session, int timeout);
LIBSSH_API ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms);
LIBSSH_API int ssh_channel_change_pty_size(ssh_channel channel,int cols,int rows);
@@ -437,12 +397,10 @@ LIBSSH_API int ssh_channel_request_pty_size(ssh_channel channel, const char *ter
int cols, int rows);
LIBSSH_API int ssh_channel_request_shell(ssh_channel channel);
LIBSSH_API int ssh_channel_request_send_signal(ssh_channel channel, const char *signum);
LIBSSH_API int ssh_channel_request_send_break(ssh_channel channel, uint32_t length);
LIBSSH_API int ssh_channel_request_sftp(ssh_channel channel);
LIBSSH_API int ssh_channel_request_subsystem(ssh_channel channel, const char *subsystem);
LIBSSH_API int ssh_channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
const char *cookie, int screen_number);
LIBSSH_API int ssh_channel_request_auth_agent(ssh_channel channel);
LIBSSH_API int ssh_channel_send_eof(ssh_channel channel);
LIBSSH_API int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct
timeval * timeout);
@@ -450,26 +408,11 @@ LIBSSH_API void ssh_channel_set_blocking(ssh_channel channel, int blocking);
LIBSSH_API void ssh_channel_set_counter(ssh_channel channel,
ssh_counter counter);
LIBSSH_API int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len);
LIBSSH_API int ssh_channel_write_stderr(ssh_channel channel,
const void *data,
uint32_t len);
LIBSSH_API uint32_t ssh_channel_window_size(ssh_channel channel);
LIBSSH_API char *ssh_basename (const char *path);
LIBSSH_API void ssh_clean_pubkey_hash(unsigned char **hash);
LIBSSH_API int ssh_connect(ssh_session session);
LIBSSH_API ssh_connector ssh_connector_new(ssh_session session);
LIBSSH_API void ssh_connector_free(ssh_connector connector);
LIBSSH_API int ssh_connector_set_in_channel(ssh_connector connector,
ssh_channel channel,
enum ssh_connector_flags_e flags);
LIBSSH_API int ssh_connector_set_out_channel(ssh_connector connector,
ssh_channel channel,
enum ssh_connector_flags_e flags);
LIBSSH_API void ssh_connector_set_in_fd(ssh_connector connector, socket_t fd);
LIBSSH_API void ssh_connector_set_out_fd(ssh_connector connector, socket_t fd);
LIBSSH_API const char *ssh_copyright(void);
LIBSSH_API void ssh_disconnect(ssh_session session);
LIBSSH_API char *ssh_dirname (const char *path);
@@ -496,7 +439,7 @@ LIBSSH_API char *ssh_get_hexa(const unsigned char *what, size_t len);
LIBSSH_API char *ssh_get_issue_banner(ssh_session session);
LIBSSH_API int ssh_get_openssh_version(ssh_session session);
LIBSSH_API int ssh_get_server_publickey(ssh_session session, ssh_key *key);
LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key);
enum ssh_publickey_hash_type {
SSH_PUBLICKEY_HASH_SHA1,
@@ -512,7 +455,6 @@ SSH_DEPRECATED LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned
SSH_DEPRECATED LIBSSH_API ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms);
SSH_DEPRECATED LIBSSH_API int ssh_forward_cancel(ssh_session session, const char *address, int port);
SSH_DEPRECATED LIBSSH_API int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port);
SSH_DEPRECATED LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key);
LIBSSH_API int ssh_get_random(void *where,int len,int strong);
@@ -524,29 +466,6 @@ LIBSSH_API int ssh_is_blocking(ssh_session session);
LIBSSH_API int ssh_is_connected(ssh_session session);
LIBSSH_API int ssh_is_server_known(ssh_session session);
/* KNOWN HOSTS */
LIBSSH_API void ssh_knownhosts_entry_free(struct ssh_knownhosts_entry *entry);
#define SSH_KNOWNHOSTS_ENTRY_FREE(e) do { \
if ((e) != NULL) { \
ssh_knownhosts_entry_free(e); \
e = NULL; \
} \
} while(0)
LIBSSH_API int ssh_known_hosts_parse_line(const char *host,
const char *line,
struct ssh_knownhosts_entry **entry);
LIBSSH_API enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session);
LIBSSH_API int ssh_session_export_known_hosts_entry(ssh_session session,
char **pentry_string);
LIBSSH_API int ssh_session_update_known_hosts(ssh_session session);
LIBSSH_API enum ssh_known_hosts_e
ssh_session_get_known_hosts_entry(ssh_session session,
struct ssh_knownhosts_entry **pentry);
LIBSSH_API enum ssh_known_hosts_e ssh_session_is_known_server(ssh_session session);
/* LOGGING */
LIBSSH_API int ssh_set_log_level(int level);
LIBSSH_API int ssh_get_log_level(void);
@@ -628,21 +547,12 @@ LIBSSH_API int ssh_pki_export_privkey_file(const ssh_key privkey,
void *auth_data,
const char *filename);
LIBSSH_API int ssh_pki_copy_cert_to_privkey(const ssh_key cert_key,
ssh_key privkey);
LIBSSH_API int ssh_pki_import_pubkey_base64(const char *b64_key,
enum ssh_keytypes_e type,
ssh_key *pkey);
LIBSSH_API int ssh_pki_import_pubkey_file(const char *filename,
ssh_key *pkey);
LIBSSH_API int ssh_pki_import_cert_base64(const char *b64_cert,
enum ssh_keytypes_e type,
ssh_key *pkey);
LIBSSH_API int ssh_pki_import_cert_file(const char *filename,
ssh_key *pkey);
LIBSSH_API int ssh_pki_export_privkey_to_pubkey(const ssh_key privkey,
ssh_key *pkey);
LIBSSH_API int ssh_pki_export_pubkey_base64(const ssh_key key,
@@ -720,7 +630,6 @@ LIBSSH_API int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i
LIBSSH_API int ssh_userauth_gssapi(ssh_session session);
LIBSSH_API const char *ssh_version(int req_version);
LIBSSH_API int ssh_write_knownhost(ssh_session session);
LIBSSH_API char *ssh_dump_knownhost(ssh_session session);
LIBSSH_API void ssh_string_burn(ssh_string str);
LIBSSH_API ssh_string ssh_string_copy(ssh_string str);
@@ -744,11 +653,9 @@ LIBSSH_API ssh_event ssh_event_new(void);
LIBSSH_API int ssh_event_add_fd(ssh_event event, socket_t fd, short events,
ssh_event_callback cb, void *userdata);
LIBSSH_API int ssh_event_add_session(ssh_event event, ssh_session session);
LIBSSH_API int ssh_event_add_connector(ssh_event event, ssh_connector connector);
LIBSSH_API int ssh_event_dopoll(ssh_event event, int timeout);
LIBSSH_API int ssh_event_remove_fd(ssh_event event, socket_t fd);
LIBSSH_API int ssh_event_remove_session(ssh_event event, ssh_session session);
LIBSSH_API int ssh_event_remove_connector(ssh_event event, ssh_connector connector);
LIBSSH_API void ssh_event_free(ssh_event event);
LIBSSH_API const char* ssh_get_clientbanner(ssh_session session);
LIBSSH_API const char* ssh_get_serverbanner(ssh_session session);
@@ -758,14 +665,6 @@ LIBSSH_API const char* ssh_get_cipher_out(ssh_session session);
LIBSSH_API const char* ssh_get_hmac_in(ssh_session session);
LIBSSH_API const char* ssh_get_hmac_out(ssh_session session);
LIBSSH_API ssh_buffer ssh_buffer_new(void);
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
LIBSSH_API int ssh_buffer_reinit(ssh_buffer buffer);
LIBSSH_API int ssh_buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len);
LIBSSH_API uint32_t ssh_buffer_get_data(ssh_buffer buffer, void *data, uint32_t requestedlen);
LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
#ifndef LIBSSH_LEGACY_0_4
#include "libssh/legacy.h"
#endif
@@ -774,3 +673,4 @@ LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
}
#endif
#endif /* _LIBSSH_H */
/* vim: set ts=2 sw=2 et cindent: */

View File

@@ -194,43 +194,6 @@ public:
ssh_throw(ret);
return ret;
}
/** @brief Authenticate through the "keyboard-interactive" method.
* @param[in] The username to authenticate. You can specify NULL if ssh_option_set_username() has been used. You cannot try two different logins in a row.
* @param[in] Undocumented. Set it to NULL.
* @throws SshException on error
* @returns SSH_AUTH_SUCCESS, SSH_AUTH_PARTIAL, SSH_AUTH_DENIED, SSH_AUTH_ERROR, SSH_AUTH_INFO, SSH_AUTH_AGAIN
* @see ssh_userauth_kbdint
*/
int userauthKbdint(const char* username, const char* submethods){
int ret=ssh_userauth_kbdint(c_session,NULL,NULL);
ssh_throw(ret);
return ret;
}
/** @brief Get the number of prompts (questions) the server has given.
* @returns The number of prompts.
* @see ssh_userauth_kbdint_getnprompts
*/
int userauthKbdintGetNPrompts(){
return ssh_userauth_kbdint_getnprompts(c_session);
}
/** @brief Set the answer for a question from a message block..
* @param[in] index The number of the ith prompt.
* @param[in] The answer to give to the server. The answer MUST be encoded UTF-8. It is up to the server how to interpret the value and validate it. However, if you read the answer in some other encoding, you MUST convert it to UTF-8.
* @throws SshException on error
* @returns 0 on success, < 0 on error
* @see ssh_userauth_kbdint_setanswer
*/
int userauthKbdintSetAnswer(unsigned int i, const char* answer){
int ret=ssh_userauth_kbdint_setanswer(c_session, i, answer);
ssh_throw(ret);
return ret;
}
/** @brief Authenticates using the password method.
* @param[in] password password to use for authentication
* @throws SshException on error
@@ -265,7 +228,8 @@ public:
ssh_throw(ret);
return ret;
}
int userauthPrivatekeyFile(const char *filename,
const char *passphrase);
/** @brief Returns the available authentication methods from the server
* @throws SshException on error
* @returns Bitfield of available methods.
@@ -317,12 +281,8 @@ public:
*/
std::string getIssueBanner(){
char *banner=ssh_get_issue_banner(c_session);
std::string ret;
if (banner)
{
ret= std::string(banner);
::free(banner);
}
std::string ret= std::string(banner);
::free(banner);
return ret;
}
/** @brief returns the OpenSSH version (server) if possible
@@ -343,12 +303,12 @@ public:
* @throws SshException on error
* @returns Integer value depending on the knowledge of the
* server key
* @see ssh_session_update_known_hosts
* @see ssh_is_server_known
*/
int isServerKnown(){
int state = ssh_session_is_known_server(c_session);
ssh_throw(state);
return state;
int ret=ssh_is_server_known(c_session);
ssh_throw(ret);
return ret;
}
void log(int priority, const char *format, ...){
char buffer[1024];
@@ -418,14 +378,11 @@ public:
return_throwable;
}
private:
ssh_session c_session;
ssh_session getCSession(){
return c_session;
}
protected:
ssh_session c_session;
private:
/* No copy constructor, no = operator */
Session(const Session &);
Session& operator=(const Session &);
@@ -524,12 +481,12 @@ public:
ssh_throw(err);
return err;
}
int read(void *dest, size_t count){
int read(void *dest, size_t count, bool is_stderr){
int err;
/* handle int overflow */
if(count > 0x7fffffff)
count = 0x7fffffff;
err=ssh_channel_read_timeout(channel,dest,count,false,-1);
err=ssh_channel_read_timeout(channel,dest,count,is_stderr,-1);
ssh_throw(err);
return err;
}
@@ -627,24 +584,16 @@ public:
ssh_throw(ret);
return ret;
}
private:
ssh_session getCSession(){
return session->getCSession();
}
ssh_channel getCChannel() {
return channel;
}
protected:
Session *session;
ssh_channel channel;
private:
Channel (Session &session, ssh_channel c_channel){
this->channel=c_channel;
this->session=&session;
}
Session *session;
ssh_channel channel;
/* No copy and no = operator */
Channel(const Channel &);
Channel &operator=(const Channel &);

View File

@@ -29,10 +29,19 @@ int ssh_file_readaccess_ok(const char *file);
char *ssh_path_expand_tilde(const char *d);
char *ssh_path_expand_escape(ssh_session session, const char *s);
int ssh_analyze_banner(ssh_session session, int server);
int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2);
int ssh_is_ipaddr_v4(const char *str);
int ssh_is_ipaddr(const char *str);
#ifndef HAVE_NTOHLL
/* macro for byte ordering */
uint64_t ntohll(uint64_t);
#endif
#ifndef HAVE_HTONLL
#define htonll(x) ntohll((x))
#endif
/* list processing */
struct ssh_list {
@@ -54,7 +63,6 @@ struct ssh_list *ssh_list_new(void);
void ssh_list_free(struct ssh_list *list);
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
struct ssh_iterator *ssh_list_find(const struct ssh_list *list, void *value);
size_t ssh_list_count(const struct ssh_list *list);
int ssh_list_append(struct ssh_list *list, const void *data);
int ssh_list_prepend(struct ssh_list *list, const void *data);
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);

View File

@@ -22,9 +22,7 @@
#define _OPTIONS_H
int ssh_config_parse_file(ssh_session session, const char *filename);
int ssh_options_set_algo(ssh_session session,
enum ssh_kex_types_e algo,
const char *list);
int ssh_options_set_algo(ssh_session session, int algo, const char *list);
int ssh_options_apply(ssh_session session);
#endif /* _OPTIONS_H */

View File

@@ -43,7 +43,18 @@ enum ssh_packet_state_e {
PACKET_STATE_PROCESSING
};
int ssh_packet_send(ssh_session session);
int packet_send(ssh_session session);
#ifdef WITH_SSH1
int packet_send1(ssh_session session) ;
void ssh_packet_set_default_callbacks1(ssh_session session);
SSH_PACKET_CALLBACK(ssh_packet_disconnect1);
SSH_PACKET_CALLBACK(ssh_packet_smsg_success1);
SSH_PACKET_CALLBACK(ssh_packet_smsg_failure1);
int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user);
#endif
SSH_PACKET_CALLBACK(ssh_packet_unimplemented);
SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback);
@@ -67,13 +78,12 @@ void ssh_packet_set_default_callbacks(ssh_session session);
void ssh_packet_process(ssh_session session, uint8_t type);
/* PACKET CRYPT */
uint32_t ssh_packet_decrypt_len(ssh_session session, uint8_t *destination, uint8_t *source);
int ssh_packet_decrypt(ssh_session session, uint8_t *destination, uint8_t *source,
size_t start, size_t encrypted_size);
unsigned char *ssh_packet_encrypt(ssh_session session,
void *packet,
unsigned int len);
int ssh_packet_hmac_verify(ssh_session session,ssh_buffer buffer,
unsigned char *mac, enum ssh_hmac_e type);
uint32_t packet_decrypt_len(ssh_session session, char *crypted);
int packet_decrypt(ssh_session session, void *packet, unsigned int len);
unsigned char *packet_encrypt(ssh_session session,
void *packet,
unsigned int len);
int packet_hmac_verify(ssh_session session,ssh_buffer buffer,
unsigned char *mac, enum ssh_hmac_e type);
#endif /* PACKET_H_ */

View File

@@ -43,3 +43,4 @@ int ssh_pcap_context_write(ssh_pcap_context,enum ssh_pcap_direction direction, v
#endif /* WITH_PCAP */
#endif /* PCAP_H_ */
/* vim: set ts=2 sw=2 et cindent: */

View File

@@ -47,11 +47,7 @@ struct ssh_key_struct {
#ifdef HAVE_LIBGCRYPT
gcry_sexp_t dsa;
gcry_sexp_t rsa;
gcry_sexp_t ecdsa;
#elif HAVE_LIBMBEDCRYPTO
mbedtls_pk_context *rsa;
mbedtls_ecdsa_context *ecdsa;
void *dsa;
void *ecdsa;
#elif HAVE_LIBCRYPTO
DSA *dsa;
RSA *rsa;
@@ -64,7 +60,6 @@ struct ssh_key_struct {
ed25519_pubkey *ed25519_pubkey;
ed25519_privkey *ed25519_privkey;
void *cert;
enum ssh_keytypes_e cert_type;
};
struct ssh_signature_struct {
@@ -73,7 +68,7 @@ struct ssh_signature_struct {
#ifdef HAVE_LIBGCRYPT
gcry_sexp_t dsa_sig;
gcry_sexp_t rsa_sig;
gcry_sexp_t ecdsa_sig;
void *ecdsa_sig;
#elif defined HAVE_LIBCRYPTO
DSA_SIG *dsa_sig;
ssh_string rsa_sig;
@@ -82,9 +77,6 @@ struct ssh_signature_struct {
# else
void *ecdsa_sig;
# endif
#elif defined HAVE_LIBMBEDCRYPTO
ssh_string rsa_sig;
struct mbedtls_ecdsa_sig ecdsa_sig;
#endif
ed25519_signature *ed25519_sig;
};
@@ -115,10 +107,10 @@ int ssh_pki_export_pubkey_blob(const ssh_key key,
ssh_string *pblob);
int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
ssh_key *pkey);
int ssh_pki_import_cert_blob(const ssh_string cert_blob,
ssh_key *pkey);
int ssh_pki_export_pubkey_rsa1(const ssh_key key,
const char *host,
char *rsa1,
size_t rsa1_len);
/* SSH Signing Functions */
ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf,

View File

@@ -43,6 +43,11 @@ int bcrypt_pbkdf(const char *pass,
/* Magic defined in OpenSSH/PROTOCOL.key */
#define OPENSSH_AUTH_MAGIC "openssh-key-v1"
#define ssh_pki_log(...) \
_ssh_log(SSH_LOG_FUNCTIONS, __func__, __VA_ARGS__)
void _ssh_pki_log(const char *function,
const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
int pki_key_ecdsa_nid_from_name(const char *name);
const char *pki_key_ecdsa_nid_to_name(int nid);
@@ -80,6 +85,10 @@ int pki_pubkey_build_rsa(ssh_key key,
ssh_string n);
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e);
ssh_string pki_publickey_to_blob(const ssh_key key);
int pki_export_pubkey_rsa1(const ssh_key key,
const char *host,
char *rsa1,
size_t rsa1_len);
/* SSH Signature Functions */
ssh_string pki_signature_to_blob(const ssh_signature sign);

View File

@@ -155,7 +155,5 @@ int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, struct ssh_socket_struct *s);
void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p);
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout);
ssh_poll_ctx ssh_poll_get_default_ctx(ssh_session session);
int ssh_event_add_poll(ssh_event event, ssh_poll_handle p);
void ssh_event_remove_poll(ssh_event event, ssh_poll_handle p);
#endif /* POLL_H_ */

View File

@@ -1,21 +0,0 @@
/*
* Public Domain poly1305 from Andrew Moon
* poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
*/
#ifndef POLY1305_H
#define POLY1305_H
#define POLY1305_KEYLEN 32
#define POLY1305_TAGLEN 16
void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen,
const uint8_t key[POLY1305_KEYLEN])
#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE
__attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN)))
__attribute__((__bounded__(__buffer__, 2, 3)))
__attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN)))
#endif
;
#endif /* POLY1305_H */

View File

@@ -29,8 +29,7 @@
#ifndef _LIBSSH_PRIV_H
#define _LIBSSH_PRIV_H
#include <stdlib.h>
#include <string.h>
#include "config.h"
#if !defined(HAVE_STRTOULL)
# if defined(HAVE___STRTOULL)
@@ -44,20 +43,6 @@
# endif
#endif /* !defined(HAVE_STRTOULL) */
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifndef bswap_32
#define bswap_32(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#endif
#ifdef _WIN32
/* Imitate define of inttypes.h */
@@ -150,11 +135,12 @@ int gettimeofday(struct timeval *__p, void *__t);
#ifndef ERROR_BUFFERLEN
#define ERROR_BUFFERLEN 1024
#endif
#ifndef CLIENT_BANNER_SSH2
#define CLIENT_BANNER_SSH2 "SSH-2.0-libssh_" SSH_STRINGIFY(LIBSSH_VERSION)
#endif /* CLIENT_BANNER_SSH2 */
#ifndef CLIENTBANNER1
#define CLIENTBANNER1 "SSH-1.5-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
#endif
#ifndef CLIENTBANNER2
#define CLIENTBANNER2 "SSH-2.0-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
#endif
#ifndef KBDINT_MAX_PROMPT
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
#endif
@@ -189,6 +175,10 @@ int gettimeofday(struct timeval *__p, void *__t);
# define LIBSSH_MEM_PROTECTION
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
/* forward declarations */
struct ssh_common_struct;
struct ssh_kex_struct;
@@ -259,18 +249,10 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen);
/* match.c */
int match_hostname(const char *host, const char *pattern, unsigned int len);
/* connector.c */
int ssh_connector_set_event(ssh_connector connector, ssh_event event);
int ssh_connector_remove_event(ssh_connector connector);
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
/** Free memory space */
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
@@ -283,9 +265,33 @@ int ssh_connector_remove_event(ssh_connector connector);
/** Get the size of an array */
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#ifndef HAVE_EXPLICIT_BZERO
void explicit_bzero(void *s, size_t n);
#endif /* !HAVE_EXPLICIT_BZERO */
/*
* See http://llvm.org/bugs/show_bug.cgi?id=15495
*/
#if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
/** Overwrite a string with '\0' */
# define BURN_STRING(x) do { \
if ((x) != NULL) \
memset((x), '\0', strlen((x))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
} while(0)
/** Overwrite the buffer with '\0' */
# define BURN_BUFFER(x, size) do { \
if ((x) != NULL) \
memset((x), '\0', (size)); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
} while(0)
#else /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
/** Overwrite a string with '\0' */
# define BURN_STRING(x) do { \
if ((x) != NULL) memset((x), '\0', strlen((x))); \
} while(0)
/** Overwrite the buffer with '\0' */
# define BURN_BUFFER(x, size) do { \
if ((x) != NULL) \
memset((x), '\0', (size)); \
} while(0)
#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
/**
* This is a hack to fix warnings. The idea is to use this everywhere that we
@@ -345,32 +351,5 @@ void explicit_bzero(void *s, size_t n);
#define CLOSE_SOCKET(s) do { if ((s) != SSH_INVALID_SOCKET) { _XCLOSESOCKET(s); (s) = SSH_INVALID_SOCKET;} } while(0)
#ifndef HAVE_HTONLL
# ifdef WORDS_BIGENDIAN
# define htonll(x) (x)
# else
# define htonll(x) \
(((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
# endif
#endif
#ifndef HAVE_NTOHLL
# ifdef WORDS_BIGENDIAN
# define ntohll(x) (x)
# else
# define ntohll(x) \
(((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
# endif
#endif
#ifndef FALL_THROUGH
# ifdef HAVE_FALLTHROUGH_ATTRIBUTE
# define FALL_THROUGH __attribute__ ((fallthrough))
# else /* HAVE_FALLTHROUGH_ATTRIBUTE */
# define FALL_THROUGH
# endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
#endif /* FALL_THROUGH */
void ssh_agent_state_free(void *data);
#endif /* _LIBSSH_PRIV_H */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -45,8 +45,7 @@ enum ssh_bind_options_e {
SSH_BIND_OPTIONS_BANNER,
SSH_BIND_OPTIONS_LOG_VERBOSITY,
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
SSH_BIND_OPTIONS_ECDSAKEY,
SSH_BIND_OPTIONS_IMPORT_KEY
SSH_BIND_OPTIONS_ECDSAKEY
};
typedef struct ssh_bind_struct* ssh_bind;
@@ -187,24 +186,6 @@ LIBSSH_API ssh_gssapi_creds ssh_gssapi_get_creds(ssh_session session);
*/
LIBSSH_API int ssh_handle_key_exchange(ssh_session session);
/**
* @brief Initialize the set of key exchange, hostkey, ciphers, MACs, and
* compression algorithms for the given ssh_session.
*
* The selection of algorithms and keys used are determined by the
* options that are currently set in the given ssh_session structure.
* May only be called before the initial key exchange has begun.
*
* @param session The session structure to initialize.
*
* @see ssh_handle_key_exchange
* @see ssh_options_set
*
* @return SSH_OK if initialization succeeds.
*/
LIBSSH_API int ssh_server_init_kex(ssh_session session);
/**
* @brief Free a ssh servers bind.
*
@@ -212,23 +193,6 @@ LIBSSH_API int ssh_server_init_kex(ssh_session session);
*/
LIBSSH_API void ssh_bind_free(ssh_bind ssh_bind_o);
/**
* @brief Set the acceptable authentication methods to be sent to the client.
*
*
* @param[in] session The server session
*
* @param[in] auth_methods The authentication methods we will support, which
* can be bitwise-or'd.
*
* Supported methods are:
*
* SSH_AUTH_METHOD_PASSWORD
* SSH_AUTH_METHOD_PUBLICKEY
* SSH_AUTH_METHOD_HOSTBASED
* SSH_AUTH_METHOD_INTERACTIVE
* SSH_AUTH_METHOD_GSSAPI_MIC
*/
LIBSSH_API void ssh_set_auth_methods(ssh_session session, int auth_methods);
/**********************************************************
@@ -352,6 +316,9 @@ LIBSSH_API int ssh_channel_request_send_exit_signal(ssh_channel channel,
int core,
const char *errmsg,
const char *lang);
LIBSSH_API int ssh_channel_write_stderr(ssh_channel channel,
const void *data,
uint32_t len);
LIBSSH_API int ssh_send_keepalive(ssh_session session);

View File

@@ -79,13 +79,6 @@ enum ssh_pending_call_e {
/* Don't block at all */
#define SSH_TIMEOUT_NONBLOCKING 0
/* options flags */
/* Authentication with *** allowed */
#define SSH_OPT_FLAG_PASSWORD_AUTH 0x1
#define SSH_OPT_FLAG_PUBKEY_AUTH 0x2
#define SSH_OPT_FLAG_KBDINT_AUTH 0x4
#define SSH_OPT_FLAG_GSSAPI_AUTH 0x8
/* members that are common to ssh_session and ssh_bind */
struct ssh_common_struct {
struct error_struct error;
@@ -157,7 +150,7 @@ struct ssh_session_struct {
/* keyb interactive data */
struct ssh_kbdint_struct *kbdint;
struct ssh_gssapi_struct *gssapi;
int version; /* 1 or 2 */
/* server host keys */
struct {
ssh_key rsa_key;
@@ -189,7 +182,6 @@ struct ssh_session_struct {
char *bindaddr; /* bind the client to an ip addr */
char *sshdir;
char *knownhosts;
char *global_knownhosts;
char *wanted_methods[10];
char *ProxyCommand;
char *custombanner;
@@ -198,12 +190,12 @@ struct ssh_session_struct {
unsigned int port;
socket_t fd;
int StrictHostKeyChecking;
int ssh2;
int ssh1;
char compressionlevel;
char *gss_server_identity;
char *gss_client_identity;
int gss_delegate_creds;
int flags;
int nodelay;
} opts;
/* counters */
ssh_counter socket_counter;

View File

@@ -788,22 +788,6 @@ LIBSSH_API sftp_statvfs_t sftp_fstatvfs(sftp_file file);
*/
LIBSSH_API void sftp_statvfs_free(sftp_statvfs_t statvfs_o);
/**
* @brief Synchronize a file's in-core state with storage device
*
* This calls the "fsync@openssh.com" extention. You should check if the
* extensions is supported using:
*
* @code
* int supported = sftp_extension_supported(sftp, "fsync@openssh.com", "1");
* @endcode
*
* @param file The opened sftp file handle to sync
*
* @return 0 on success, < 0 on error with ssh and sftp error set.
*/
LIBSSH_API int sftp_fsync(sftp_file file);
/**
* @brief Canonicalize a sftp path.
*
@@ -863,18 +847,18 @@ LIBSSH_API void sftp_client_message_set_filename(sftp_client_message msg, const
LIBSSH_API const char *sftp_client_message_get_data(sftp_client_message msg);
LIBSSH_API uint32_t sftp_client_message_get_flags(sftp_client_message msg);
LIBSSH_API int sftp_send_client_message(sftp_session sftp, sftp_client_message msg);
LIBSSH_API int sftp_reply_name(sftp_client_message msg, const char *name,
int sftp_reply_name(sftp_client_message msg, const char *name,
sftp_attributes attr);
LIBSSH_API int sftp_reply_handle(sftp_client_message msg, ssh_string handle);
LIBSSH_API ssh_string sftp_handle_alloc(sftp_session sftp, void *info);
LIBSSH_API int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr);
LIBSSH_API void *sftp_handle(sftp_session sftp, ssh_string handle);
LIBSSH_API int sftp_reply_status(sftp_client_message msg, uint32_t status, const char *message);
LIBSSH_API int sftp_reply_names_add(sftp_client_message msg, const char *file,
int sftp_reply_handle(sftp_client_message msg, ssh_string handle);
ssh_string sftp_handle_alloc(sftp_session sftp, void *info);
int sftp_reply_attr(sftp_client_message msg, sftp_attributes attr);
void *sftp_handle(sftp_session sftp, ssh_string handle);
int sftp_reply_status(sftp_client_message msg, uint32_t status, const char *message);
int sftp_reply_names_add(sftp_client_message msg, const char *file,
const char *longname, sftp_attributes attr);
LIBSSH_API int sftp_reply_names(sftp_client_message msg);
LIBSSH_API int sftp_reply_data(sftp_client_message msg, const void *data, int len);
LIBSSH_API void sftp_handle_remove(sftp_session sftp, void *handle);
int sftp_reply_names(sftp_client_message msg);
int sftp_reply_data(sftp_client_message msg, const void *data, int len);
void sftp_handle_remove(sftp_session sftp, void *handle);
/* SFTP commands and constants */
#define SSH_FXP_INIT 1
@@ -978,16 +962,6 @@ LIBSSH_API void sftp_handle_remove(sftp_session sftp, void *handle);
#define SSH_FXF_EXCL 0x20
#define SSH_FXF_TEXT 0x40
/* file type flags */
#define SSH_S_IFMT 00170000
#define SSH_S_IFSOCK 0140000
#define SSH_S_IFLNK 0120000
#define SSH_S_IFREG 0100000
#define SSH_S_IFBLK 0060000
#define SSH_S_IFDIR 0040000
#define SSH_S_IFCHR 0020000
#define SSH_S_IFIFO 0010000
/* rename flags */
#define SSH_FXF_RENAME_OVERWRITE 0x00000001
#define SSH_FXF_RENAME_ATOMIC 0x00000002
@@ -1017,9 +991,10 @@ LIBSSH_API void sftp_handle_remove(sftp_session sftp, void *handle);
#define SSH_FXE_STATVFS_ST_NOSUID 0x2 /* no setuid */
#ifdef __cplusplus
}
} ;
#endif
#endif /* SFTP_H */
/** @} */
/* vim: set ts=2 sw=2 et cindent: */

82
include/libssh/ssh1.h Normal file
View File

@@ -0,0 +1,82 @@
#ifndef __SSH1_H
#define __SSH1_H
#define SSH_MSG_NONE 0 /* no message */
#define SSH_MSG_DISCONNECT 1 /* cause (string) */
#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
#define SSH_CMSG_USER 4 /* user (string) */
#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */
#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */
#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */
#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */
#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */
#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */
#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */
#define SSH_CMSG_EXEC_SHELL 12 /* */
#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */
#define SSH_SMSG_SUCCESS 14 /* */
#define SSH_SMSG_FAILURE 15 /* */
#define SSH_CMSG_STDIN_DATA 16 /* data (string) */
#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */
#define SSH_SMSG_STDERR_DATA 18 /* data (string) */
#define SSH_CMSG_EOF 19 /* */
#define SSH_SMSG_EXITSTATUS 20 /* status (int) */
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */
#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */
#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */
#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */
#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */
/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */
#define SSH_SMSG_X11_OPEN 27 /* channel (int) */
#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */
#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */
#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */
#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */
#define SSH_MSG_IGNORE 32 /* string */
#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */
#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */
#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */
#define SSH_MSG_DEBUG 36 /* string */
#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */
#define SSH_CMSG_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */
#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */
#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */
#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */
#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */
#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */
#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */
#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */
/* protocol version 1.5 overloads some version 1.3 message types */
#define SSH_MSG_CHANNEL_INPUT_EOF SSH_MSG_CHANNEL_CLOSE
#define SSH_MSG_CHANNEL_OUTPUT_CLOSE SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
/*
* Authentication methods. New types can be added, but old types should not
* be removed for compatibility. The maximum allowed value is 31.
*/
#define SSH_AUTH_RHOSTS 1
#define SSH_AUTH_RSA 2
#define SSH_AUTH_PASSWORD 3
#define SSH_AUTH_RHOSTS_RSA 4
#define SSH_AUTH_TIS 5
#define SSH_AUTH_KERBEROS 6
#define SSH_PASS_KERBEROS_TGT 7
/* 8 to 15 are reserved */
#define SSH_PASS_AFS_TOKEN 21
/* Protocol flags. These are bit masks. */
#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */
#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */
/* cipher flags. they are bit numbers */
#define SSH_CIPHER_NONE 0 /* No encryption */
#define SSH_CIPHER_IDEA 1 /* IDEA in CFB mode */
#define SSH_CIPHER_DES 2 /* DES in CBC mode */
#define SSH_CIPHER_3DES 3 /* Triple-DES in CBC mode */
#define SSH_CIPHER_RC4 5 /* RC4 */
#define SSH_CIPHER_BLOWFISH 6
#endif

View File

@@ -24,40 +24,8 @@
#include <libssh/libssh.h>
#include <libssh/callbacks.h>
#if HAVE_PTHREAD
#include <pthread.h>
#define SSH_MUTEX pthread_mutex_t
#if defined _GNU_SOURCE
#define SSH_MUTEX_STATIC_INIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
#else
#define SSH_MUTEX_STATIC_INIT PTHREAD_MUTEX_INITIALIZER
#endif
#elif (defined _WIN32) || (defined _WIN64)
#include <windows.h>
#include <winbase.h>
#define SSH_MUTEX CRITICAL_SECTION *
#define SSH_MUTEX_STATIC_INIT NULL
#else
# define SSH_MUTEX void *
#define SSH_MUTEX_STATIC_INIT NULL
#endif
int ssh_threads_init(void);
void ssh_threads_finalize(void);
const char *ssh_threads_get_type(void);
void ssh_mutex_lock(SSH_MUTEX *mutex);
void ssh_mutex_unlock(SSH_MUTEX *mutex);
struct ssh_threads_callbacks_struct *ssh_threads_get_default(void);
int crypto_thread_init(struct ssh_threads_callbacks_struct *user_callbacks);
void crypto_thread_finalize(void);
#endif /* THREADS_H_ */

View File

@@ -25,7 +25,6 @@
#include "libssh/libssh.h"
#include "libssh/libcrypto.h"
#include "libssh/libgcrypt.h"
#include "libssh/libmbedcrypto.h"
enum ssh_mac_e {
SSH_MAC_SHA1=1,
@@ -39,8 +38,7 @@ enum ssh_hmac_e {
SSH_HMAC_SHA256,
SSH_HMAC_SHA384,
SSH_HMAC_SHA512,
SSH_HMAC_MD5,
SSH_HMAC_AEAD_POLY1305
SSH_HMAC_MD5
};
enum ssh_des_e {
@@ -53,8 +51,6 @@ struct ssh_hmac_struct {
enum ssh_hmac_e hmac_type;
};
struct ssh_cipher_struct;
typedef struct ssh_mac_ctx_struct *ssh_mac_ctx;
MD5CTX md5_init(void);
void md5_update(MD5CTX c, const void *data, unsigned long len);
@@ -94,18 +90,15 @@ void hmac_update(HMACCTX c, const void *data, unsigned long len);
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
size_t hmac_digest_len(enum ssh_hmac_e type);
int crypt_set_algorithms_client(ssh_session session);
int crypt_set_algorithms(ssh_session session, enum ssh_des_e des_type);
int crypt_set_algorithms_server(ssh_session session);
struct ssh_crypto_struct *crypto_new(void);
void crypto_free(struct ssh_crypto_struct *crypto);
void ssh_reseed(void);
int ssh_crypto_init(void);
void ssh_crypto_finalize(void);
void ssh_cipher_clear(struct ssh_cipher_struct *cipher);
struct ssh_hmac_struct *ssh_get_hmactab(void);
struct ssh_cipher_struct *ssh_get_ciphertab(void);
const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type);
#endif /* WRAPPER_H_ */

View File

@@ -11,5 +11,3 @@ set(LIBSSH_LIBRARY @LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@)
set(LIBSSH_LIBRARIES @LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@)
set(LIBSSH_THREADS_LIBRARY @LIB_INSTALL_DIR@/@LIBSSH_THREADS_LIBRARY_NAME@)
mark_as_advanced(LIBSSH_LIBRARIES LIBSSH_INCLUDE_DIR)

View File

@@ -63,7 +63,7 @@ function clean_build_dir() {
function usage () {
echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help|--clang|--cmakedir /directory|--make
(gmake|make)|--ccompiler(gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withserver|--withoutsymbolversioning]"
(gmake|make)|--ccompiler (gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withssh1|--withserver]"
cleanup_and_exit
}
@@ -137,20 +137,17 @@ while test -n "$1"; do
OPTIONS="${OPTIONS} -DWITH_STATIC_LIB=ON"
;;
*-unittesting)
OPTIONS="${OPTIONS} -DUNIT_TESTING=ON"
OPTIONS="${OPTIONS} -DWITH_TESTING=ON"
;;
*-clientunittesting)
OPTIONS="${OPTIONS} -DCLIENT_TESTING=ON"
OPTIONS="${OPTIONS} -DWITH_CLIENT_TESTING=ON"
;;
*-withssh1)
OPTIONS="${OPTIONS} -DWITH_SSH1=ON"
;;
*-withserver)
OPTIONS="${OPTIONS} -DWITH_SERVER=ON"
;;
*-withoutsymbolversioning)
OPTIONS="${OPTIONS} -DWITH_SYMBOL_VERSIONING=OFF"
;;
*-finalrelease)
OPTIONS="${OPTIONS} -DWITH_FINAL=ON"
;;
----noarg)
echo "$ARG does not take an argument"
cleanup_and_exit

View File

@@ -1 +0,0 @@
4.5.0

View File

@@ -1,411 +0,0 @@
ssh_set_server_callbacks
ssh_set_callbacks
ssh_set_channel_callbacks
ssh_add_channel_callbacks
ssh_remove_channel_callbacks
ssh_threads_set_callbacks
ssh_threads_get_pthread
ssh_threads_get_noop
ssh_set_log_callback
ssh_get_log_callback
ssh_auth_list
ssh_userauth_offer_pubkey
ssh_userauth_pubkey
ssh_userauth_agent_pubkey
ssh_userauth_autopubkey
ssh_userauth_privatekey_file
buffer_free
buffer_get
buffer_get_len
buffer_new
channel_accept_x11
channel_change_pty_size
channel_forward_accept
channel_close
channel_forward_cancel
channel_forward_listen
channel_free
channel_get_exit_status
channel_get_session
channel_is_closed
channel_is_eof
channel_is_open
channel_new
channel_open_forward
channel_open_session
channel_poll
channel_read
channel_read_buffer
channel_read_nonblocking
channel_request_env
channel_request_exec
channel_request_pty
channel_request_pty_size
channel_request_shell
channel_request_send_signal
channel_request_sftp
channel_request_subsystem
channel_request_x11
channel_send_eof
channel_select
channel_set_blocking
channel_write
privatekey_free
privatekey_from_file
publickey_free
ssh_publickey_to_file
publickey_from_file
publickey_from_privatekey
publickey_to_string
ssh_try_publickey_from_file
ssh_privatekey_type
ssh_get_pubkey
ssh_message_retrieve
ssh_message_auth_publickey
string_burn
string_copy
string_data
string_fill
string_free
string_from_char
string_len
string_new
string_to_char
ssh_blocking_flush
ssh_channel_accept_x11
ssh_channel_change_pty_size
ssh_channel_close
ssh_channel_free
ssh_channel_get_exit_status
ssh_channel_get_session
ssh_channel_is_closed
ssh_channel_is_eof
ssh_channel_is_open
ssh_channel_new
ssh_channel_open_auth_agent
ssh_channel_open_forward
ssh_channel_open_session
ssh_channel_open_x11
ssh_channel_poll
ssh_channel_poll_timeout
ssh_channel_read
ssh_channel_read_timeout
ssh_channel_read_nonblocking
ssh_channel_request_env
ssh_channel_request_exec
ssh_channel_request_pty
ssh_channel_request_pty_size
ssh_channel_request_shell
ssh_channel_request_send_signal
ssh_channel_request_send_break
ssh_channel_request_sftp
ssh_channel_request_subsystem
ssh_channel_request_x11
ssh_channel_request_auth_agent
ssh_channel_send_eof
ssh_channel_select
ssh_channel_set_blocking
ssh_channel_set_counter
ssh_channel_write
ssh_channel_write_stderr
ssh_channel_window_size
ssh_basename
ssh_clean_pubkey_hash
ssh_connect
ssh_connector_new
ssh_connector_free
ssh_connector_set_in_channel
ssh_connector_set_out_channel
ssh_connector_set_in_fd
ssh_connector_set_out_fd
ssh_copyright
ssh_disconnect
ssh_dirname
ssh_finalize
ssh_channel_accept_forward
ssh_channel_cancel_forward
ssh_channel_listen_forward
ssh_free
ssh_get_disconnect_message
ssh_get_error
ssh_get_error_code
ssh_get_fd
ssh_get_hexa
ssh_get_issue_banner
ssh_get_openssh_version
ssh_get_server_publickey
ssh_get_publickey_hash
ssh_get_pubkey_hash
ssh_forward_accept
ssh_forward_cancel
ssh_forward_listen
ssh_get_publickey
ssh_get_random
ssh_get_version
ssh_get_status
ssh_get_poll_flags
ssh_init
ssh_is_blocking
ssh_is_connected
ssh_is_server_known
ssh_knownhosts_entry_free
ssh_known_hosts_parse_line
ssh_session_has_known_hosts_entry
ssh_session_export_known_hosts_entry
ssh_session_update_known_hosts
ssh_session_is_known_server
ssh_set_log_level
ssh_get_log_level
ssh_get_log_userdata
ssh_set_log_userdata
_ssh_log
ssh_log
ssh_message_channel_request_open_reply_accept
ssh_message_channel_request_reply_success
ssh_message_free
ssh_message_get
ssh_message_subtype
ssh_message_type
ssh_mkdir
ssh_new
ssh_options_copy
ssh_options_getopt
ssh_options_parse_config
ssh_options_set
ssh_options_get
ssh_options_get_port
ssh_pcap_file_close
ssh_pcap_file_free
ssh_pcap_file_new
ssh_pcap_file_open
ssh_key_new
ssh_key_free
ssh_key_type
ssh_key_type_to_char
ssh_key_type_from_name
ssh_key_is_public
ssh_key_is_private
ssh_key_cmp
ssh_pki_generate
ssh_pki_import_privkey_base64
ssh_pki_import_privkey_file
ssh_pki_export_privkey_file
ssh_pki_copy_cert_to_privkey
ssh_pki_import_pubkey_base64
ssh_pki_import_pubkey_file
ssh_pki_import_cert_base64
ssh_pki_import_cert_file
ssh_pki_export_privkey_to_pubkey
ssh_pki_export_pubkey_base64
ssh_pki_export_pubkey_file
ssh_pki_key_ecdsa_name
ssh_print_hexa
ssh_send_ignore
ssh_send_debug
ssh_gssapi_set_creds
ssh_scp_accept_request
ssh_scp_close
ssh_scp_deny_request
ssh_scp_free
ssh_scp_init
ssh_scp_leave_directory
ssh_scp_new
ssh_scp_pull_request
ssh_scp_push_directory
ssh_scp_push_file
ssh_scp_push_file64
ssh_scp_read
ssh_scp_request_get_filename
ssh_scp_request_get_permissions
ssh_scp_request_get_size
ssh_scp_request_get_size64
ssh_scp_request_get_warning
ssh_scp_write
ssh_select
ssh_service_request
ssh_set_agent_channel
ssh_set_agent_socket
ssh_set_blocking
ssh_set_counters
ssh_set_fd_except
ssh_set_fd_toread
ssh_set_fd_towrite
ssh_silent_disconnect
ssh_set_pcap_file
ssh_userauth_none
ssh_userauth_list
ssh_userauth_try_publickey
ssh_userauth_publickey
ssh_userauth_agent
ssh_userauth_publickey_auto
ssh_userauth_password
ssh_userauth_kbdint
ssh_userauth_kbdint_getinstruction
ssh_userauth_kbdint_getname
ssh_userauth_kbdint_getnprompts
ssh_userauth_kbdint_getprompt
ssh_userauth_kbdint_getnanswers
ssh_userauth_kbdint_getanswer
ssh_userauth_kbdint_setanswer
ssh_userauth_gssapi
ssh_version
ssh_write_knownhost
ssh_dump_knownhost
ssh_string_burn
ssh_string_copy
ssh_string_data
ssh_string_fill
ssh_string_free
ssh_string_from_char
ssh_string_len
ssh_string_new
ssh_string_get_char
ssh_string_to_char
ssh_string_free_char
ssh_getpass
ssh_event_new
ssh_event_add_fd
ssh_event_add_session
ssh_event_add_connector
ssh_event_dopoll
ssh_event_remove_fd
ssh_event_remove_session
ssh_event_remove_connector
ssh_event_free
ssh_get_clientbanner
ssh_get_serverbanner
ssh_get_kex_algo
ssh_get_cipher_in
ssh_get_cipher_out
ssh_get_hmac_in
ssh_get_hmac_out
ssh_buffer_new
ssh_buffer_free
ssh_buffer_reinit
ssh_buffer_add_data
ssh_buffer_get_data
ssh_buffer_get
ssh_buffer_get_len
ssh_bind_new
ssh_bind_options_set
ssh_bind_listen
ssh_bind_set_callbacks
ssh_bind_set_blocking
ssh_bind_get_fd
ssh_bind_set_fd
ssh_bind_fd_toaccept
ssh_bind_accept
ssh_bind_accept_fd
ssh_gssapi_get_creds
ssh_handle_key_exchange
ssh_server_init_kex
ssh_bind_free
ssh_set_auth_methods
ssh_message_reply_default
ssh_message_auth_user
ssh_message_auth_password
ssh_message_auth_pubkey
ssh_message_auth_kbdint_is_response
ssh_message_auth_publickey_state
ssh_message_auth_reply_success
ssh_message_auth_reply_pk_ok
ssh_message_auth_reply_pk_ok_simple
ssh_message_auth_set_methods
ssh_message_auth_interactive_request
ssh_message_service_reply_success
ssh_message_service_service
ssh_message_global_request_reply_success
ssh_set_message_callback
ssh_execute_message_callbacks
ssh_message_channel_request_open_originator
ssh_message_channel_request_open_originator_port
ssh_message_channel_request_open_destination
ssh_message_channel_request_open_destination_port
ssh_message_channel_request_channel
ssh_message_channel_request_pty_term
ssh_message_channel_request_pty_width
ssh_message_channel_request_pty_height
ssh_message_channel_request_pty_pxwidth
ssh_message_channel_request_pty_pxheight
ssh_message_channel_request_env_name
ssh_message_channel_request_env_value
ssh_message_channel_request_command
ssh_message_channel_request_subsystem
ssh_message_channel_request_x11_single_connection
ssh_message_channel_request_x11_auth_protocol
ssh_message_channel_request_x11_auth_cookie
ssh_message_channel_request_x11_screen_number
ssh_message_global_request_address
ssh_message_global_request_port
ssh_channel_open_reverse_forward
ssh_channel_request_send_exit_status
ssh_channel_request_send_exit_signal
ssh_send_keepalive
ssh_accept
channel_write_stderr
sftp_new
sftp_new_channel
sftp_free
sftp_init
sftp_get_error
sftp_extensions_get_count
sftp_extensions_get_name
sftp_extensions_get_data
sftp_extension_supported
sftp_opendir
sftp_readdir
sftp_dir_eof
sftp_stat
sftp_lstat
sftp_fstat
sftp_attributes_free
sftp_closedir
sftp_close
sftp_open
sftp_file_set_nonblocking
sftp_file_set_blocking
sftp_read
sftp_async_read_begin
sftp_async_read
sftp_write
sftp_seek
sftp_seek64
sftp_tell
sftp_tell64
sftp_rewind
sftp_unlink
sftp_rmdir
sftp_mkdir
sftp_rename
sftp_setstat
sftp_chown
sftp_chmod
sftp_utimes
sftp_symlink
sftp_readlink
sftp_statvfs
sftp_fstatvfs
sftp_statvfs_free
sftp_fsync
sftp_canonicalize_path
sftp_server_version
sftp_server_new
sftp_server_init
sftp_get_client_message
sftp_client_message_free
sftp_client_message_get_type
sftp_client_message_get_filename
sftp_client_message_set_filename
sftp_client_message_get_data
sftp_client_message_get_flags
sftp_send_client_message
sftp_reply_name
sftp_reply_handle
sftp_handle_alloc
sftp_reply_attr
sftp_handle
sftp_reply_status
sftp_reply_names_add
sftp_reply_names
sftp_reply_data
sftp_handle_remove

View File

@@ -1,3 +1,5 @@
project(libssh-library C)
set(LIBSSH_PUBLIC_INCLUDE_DIRS
${libssh_SOURCE_DIR}/include
CACHE INTERNAL "libssh public include directories"
@@ -37,17 +39,6 @@ if (OPENSSL_CRYPTO_LIBRARY)
)
endif (OPENSSL_CRYPTO_LIBRARY)
if (MBEDTLS_CRYPTO_LIBRARY)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
${MBEDTLS_INCLUDE_DIR}
)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
${MBEDTLS_CRYPTO_LIBRARY}
)
endif (MBEDTLS_CRYPTO_LIBRARY)
if (GCRYPT_LIBRARY)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
@@ -124,7 +115,6 @@ set(libssh_SRCS
client.c
config.c
connect.c
connector.c
curve25519.c
dh.c
ecdh.c
@@ -133,8 +123,8 @@ set(libssh_SRCS
init.c
kex.c
known_hosts.c
knownhosts.c
legacy.c
libcrypto.c
log.c
match.c
messages.c
@@ -156,63 +146,24 @@ set(libssh_SRCS
wrapper.c
external/bcrypt_pbkdf.c
external/blowfish.c
external/chacha.c
external/ed25519.c
external/fe25519.c
external/ge25519.c
external/poly1305.c
external/sc25519.c
chachapoly.c
)
if (CMAKE_USE_PTHREADS_INIT)
set(libssh_SRCS
${libssh_SRCS}
threads/noop.c
threads/pthread.c
)
elseif (CMAKE_USE_WIN32_THREADS_INIT)
set(libssh_SRCS
${libssh_SRCS}
threads/noop.c
threads/winlocks.c
)
else()
set(libssh_SRCS
${libssh_SRCS}
threads/noop.c
)
endif()
if (WITH_GCRYPT)
set(libssh_SRCS
${libssh_SRCS}
threads/libgcrypt.c
libgcrypt.c
gcrypt_missing.c
pki_gcrypt.c
ecdh_gcrypt.c
)
elseif (WITH_MBEDTLS)
set(libssh_SRCS
${libssh_SRCS}
threads/mbedtls.c
libmbedcrypto.c
mbedcrypto_missing.c
pki_mbedcrypto.c
ecdh_mbedcrypto.c
)
else (WITH_GCRYPT)
set(libssh_SRCS
${libssh_SRCS}
threads/libcrypto.c
pki_crypto.c
ecdh_crypto.c
libcrypto.c
)
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
endif()
endif (WITH_GCRYPT)
if (WITH_SFTP)
@@ -229,6 +180,17 @@ if (WITH_SFTP)
endif (WITH_SERVER)
endif (WITH_SFTP)
if (WITH_SSH1)
set(libssh_SRCS
${libssh_SRCS}
auth1.c
channels1.c
crc32.c
kex1.c
packet1.c
)
endif (WITH_SSH1)
if (WITH_SERVER)
set(libssh_SRCS
${libssh_SRCS}
@@ -263,52 +225,10 @@ include_directories(
${LIBSSH_PRIVATE_INCLUDE_DIRS}
)
# Set the path to the default map file
set(MAP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.map")
if (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
# Get the list of header files
get_file_list("dev_header_list"
DIRECTORIES "${LIBSSH_PUBLIC_INCLUDE_DIRS}/libssh"
FILES_PATTERNS "*.h")
# Extract the symbols marked as "LIBSSH_API" from the header files
extract_symbols("${PROJECT_NAME}_dev.symbols"
HEADERS_LIST_FILE "dev_header_list"
FILTER_PATTERN "LIBSSH_API")
if (WITH_ABI_BREAK)
set(ALLOW_ABI_BREAK "BREAK_ABI")
endif()
# Generate the symbol version map file
generate_map_file("${PROJECT_NAME}_dev.map"
SYMBOLS "${PROJECT_NAME}_dev.symbols"
RELEASE_NAME_VERSION ${PROJECT_NAME}_AFTER_${LIBRARY_VERSION}
CURRENT_MAP ${MAP_PATH}
${ALLOW_ABI_BREAK})
set(libssh_SRCS
${libssh_SRCS}
${PROJECT_NAME}_dev.map
)
endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
add_library(${LIBSSH_SHARED_LIBRARY} SHARED ${libssh_SRCS})
target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
if (WITH_SYMBOL_VERSIONING)
if (ABIMAP_FOUND)
# Change path to devel map file
set(MAP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_dev.map")
endif (ABIMAP_FOUND)
set_target_properties(${LIBSSH_SHARED_LIBRARY}
PROPERTIES LINK_FLAGS
"-Wl,--version-script,\"${MAP_PATH}\"")
endif (WITH_SYMBOL_VERSIONING)
set_target_properties(
${LIBSSH_SHARED_LIBRARY}
PROPERTIES
@@ -381,3 +301,6 @@ if (WITH_STATIC_LIB)
endif (WITH_STATIC_LIB)
message(STATUS "Threads_FOUND=${Threads_FOUND}")
if (Threads_FOUND)
add_subdirectory(threads)
endif (Threads_FOUND)

View File

@@ -143,7 +143,7 @@ static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int
}
}
ssh_agent ssh_agent_new(struct ssh_session_struct *session) {
ssh_agent agent_new(struct ssh_session_struct *session) {
ssh_agent agent = NULL;
agent = malloc(sizeof(struct ssh_agent_struct));
@@ -205,7 +205,7 @@ int ssh_set_agent_socket(ssh_session session, socket_t fd){
return SSH_OK;
}
void ssh_agent_close(struct ssh_agent_struct *agent) {
void agent_close(struct ssh_agent_struct *agent) {
if (agent == NULL) {
return;
}
@@ -213,13 +213,13 @@ void ssh_agent_close(struct ssh_agent_struct *agent) {
ssh_socket_close(agent->sock);
}
void ssh_agent_free(ssh_agent agent) {
void agent_free(ssh_agent agent) {
if (agent) {
if (agent->ident) {
ssh_buffer_free(agent->ident);
}
if (agent->sock) {
ssh_agent_close(agent);
agent_close(agent);
ssh_socket_free(agent->sock);
}
SAFE_FREE(agent);
@@ -273,13 +273,13 @@ static int agent_talk(struct ssh_session_struct *session,
uint32_t len = 0;
uint8_t payload[1024] = {0};
len = ssh_buffer_get_len(request);
len = buffer_get_rest_len(request);
SSH_LOG(SSH_LOG_TRACE, "Request length: %u", len);
agent_put_u32(payload, len);
/* send length and then the request packet */
if (atomicio(session->agent, payload, 4, 0) == 4) {
if (atomicio(session->agent, ssh_buffer_get(request), len, 0)
if (atomicio(session->agent, buffer_get_rest(request), len, 0)
!= len) {
SSH_LOG(SSH_LOG_WARN, "atomicio sending request failed: %s",
strerror(errno));
@@ -331,16 +331,30 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
ssh_buffer request = NULL;
ssh_buffer reply = NULL;
unsigned int type = 0;
unsigned int c1 = 0, c2 = 0;
uint8_t buf[4] = {0};
int rc;
switch (session->version) {
case 1:
c1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
c2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
break;
case 2:
c1 = SSH2_AGENTC_REQUEST_IDENTITIES;
c2 = SSH2_AGENT_IDENTITIES_ANSWER;
break;
default:
return 0;
}
/* send message to the agent requesting the list of identities */
request = ssh_buffer_new();
if (request == NULL) {
ssh_set_error_oom(session);
return -1;
}
if (ssh_buffer_add_u8(request, SSH2_AGENTC_REQUEST_IDENTITIES) < 0) {
if (buffer_add_u8(request, c1) < 0) {
ssh_set_error_oom(session);
ssh_buffer_free(request);
return -1;
@@ -361,32 +375,29 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
ssh_buffer_free(request);
/* get message type and verify the answer */
rc = ssh_buffer_get_u8(reply, (uint8_t *) &type);
rc = buffer_get_u8(reply, (uint8_t *) &type);
if (rc != sizeof(uint8_t)) {
ssh_set_error(session, SSH_FATAL,
"Bad authentication reply size: %d", rc);
ssh_buffer_free(reply);
return -1;
}
#ifdef WORDS_BIGENDIAN
type = bswap_32(type);
#endif
SSH_LOG(SSH_LOG_WARN,
"Answer type: %d, expected answer: %d",
type, SSH2_AGENT_IDENTITIES_ANSWER);
type, c2);
if (agent_failed(type)) {
ssh_buffer_free(reply);
return 0;
} else if (type != SSH2_AGENT_IDENTITIES_ANSWER) {
} else if (type != c2) {
ssh_set_error(session, SSH_FATAL,
"Bad authentication reply message type: %u", type);
"Bad authentication reply message type: %d", type);
ssh_buffer_free(reply);
return -1;
}
ssh_buffer_get_u32(reply, (uint32_t *) buf);
buffer_get_u32(reply, (uint32_t *) buf);
session->agent->count = agent_get_u32(buf);
SSH_LOG(SSH_LOG_DEBUG, "Agent count: %d",
session->agent->count);
@@ -428,45 +439,49 @@ ssh_key ssh_agent_get_next_ident(struct ssh_session_struct *session,
return NULL;
}
/* get the blob */
blob = ssh_buffer_get_ssh_string(session->agent->ident);
if (blob == NULL) {
return NULL;
}
switch(session->version) {
case 1:
return NULL;
case 2:
/* get the blob */
blob = buffer_get_ssh_string(session->agent->ident);
if (blob == NULL) {
return NULL;
}
/* get the comment */
tmp = ssh_buffer_get_ssh_string(session->agent->ident);
if (tmp == NULL) {
ssh_string_free(blob);
/* get the comment */
tmp = buffer_get_ssh_string(session->agent->ident);
if (tmp == NULL) {
ssh_string_free(blob);
return NULL;
}
return NULL;
}
if (comment) {
*comment = ssh_string_to_char(tmp);
} else {
ssh_string_free(blob);
ssh_string_free(tmp);
if (comment) {
*comment = ssh_string_to_char(tmp);
} else {
ssh_string_free(blob);
ssh_string_free(tmp);
return NULL;
}
ssh_string_free(tmp);
return NULL;
}
ssh_string_free(tmp);
/* get key from blob */
rc = ssh_pki_import_pubkey_blob(blob, &key);
if (rc == SSH_ERROR) {
/* Try again as a cert. */
rc = ssh_pki_import_cert_blob(blob, &key);
}
ssh_string_free(blob);
if (rc == SSH_ERROR) {
return NULL;
/* get key from blob */
rc = ssh_pki_import_pubkey_blob(blob, &key);
ssh_string_free(blob);
if (rc == SSH_ERROR) {
return NULL;
}
break;
default:
return NULL;
}
return key;
}
int ssh_agent_is_running(ssh_session session) {
int agent_is_running(ssh_session session) {
if (session == NULL || session->agent == NULL) {
return 0;
}
@@ -492,8 +507,8 @@ ssh_string ssh_agent_sign_data(ssh_session session,
ssh_buffer reply;
ssh_string key_blob;
ssh_string sig_blob;
unsigned int type = 0;
unsigned int flags = 0;
int type = SSH2_AGENT_FAILURE;
int flags = 0;
uint32_t dlen;
int rc;
@@ -503,7 +518,7 @@ ssh_string ssh_agent_sign_data(ssh_session session,
}
/* create request */
if (ssh_buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) {
if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) {
ssh_buffer_free(request);
return NULL;
}
@@ -514,23 +529,8 @@ ssh_string ssh_agent_sign_data(ssh_session session,
return NULL;
}
/*
* make sure it already can contain all the expected content:
* - 1 x uint8_t
* - 2 x uint32_t
* - 1 x ssh_string (uint8_t + data)
*/
rc = ssh_buffer_allocate_size(request,
sizeof(uint8_t) * 2 +
sizeof(uint32_t) * 2 +
ssh_string_len(key_blob));
if (rc < 0) {
ssh_buffer_free(request);
return NULL;
}
/* adds len + blob */
rc = ssh_buffer_add_ssh_string(request, key_blob);
rc = buffer_add_ssh_string(request, key_blob);
ssh_string_free(key_blob);
if (rc < 0) {
ssh_buffer_free(request);
@@ -538,17 +538,17 @@ ssh_string ssh_agent_sign_data(ssh_session session,
}
/* Add data */
dlen = ssh_buffer_get_len(data);
if (ssh_buffer_add_u32(request, htonl(dlen)) < 0) {
dlen = buffer_get_rest_len(data);
if (buffer_add_u32(request, htonl(dlen)) < 0) {
ssh_buffer_free(request);
return NULL;
}
if (ssh_buffer_add_data(request, ssh_buffer_get(data), dlen) < 0) {
if (ssh_buffer_add_data(request, buffer_get_rest(data), dlen) < 0) {
ssh_buffer_free(request);
return NULL;
}
if (ssh_buffer_add_u32(request, htonl(flags)) < 0) {
if (buffer_add_u32(request, htonl(flags)) < 0) {
ssh_buffer_free(request);
return NULL;
}
@@ -568,31 +568,27 @@ ssh_string ssh_agent_sign_data(ssh_session session,
ssh_buffer_free(request);
/* check if reply is valid */
if (ssh_buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) {
if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) {
ssh_buffer_free(reply);
return NULL;
}
#ifdef WORDS_BIGENDIAN
type = bswap_32(type);
#endif
if (agent_failed(type)) {
SSH_LOG(SSH_LOG_WARN, "Agent reports failure in signing the key");
ssh_buffer_free(reply);
return NULL;
} else if (type != SSH2_AGENT_SIGN_RESPONSE) {
ssh_set_error(session,
SSH_FATAL,
"Bad authentication response: %u",
type);
ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type);
ssh_buffer_free(reply);
return NULL;
}
sig_blob = ssh_buffer_get_ssh_string(reply);
sig_blob = buffer_get_ssh_string(reply);
ssh_buffer_free(reply);
return sig_blob;
}
#endif /* _WIN32 */
/* vim: set ts=4 sw=4 et cindent: */

747
src/auth.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

229
src/auth1.c Normal file
View File

@@ -0,0 +1,229 @@
/*
* auth1.c - authentication with SSH-1 protocol
*
* This file is part of the SSH Library
*
* Copyright (c) 2005-2008 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include "libssh/priv.h"
#include "libssh/ssh1.h"
#include "libssh/buffer.h"
#include "libssh/packet.h"
#include "libssh/session.h"
#include "libssh/string.h"
#ifdef WITH_SSH1
static int ssh_auth_status_termination(void *s){
ssh_session session=s;
if(session->auth_state != SSH_AUTH_STATE_NONE ||
session->session_state == SSH_SESSION_STATE_ERROR)
return 1;
return 0;
}
static int wait_auth1_status(ssh_session session) {
/* wait for a packet */
if (ssh_handle_packets_termination(session,SSH_TIMEOUT_USER,
ssh_auth_status_termination, session) != SSH_OK){
return SSH_AUTH_ERROR;
}
SSH_LOG(SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state);
switch(session->auth_state) {
case SSH_AUTH_STATE_SUCCESS:
return SSH_AUTH_SUCCESS;
case SSH_AUTH_STATE_FAILED:
return SSH_AUTH_DENIED;
default:
return SSH_AUTH_AGAIN;
}
return SSH_AUTH_ERROR;
}
void ssh_auth1_handler(ssh_session session, uint8_t type){
if(session->session_state != SSH_SESSION_STATE_AUTHENTICATING){
ssh_set_error(session,SSH_FATAL,"SSH_SMSG_SUCCESS or FAILED received in wrong state");
return;
}
if(type==SSH_SMSG_SUCCESS){
session->auth_state=SSH_AUTH_STATE_SUCCESS;
session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
} else if(type==SSH_SMSG_FAILURE)
session->auth_state=SSH_AUTH_STATE_FAILED;
}
static int send_username(ssh_session session, const char *username) {
ssh_string user = NULL;
int rc;
/* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */
if(session->auth_service_state == SSH_AUTH_SERVICE_USER_SENT) {
if(session->auth_state == SSH_AUTH_STATE_FAILED)
return SSH_AUTH_DENIED;
if(session->auth_state == SSH_AUTH_STATE_SUCCESS)
return SSH_AUTH_SUCCESS;
return SSH_AUTH_ERROR;
}
if (session->auth_service_state == SSH_AUTH_SERVICE_SENT)
goto pending;
if (!username) {
if(!(username = session->opts.username)) {
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
session->auth_service_state = SSH_AUTH_SERVICE_DENIED;
return SSH_ERROR;
} else {
username = session->opts.username;
}
}
}
user = ssh_string_from_char(username);
if (user == NULL) {
return SSH_AUTH_ERROR;
}
if (buffer_add_u8(session->out_buffer, SSH_CMSG_USER) < 0) {
ssh_string_free(user);
return SSH_AUTH_ERROR;
}
if (buffer_add_ssh_string(session->out_buffer, user) < 0) {
ssh_string_free(user);
return SSH_AUTH_ERROR;
}
ssh_string_free(user);
session->auth_state=SSH_AUTH_STATE_NONE;
session->auth_service_state = SSH_AUTH_SERVICE_SENT;
if (packet_send(session) == SSH_ERROR) {
return SSH_AUTH_ERROR;
}
pending:
rc = wait_auth1_status(session);
switch (rc){
case SSH_AUTH_SUCCESS:
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
session->auth_state=SSH_AUTH_STATE_SUCCESS;
ssh_set_error(session, SSH_NO_ERROR, "Authentication successful");
return SSH_AUTH_SUCCESS;
case SSH_AUTH_DENIED:
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
ssh_set_error(session,SSH_REQUEST_DENIED,"Password authentication necessary for user %s",username);
return SSH_AUTH_DENIED;
case SSH_AUTH_AGAIN:
return SSH_AUTH_AGAIN;
default:
session->auth_service_state = SSH_AUTH_SERVICE_NONE;
session->auth_state=SSH_AUTH_STATE_ERROR;
return SSH_AUTH_ERROR;
}
}
/* use the "none" authentication question */
int ssh_userauth1_none(ssh_session session, const char *username){
return send_username(session, username);
}
/** \internal
* \todo implement ssh1 public key
*/
int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
int type, ssh_string pubkey) {
(void) session;
(void) username;
(void) type;
(void) pubkey;
return SSH_AUTH_DENIED;
}
int ssh_userauth1_password(ssh_session session, const char *username,
const char *password) {
ssh_string pwd = NULL;
int rc;
rc = send_username(session, username);
if (rc != SSH_AUTH_DENIED) {
return rc;
}
if (session->pending_call_state == SSH_PENDING_CALL_AUTH_PASSWORD)
goto pending;
/* we trick a bit here. A known flaw in SSH1 protocol is that it's
* easy to guess password sizes.
* not that sure ...
*/
/* XXX fix me here ! */
/* cisco IOS doesn't like when a password is followed by zeroes and random pad. */
if(1 || strlen(password) >= 128) {
/* not risky to disclose the size of such a big password .. */
pwd = ssh_string_from_char(password);
if (pwd == NULL) {
return SSH_AUTH_ERROR;
}
} else {
char buf[128] = {0};
/* fill the password string from random things. the strcpy
* ensure there is at least a nul byte after the password.
* most implementation won't see the garbage at end.
* why garbage ? because nul bytes will be compressed by
* gzip and disclose password len.
*/
pwd = ssh_string_new(sizeof(buf));
if (pwd == NULL) {
return SSH_AUTH_ERROR;
}
ssh_get_random(buf, sizeof(buf), 0);
strcpy(buf, password);
ssh_string_fill(pwd, buf, sizeof(buf));
}
if (buffer_add_u8(session->out_buffer, SSH_CMSG_AUTH_PASSWORD) < 0) {
ssh_string_burn(pwd);
ssh_string_free(pwd);
return SSH_AUTH_ERROR;
}
if (buffer_add_ssh_string(session->out_buffer, pwd) < 0) {
ssh_string_burn(pwd);
ssh_string_free(pwd);
return SSH_AUTH_ERROR;
}
ssh_string_burn(pwd);
ssh_string_free(pwd);
session->auth_state=SSH_AUTH_STATE_NONE;
session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
if (packet_send(session) == SSH_ERROR) {
return SSH_AUTH_ERROR;
}
pending:
rc = wait_auth1_status(session);
if (rc != SSH_AUTH_AGAIN)
session->pending_call_state = SSH_PENDING_CALL_NONE;
return rc;
}
#endif /* WITH_SSH1 */
/* vim: set ts=2 sw=2 et cindent: */

View File

@@ -22,9 +22,9 @@
*/
/* just the dirtiest part of code i ever made */
#include "config.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "libssh/priv.h"
#include "libssh/buffer.h"
@@ -288,3 +288,5 @@ unsigned char *bin_to_base64(const unsigned char *source, int len) {
return base64;
}
/* vim: set ts=2 sw=2 et cindent: */

View File

@@ -19,15 +19,13 @@
* MA 02111-1307, USA.
*/
#include "config.h"
#include <stdio.h>
#include "libssh/priv.h"
#include "libssh/bignum.h"
#include "libssh/string.h"
ssh_string ssh_make_bignum_string(bignum num) {
ssh_string make_bignum_string(bignum num) {
ssh_string ptr = NULL;
int pad = 0;
unsigned int len = bignum_num_bytes(num);
@@ -60,14 +58,12 @@ ssh_string ssh_make_bignum_string(bignum num) {
bignum_bn2bin(num, len, ptr->data + pad);
#elif HAVE_LIBCRYPTO
bignum_bn2bin(num, ptr->data + pad);
#elif HAVE_LIBMBEDCRYPTO
bignum_bn2bin(num, ptr->data + pad);
#endif
return ptr;
}
bignum ssh_make_string_bn(ssh_string string){
bignum make_string_bn(ssh_string string){
bignum bn = NULL;
unsigned int len = ssh_string_len(string);
@@ -80,15 +76,12 @@ bignum ssh_make_string_bn(ssh_string string){
bignum_bin2bn(string->data, len, &bn);
#elif defined HAVE_LIBCRYPTO
bn = bignum_bin2bn(string->data, len, NULL);
#elif defined HAVE_LIBMBEDCRYPTO
bn = bignum_new();
bignum_bin2bn(string->data, len, bn);
#endif
return bn;
}
void ssh_make_string_bn_inplace(ssh_string string, bignum bnout) {
void make_string_bn_inplace(ssh_string string, bignum bnout) {
unsigned int len = ssh_string_len(string);
#ifdef HAVE_LIBGCRYPT
/* XXX: FIXME as needed for LIBGCRYPT ECDSA codepaths. */
@@ -96,22 +89,17 @@ void ssh_make_string_bn_inplace(ssh_string string, bignum bnout) {
(void) bnout;
#elif defined HAVE_LIBCRYPTO
bignum_bin2bn(string->data, len, bnout);
#elif defined HAVE_LIBMBEDCRYPTO
bignum_bin2bn(string->data, len, bnout);
#endif
}
/* prints the bignum on stderr */
void ssh_print_bignum(const char *which, const bignum num) {
void ssh_print_bignum(const char *which, bignum num) {
#ifdef HAVE_LIBGCRYPT
unsigned char *hex = NULL;
bignum_bn2hex(num, &hex);
#elif defined HAVE_LIBCRYPTO
char *hex = NULL;
hex = bignum_bn2hex(num);
#elif defined HAVE_LIBMBEDCRYPTO
char *hex = NULL;
hex = bignum_bn2hex(num);
#endif
fprintf(stderr, "%s value: ", which);
fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex);
@@ -119,7 +107,5 @@ void ssh_print_bignum(const char *which, const bignum num) {
SAFE_FREE(hex);
#elif defined HAVE_LIBCRYPTO
OPENSSL_free(hex);
#elif defined HAVE_LIBMBEDCRYPTO
SAFE_FREE(hex);
#endif
}

View File

@@ -149,10 +149,9 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
if (sshbind->ecdsakey == NULL &&
sshbind->dsakey == NULL &&
sshbind->rsakey == NULL &&
sshbind->ed25519key == NULL) {
sshbind->rsakey == NULL) {
ssh_set_error(sshbind, SSH_FATAL,
"ECDSA, ED25519, DSA, or RSA host key file must be set");
"ECDSA, DSA, or RSA host key file must be set");
return SSH_ERROR;
}
@@ -179,7 +178,6 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
}
#endif
#ifdef HAVE_DSA
if (sshbind->dsa == NULL && sshbind->dsakey != NULL) {
rc = ssh_pki_import_privkey_file(sshbind->dsakey,
NULL,
@@ -201,7 +199,6 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
return SSH_ERROR;
}
}
#endif
if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
rc = ssh_pki_import_privkey_file(sshbind->rsakey,
@@ -215,7 +212,8 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
return SSH_ERROR;
}
if (ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA) {
if (ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA &&
ssh_key_type(sshbind->rsa) != SSH_KEYTYPE_RSA1) {
ssh_set_error(sshbind, SSH_FATAL,
"The RSA host key has the wrong type");
ssh_key_free(sshbind->rsa);
@@ -224,27 +222,6 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
}
}
if (sshbind->ed25519 == NULL && sshbind->ed25519key != NULL) {
rc = ssh_pki_import_privkey_file(sshbind->ed25519key,
NULL,
NULL,
NULL,
&sshbind->ed25519);
if (rc == SSH_ERROR || rc == SSH_EOF) {
ssh_set_error(sshbind, SSH_FATAL,
"Failed to import private ED25519 host key");
return SSH_ERROR;
}
if (ssh_key_type(sshbind->ed25519) != SSH_KEYTYPE_ED25519) {
ssh_set_error(sshbind, SSH_FATAL,
"The ED25519 host key has the wrong type");
ssh_key_free(sshbind->ed25519);
sshbind->ed25519 = NULL;
return SSH_ERROR;
}
}
return SSH_OK;
}
@@ -253,14 +230,14 @@ int ssh_bind_listen(ssh_bind sshbind) {
socket_t fd;
int rc;
if (sshbind->rsa == NULL &&
sshbind->dsa == NULL &&
sshbind->ecdsa == NULL &&
sshbind->ed25519 == NULL) {
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
}
if (ssh_init() < 0) {
ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
return -1;
}
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
}
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
@@ -275,7 +252,6 @@ int ssh_bind_listen(ssh_bind sshbind) {
sshbind->dsa = NULL;
ssh_key_free(sshbind->rsa);
sshbind->rsa = NULL;
/* XXX should this clear also other structures that were allocated */
return -1;
}
@@ -288,7 +264,6 @@ int ssh_bind_listen(ssh_bind sshbind) {
sshbind->dsa = NULL;
ssh_key_free(sshbind->rsa);
sshbind->rsa = NULL;
/* XXX should this clear also other structures that were allocated */
return -1;
}
@@ -415,6 +390,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
}
session->server = 1;
session->version = 2;
/* copy options */
for (i = 0; i < 10; i++) {
@@ -454,14 +430,9 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
* where keys can be imported) on this ssh_bind and are instead
* only using ssh_bind_accept_fd to manage sockets ourselves.
*/
if (sshbind->rsa == NULL &&
sshbind->dsa == NULL &&
sshbind->ecdsa == NULL &&
sshbind->ed25519 == NULL) {
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
}
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
}
#ifdef HAVE_ECC
@@ -473,7 +444,6 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
}
}
#endif
#ifdef HAVE_DSA
if (sshbind->dsa) {
session->srv.dsa_key = ssh_key_dup(sshbind->dsa);
if (session->srv.dsa_key == NULL) {
@@ -481,7 +451,6 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
return SSH_ERROR;
}
}
#endif
if (sshbind->rsa) {
session->srv.rsa_key = ssh_key_dup(sshbind->rsa);
if (session->srv.rsa_key == NULL) {

View File

@@ -21,9 +21,9 @@
* MA 02111-1307, USA.
*/
#include "config.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#ifndef _WIN32
@@ -84,12 +84,12 @@ static void buffer_verify(ssh_buffer buf){
* @return A newly initialized SSH buffer, NULL on error.
*/
struct ssh_buffer_struct *ssh_buffer_new(void) {
struct ssh_buffer_struct *buf =
calloc(1, sizeof(struct ssh_buffer_struct));
struct ssh_buffer_struct *buf = malloc(sizeof(struct ssh_buffer_struct));
if (buf == NULL) {
return NULL;
}
memset(buf, 0, sizeof(struct ssh_buffer_struct));
buffer_verify(buf);
return buf;
}
@@ -107,10 +107,10 @@ void ssh_buffer_free(struct ssh_buffer_struct *buffer) {
if (buffer->data) {
/* burn the data */
explicit_bzero(buffer->data, buffer->allocated);
BURN_BUFFER(buffer->data, buffer->allocated);
SAFE_FREE(buffer->data);
}
explicit_bzero(buffer, sizeof(struct ssh_buffer_struct));
BURN_BUFFER(buffer, sizeof(struct ssh_buffer_struct));
SAFE_FREE(buffer);
}
@@ -127,40 +127,38 @@ void ssh_buffer_set_secure(ssh_buffer buffer){
}
static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed) {
size_t smallest = 1;
char *new;
size_t smallest = 1;
char *new;
buffer_verify(buffer);
buffer_verify(buffer);
/* Find the smallest power of two which is greater or equal to needed */
while(smallest <= needed) {
if (smallest == 0) {
return -1;
}
smallest <<= 1;
}
needed = smallest;
if (buffer->secure){
new = malloc(needed);
if (new == NULL) {
return -1;
}
if (buffer->used > 0) {
memcpy(new, buffer->data,buffer->used);
explicit_bzero(buffer->data, buffer->used);
SAFE_FREE(buffer->data);
}
} else {
new = realloc(buffer->data, needed);
if (new == NULL) {
buffer->data = NULL;
return -1;
}
}
buffer->data = new;
buffer->allocated = needed;
buffer_verify(buffer);
return 0;
/* Find the smallest power of two which is greater or equal to needed */
while(smallest <= needed) {
if (smallest == 0) {
return -1;
}
smallest <<= 1;
}
needed = smallest;
if (buffer->secure){
new = malloc(needed);
if (new == NULL) {
return -1;
}
memcpy(new, buffer->data,buffer->used);
BURN_BUFFER(buffer->data, buffer->used);
SAFE_FREE(buffer->data);
} else {
new = realloc(buffer->data, needed);
if (new == NULL) {
buffer->data = NULL;
return -1;
}
}
buffer->data = new;
buffer->allocated = needed;
buffer_verify(buffer);
return 0;
}
/** @internal
@@ -179,13 +177,15 @@ static void buffer_shift(ssh_buffer buffer){
if (buffer->secure){
void *ptr = buffer->data + buffer->used;
explicit_bzero(ptr, burn_pos);
BURN_BUFFER(ptr, burn_pos);
}
buffer_verify(buffer);
}
/**
* @internal
*
* @brief Reinitialize a SSH buffer.
*
* @param[in] buffer The buffer to reinitialize.
@@ -194,24 +194,22 @@ static void buffer_shift(ssh_buffer buffer){
*/
int ssh_buffer_reinit(struct ssh_buffer_struct *buffer)
{
buffer_verify(buffer);
if (buffer->used > 0) {
explicit_bzero(buffer->data, buffer->used);
buffer_verify(buffer);
BURN_BUFFER(buffer->data, buffer->used);
buffer->used = 0;
buffer->pos = 0;
if(buffer->allocated > 127) {
if (realloc_buffer(buffer, 127) < 0) {
return -1;
}
buffer->used = 0;
buffer->pos = 0;
if (buffer->allocated > 127) {
if (realloc_buffer(buffer, 127) < 0) {
return -1;
}
}
buffer_verify(buffer);
return 0;
}
buffer_verify(buffer);
return 0;
}
/**
* @internal
*
* @brief Add data at the tail of a buffer.
*
* @param[in] buffer The buffer to add the data.
@@ -248,72 +246,6 @@ int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint
return 0;
}
/**
* @brief Ensure the buffer has at least a certain preallocated size.
*
* @param[in] buffer The buffer to enlarge.
*
* @param[in] len The length to ensure as allocated.
*
* @return 0 on success, < 0 on error.
*/
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer,
uint32_t len)
{
buffer_verify(buffer);
if (buffer->allocated < len) {
if (buffer->pos > 0) {
buffer_shift(buffer);
}
if (realloc_buffer(buffer, len) < 0) {
return -1;
}
}
buffer_verify(buffer);
return 0;
}
/**
* @internal
*
* @brief Allocate space for data at the tail of a buffer.
*
* @param[in] buffer The buffer to add the data.
*
* @param[in] len The length of the data to add.
*
* @return Pointer on the allocated space
* NULL on error.
*/
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
{
void *ptr;
buffer_verify(buffer);
if (buffer->used + len < len) {
return NULL;
}
if (buffer->allocated < (buffer->used + len)) {
if (buffer->pos > 0) {
buffer_shift(buffer);
}
if (realloc_buffer(buffer, buffer->used + len) < 0) {
return NULL;
}
}
ptr = buffer->data + buffer->used;
buffer->used+=len;
buffer_verify(buffer);
return ptr;
}
/**
* @internal
*
@@ -325,7 +257,7 @@ void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
*
* @return 0 on success, < 0 on error.
*/
int ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
int buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
struct ssh_string_struct *string) {
uint32_t len = 0;
@@ -352,7 +284,7 @@ int ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
*
* @return 0 on success, -1 on error.
*/
int ssh_buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data)
int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data)
{
int rc;
@@ -375,7 +307,7 @@ int ssh_buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data)
*
* @return 0 on success, -1 on error.
*/
int ssh_buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
{
int rc;
@@ -398,7 +330,7 @@ int ssh_buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data)
*
* @return 0 on success, -1 on error.
*/
int ssh_buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data)
int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data)
{
int rc;
@@ -421,7 +353,7 @@ int ssh_buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data)
*
* @return 0 on success, -1 on error.
*/
int ssh_buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data)
int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data)
{
int rc;
@@ -446,7 +378,7 @@ int ssh_buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data)
*
* @return 0 on success, -1 on error.
*/
int ssh_buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
uint32_t len) {
buffer_verify(buffer);
@@ -487,14 +419,14 @@ int ssh_buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data,
*
* @return 0 on success, -1 on error.
*/
int ssh_buffer_add_buffer(struct ssh_buffer_struct *buffer,
int buffer_add_buffer(struct ssh_buffer_struct *buffer,
struct ssh_buffer_struct *source)
{
int rc;
rc = ssh_buffer_add_data(buffer,
ssh_buffer_get(source),
ssh_buffer_get_len(source));
buffer_get_rest(source),
buffer_get_rest_len(source));
if (rc < 0) {
return -1;
}
@@ -503,28 +435,63 @@ int ssh_buffer_add_buffer(struct ssh_buffer_struct *buffer,
}
/**
* @brief Get a pointer on the head of a buffer.
*
* @param[in] buffer The buffer to get the head pointer.
*
* @return A data pointer on the head. It doesn't take the position
* into account.
*
* @warning Don't expect data to be nul-terminated.
*
* @see buffer_get_rest()
* @see buffer_get_len()
*/
void *ssh_buffer_get_begin(struct ssh_buffer_struct *buffer){
return buffer->data;
}
/**
* @internal
*
* @brief Get a pointer to the head of a buffer at the current position.
*
* @param[in] buffer The buffer to get the head pointer.
*
* @return A pointer to the data from current position.
*
* @see ssh_buffer_get_len()
* @see buffer_get_rest_len()
* @see buffer_get()
*/
void *ssh_buffer_get(struct ssh_buffer_struct *buffer){
void *buffer_get_rest(struct ssh_buffer_struct *buffer){
return buffer->data + buffer->pos;
}
/**
* @brief Get the length of the buffer, not counting position.
*
* @param[in] buffer The buffer to get the length from.
*
* @return The length of the buffer.
*
* @see buffer_get()
*/
uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
return buffer->used;
}
/**
* @internal
*
* @brief Get the length of the buffer from the current position.
*
* @param[in] buffer The buffer to get the length from.
*
* @return The length of the buffer.
*
* @see ssh_buffer_get()
* @see buffer_get_rest()
*/
uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
uint32_t buffer_get_rest_len(struct ssh_buffer_struct *buffer){
buffer_verify(buffer);
return buffer->used - buffer->pos;
}
@@ -542,7 +509,7 @@ uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
*
* @return The new size of the buffer.
*/
uint32_t ssh_buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
uint32_t buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer);
if (buffer->pos + len < len || buffer->used < buffer->pos + len) {
@@ -570,7 +537,7 @@ uint32_t ssh_buffer_pass_bytes(struct ssh_buffer_struct *buffer, uint32_t len){
*
* @return The new size of the buffer.
*/
uint32_t ssh_buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){
buffer_verify(buffer);
if (buffer->used < len) {
@@ -583,6 +550,8 @@ uint32_t ssh_buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t le
}
/**
* @internal
*
* @brief Get the remaining data out of the buffer and adjust the read pointer.
*
* @param[in] buffer The buffer to read.
@@ -593,17 +562,13 @@ uint32_t ssh_buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t le
*
* @returns 0 if there is not enough data in buffer, len otherwise.
*/
uint32_t ssh_buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len)
{
int rc;
uint32_t buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len){
/*
* Check for a integer overflow first, then check if not enough data is in
* the buffer.
*/
rc = ssh_buffer_validate_length(buffer, len);
if (rc != SSH_OK) {
return 0;
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
return 0;
}
memcpy(data,buffer->data+buffer->pos,len);
buffer->pos+=len;
@@ -618,27 +583,23 @@ uint32_t ssh_buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint3
*
* @param[in] buffer The buffer to read.
*
* @param[in] data A pointer to a uint8_t where to store the data.
* @param[in] data A pointer to a uint8_t where to store the data.
*
* @returns 0 if there is not enough data in buffer, 1 otherwise.
*/
int ssh_buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
return ssh_buffer_get_data(buffer,data,sizeof(uint8_t));
int buffer_get_u8(struct ssh_buffer_struct *buffer, uint8_t *data){
return buffer_get_data(buffer,data,sizeof(uint8_t));
}
/**
* @internal
*
* @brief gets a 32 bits unsigned int out of the buffer. Adjusts the read pointer.
*
* @param[in] buffer The buffer to read.
*
* @param[in] data A pointer to a uint32_t where to store the data.
*
* @returns 0 if there is not enough data in buffer, 4 otherwise.
/** \internal
* \brief gets a 32 bits unsigned int out of the buffer. Adjusts the read pointer.
* \param buffer Buffer to read
* \param data pointer to a uint32_t where to store the data
* \returns 0 if there is not enough data in buffer
* \returns 4 otherwise.
*/
int ssh_buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
return ssh_buffer_get_data(buffer,data,sizeof(uint32_t));
int buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
return buffer_get_data(buffer,data,sizeof(uint32_t));
}
/**
* @internal
@@ -652,26 +613,8 @@ int ssh_buffer_get_u32(struct ssh_buffer_struct *buffer, uint32_t *data){
*
* @returns 0 if there is not enough data in buffer, 8 otherwise.
*/
int ssh_buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
return ssh_buffer_get_data(buffer,data,sizeof(uint64_t));
}
/**
* @brief Valdiates that the given length can be obtained from the buffer.
*
* @param[in] buffer The buffer to read from.
*
* @param[in] len The length to be checked.
*
* @return SSH_OK if the length is valid, SSH_ERROR otherwise.
*/
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len)
{
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
return SSH_ERROR;
}
return SSH_OK;
int buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){
return buffer_get_data(buffer,data,sizeof(uint64_t));
}
/**
@@ -683,26 +626,24 @@ int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len)
*
* @returns The SSH String, NULL on error.
*/
struct ssh_string_struct *ssh_buffer_get_ssh_string(struct ssh_buffer_struct *buffer) {
struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer) {
uint32_t stringlen;
uint32_t hostlen;
struct ssh_string_struct *str = NULL;
int rc;
if (ssh_buffer_get_u32(buffer, &stringlen) == 0) {
if (buffer_get_u32(buffer, &stringlen) == 0) {
return NULL;
}
hostlen = ntohl(stringlen);
/* verify if there is enough space in buffer to get it */
rc = ssh_buffer_validate_length(buffer, hostlen);
if (rc != SSH_OK) {
if (buffer->pos + hostlen < hostlen || buffer->pos + hostlen > buffer->used) {
return NULL; /* it is indeed */
}
str = ssh_string_new(hostlen);
if (str == NULL) {
return NULL;
}
if (ssh_buffer_get_data(buffer, ssh_string_data(str), hostlen) != hostlen) {
if (buffer_get_data(buffer, ssh_string_data(str), hostlen) != hostlen) {
/* should never happen */
SAFE_FREE(str);
return NULL;
@@ -711,6 +652,41 @@ struct ssh_string_struct *ssh_buffer_get_ssh_string(struct ssh_buffer_struct *bu
return str;
}
/**
* @internal
*
* @brief Get a mpint out of the buffer and adjusts the read pointer.
*
* @note This function is SSH-1 only.
*
* @param[in] buffer The buffer to read.
*
* @returns The SSH String containing the mpint, NULL on error.
*/
struct ssh_string_struct *buffer_get_mpint(struct ssh_buffer_struct *buffer) {
uint16_t bits;
uint32_t len;
struct ssh_string_struct *str = NULL;
if (buffer_get_data(buffer, &bits, sizeof(uint16_t)) != sizeof(uint16_t)) {
return NULL;
}
bits = ntohs(bits);
len = (bits + 7) / 8;
if (buffer->pos + len < len || buffer->pos + len > buffer->used) {
return NULL;
}
str = ssh_string_new(len);
if (str == NULL) {
return NULL;
}
if (buffer_get_data(buffer, ssh_string_data(str), len) != len) {
SAFE_FREE(str);
return NULL;
}
return str;
}
/** @internal
* @brief Add multiple values in a buffer on a single function call
* @param[in] buffer The buffer to add to
@@ -749,32 +725,32 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
switch(*p) {
case 'b':
o.byte = (uint8_t)va_arg(ap, unsigned int);
rc = ssh_buffer_add_u8(buffer, o.byte);
rc = buffer_add_u8(buffer, o.byte);
break;
case 'w':
o.word = (uint16_t)va_arg(ap, unsigned int);
o.word = htons(o.word);
rc = ssh_buffer_add_u16(buffer, o.word);
rc = buffer_add_u16(buffer, o.word);
break;
case 'd':
o.dword = va_arg(ap, uint32_t);
o.dword = htonl(o.dword);
rc = ssh_buffer_add_u32(buffer, o.dword);
rc = buffer_add_u32(buffer, o.dword);
break;
case 'q':
o.qword = va_arg(ap, uint64_t);
o.qword = htonll(o.qword);
rc = ssh_buffer_add_u64(buffer, o.qword);
rc = buffer_add_u64(buffer, o.qword);
break;
case 'S':
o.string = va_arg(ap, ssh_string);
rc = ssh_buffer_add_ssh_string(buffer, o.string);
rc = buffer_add_ssh_string(buffer, o.string);
o.string = NULL;
break;
case 's':
cstring = va_arg(ap, char *);
len = strlen(cstring);
rc = ssh_buffer_add_u32(buffer, htonl(len));
rc = buffer_add_u32(buffer, htonl(len));
if (rc == SSH_OK){
rc = ssh_buffer_add_data(buffer, cstring, len);
}
@@ -791,12 +767,12 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
break;
case 'B':
b = va_arg(ap, bignum);
o.string = ssh_make_bignum_string(b);
o.string = make_bignum_string(b);
if(o.string == NULL){
rc = SSH_ERROR;
break;
}
rc = ssh_buffer_add_ssh_string(buffer, o.string);
rc = buffer_add_ssh_string(buffer, o.string);
SAFE_FREE(o.string);
break;
case 't':
@@ -891,12 +867,11 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
char **cstring;
void **data;
} o;
size_t len, rlen, max_len;
size_t len, rlen;
uint32_t u32len;
va_list ap_copy;
int count;
max_len = ssh_buffer_get_len(buffer);
/* copy the argument list in case a rollback is needed */
va_copy(ap_copy, ap);
@@ -910,60 +885,52 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
switch (*p) {
case 'b':
o.byte = va_arg(ap, uint8_t *);
rlen = ssh_buffer_get_u8(buffer, o.byte);
rlen = buffer_get_u8(buffer, o.byte);
rc = rlen==1 ? SSH_OK : SSH_ERROR;
break;
case 'w':
o.word = va_arg(ap, uint16_t *);
rlen = ssh_buffer_get_data(buffer, o.word, sizeof(uint16_t));
rlen = buffer_get_data(buffer, o.word, sizeof(uint16_t));
*o.word = ntohs(*o.word);
rc = rlen==2 ? SSH_OK : SSH_ERROR;
break;
case 'd':
o.dword = va_arg(ap, uint32_t *);
rlen = ssh_buffer_get_u32(buffer, o.dword);
rlen = buffer_get_u32(buffer, o.dword);
*o.dword = ntohl(*o.dword);
rc = rlen==4 ? SSH_OK : SSH_ERROR;
break;
case 'q':
o.qword = va_arg(ap, uint64_t*);
rlen = ssh_buffer_get_u64(buffer, o.qword);
rlen = buffer_get_u64(buffer, o.qword);
*o.qword = ntohll(*o.qword);
rc = rlen==8 ? SSH_OK : SSH_ERROR;
break;
case 'S':
o.string = va_arg(ap, ssh_string *);
*o.string = ssh_buffer_get_ssh_string(buffer);
*o.string = buffer_get_ssh_string(buffer);
rc = *o.string != NULL ? SSH_OK : SSH_ERROR;
o.string = NULL;
break;
case 's': {
uint32_t u32len = 0;
case 's':
o.cstring = va_arg(ap, char **);
*o.cstring = NULL;
rc = ssh_buffer_get_u32(buffer, &u32len);
rc = buffer_get_u32(buffer, &u32len);
if (rc != 4){
rc = SSH_ERROR;
break;
}
len = ntohl(u32len);
if (len > max_len - 1) {
if (len > UINT_MAX - 1){
rc = SSH_ERROR;
break;
}
rc = ssh_buffer_validate_length(buffer, len);
if (rc != SSH_OK) {
break;
}
*o.cstring = malloc(len + 1);
if (*o.cstring == NULL){
rc = SSH_ERROR;
break;
}
rlen = ssh_buffer_get_data(buffer, *o.cstring, len);
rlen = buffer_get_data(buffer, *o.cstring, len);
if (rlen != len){
SAFE_FREE(*o.cstring);
rc = SSH_ERROR;
@@ -973,18 +940,8 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
o.cstring = NULL;
rc = SSH_OK;
break;
}
case 'P':
len = va_arg(ap, size_t);
if (len > max_len - 1) {
rc = SSH_ERROR;
break;
}
rc = ssh_buffer_validate_length(buffer, len);
if (rc != SSH_OK) {
break;
}
o.data = va_arg(ap, void **);
count++;
@@ -994,7 +951,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
rc = SSH_ERROR;
break;
}
rlen = ssh_buffer_get_data(buffer, *o.data, len);
rlen = buffer_get_data(buffer, *o.data, len);
if (rlen != len){
SAFE_FREE(*o.data);
rc = SSH_ERROR;
@@ -1096,3 +1053,5 @@ int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
}
/** @} */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -25,10 +25,7 @@
#include "libssh/callbacks.h"
#include "libssh/session.h"
#include "libssh/misc.h"
#define is_callback_valid(session, cb) \
(cb->size <= 0 || cb->size > 1024 * sizeof(void *))
/* LEGACY */
static void ssh_legacy_log_callback(int priority,
@@ -50,12 +47,12 @@ int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
return SSH_ERROR;
}
if (is_callback_valid(session, cb)) {
ssh_set_error(session,
SSH_FATAL,
"Invalid callback passed in (badly initialized)");
return SSH_ERROR;
};
if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){
ssh_set_error(session,SSH_FATAL,
"Invalid callback passed in (badly initialized)");
return SSH_ERROR;
}
session->common.callbacks = cb;
/* LEGACY */
@@ -67,80 +64,35 @@ int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
return 0;
}
static int ssh_add_set_channel_callbacks(ssh_channel channel,
ssh_channel_callbacks cb,
int prepend)
{
ssh_session session = NULL;
int rc;
int ssh_set_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb) {
ssh_session session = NULL;
if (channel == NULL || cb == NULL) {
return SSH_ERROR;
}
session = channel->session;
if (channel == NULL || cb == NULL) {
return SSH_ERROR;
}
session = channel->session;
if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){
ssh_set_error(session,SSH_FATAL,
"Invalid channel callback passed in (badly initialized)");
if (is_callback_valid(session, cb)) {
ssh_set_error(session,
SSH_FATAL,
"Invalid callback passed in (badly initialized)");
return SSH_ERROR;
};
if (channel->callbacks == NULL) {
channel->callbacks = ssh_list_new();
if (channel->callbacks == NULL){
ssh_set_error_oom(session);
return SSH_ERROR;
}
}
if (prepend) {
rc = ssh_list_prepend(channel->callbacks, cb);
} else {
rc = ssh_list_append(channel->callbacks, cb);
}
return SSH_ERROR;
}
channel->callbacks = cb;
return rc;
return 0;
}
int ssh_set_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
{
return ssh_add_set_channel_callbacks(channel, cb, 1);
}
int ssh_add_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
{
return ssh_add_set_channel_callbacks(channel, cb, 0);
}
int ssh_remove_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
{
struct ssh_iterator *it;
if (channel == NULL || channel->callbacks == NULL){
return SSH_ERROR;
}
it = ssh_list_find(channel->callbacks, cb);
if (it == NULL){
return SSH_ERROR;
}
ssh_list_remove(channel->callbacks, it);
return SSH_OK;
}
int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb){
if (session == NULL || cb == NULL) {
return SSH_ERROR;
}
if (is_callback_valid(session, cb)) {
ssh_set_error(session,
SSH_FATAL,
"Invalid callback passed in (badly initialized)");
return SSH_ERROR;
};
if(cb->size <= 0 || cb->size > 1024 * sizeof(void *)){
ssh_set_error(session,SSH_FATAL,
"Invalid callback passed in (badly initialized)");
return SSH_ERROR;
}
session->server_callbacks = cb;
return 0;

View File

@@ -1,212 +0,0 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2015 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/libssh.h"
#include "libssh/crypto.h"
#include "libssh/chacha.h"
#include "libssh/poly1305.h"
#include "libssh/misc.h"
/* size of the keys k1 and k2 as defined in specs */
#define CHACHA20_KEYLEN 32
struct chacha20_poly1305_keysched {
/* key used for encrypting the length field*/
struct chacha_ctx k1;
/* key used for encrypting the packets */
struct chacha_ctx k2;
};
#pragma pack(push, 1)
struct ssh_packet_header {
uint32_t length;
uint8_t payload[];
};
#pragma pack(pop)
static const uint8_t zero_block_counter[8] = {0, 0, 0, 0, 0, 0, 0, 0};
static const uint8_t payload_block_counter[8] = {1, 0, 0, 0, 0, 0, 0, 0};
static int chacha20_set_encrypt_key(struct ssh_cipher_struct *cipher,
void *key,
void *IV)
{
struct chacha20_poly1305_keysched *sched;
uint8_t *u8key = key;
(void)IV;
if (cipher->chacha20_schedule == NULL) {
sched = malloc(sizeof *sched);
if (sched == NULL){
return -1;
}
} else {
sched = cipher->chacha20_schedule;
}
chacha_keysetup(&sched->k2, u8key, CHACHA20_KEYLEN * 8);
chacha_keysetup(&sched->k1, u8key + CHACHA20_KEYLEN, CHACHA20_KEYLEN * 8);
cipher->chacha20_schedule = sched;
return 0;
}
/**
* @internal
*
* @brief encrypts an outgoing packet with chacha20 and authenticate it
* with poly1305.
*/
static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
void *in,
void *out,
size_t len,
uint8_t *tag,
uint64_t seq)
{
struct ssh_packet_header *in_packet = in, *out_packet = out;
uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0};
struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
seq = htonll(seq);
/* step 1, prepare the poly1305 key */
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter);
chacha_encrypt_bytes(&keys->k2,
poly1305_ctx,
poly1305_ctx,
POLY1305_KEYLEN);
/* step 2, encrypt length field */
chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter);
chacha_encrypt_bytes(&keys->k1,
(uint8_t *)&in_packet->length,
(uint8_t *)&out_packet->length,
sizeof(uint32_t));
/* step 3, encrypt packet payload */
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter);
chacha_encrypt_bytes(&keys->k2,
in_packet->payload,
out_packet->payload,
len - sizeof(uint32_t));
/* ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */
/* step 4, compute the MAC */
poly1305_auth(tag, (uint8_t *)out_packet, len, poly1305_ctx);
/* ssh_print_hexa("poly1305 src", (uint8_t *)out_packet, len);
ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN); */
}
static int chacha20_poly1305_aead_decrypt_length(
struct ssh_cipher_struct *cipher,
void *in,
uint8_t *out,
size_t len,
uint64_t seq)
{
struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
if (len < sizeof(uint32_t)) {
return SSH_ERROR;
}
seq = htonll(seq);
chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter);
chacha_encrypt_bytes(&keys->k1,
in,
(uint8_t *)out,
sizeof(uint32_t));
return SSH_OK;
}
static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
void *complete_packet,
uint8_t *out,
size_t encrypted_size,
uint64_t seq)
{
uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0};
uint8_t tag[POLY1305_TAGLEN] = {0};
struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
uint8_t *mac = (uint8_t *)complete_packet + sizeof(uint32_t) + encrypted_size;
int cmp;
seq = htonll(seq);
ZERO_STRUCT(poly1305_ctx);
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter);
chacha_encrypt_bytes(&keys->k2,
poly1305_ctx,
poly1305_ctx,
POLY1305_KEYLEN);
#if 0
ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx));
#endif
poly1305_auth(tag, (uint8_t *)complete_packet, encrypted_size +
sizeof(uint32_t), poly1305_ctx);
#if 0
ssh_print_hexa("poly1305 src",
(uint8_t*)complete_packet,
encrypted_size + 4);
ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN);
ssh_print_hexa("received tag", mac, POLY1305_TAGLEN);
#endif
cmp = memcmp(tag, mac, POLY1305_TAGLEN);
if(cmp != 0) {
/* mac error */
SSH_LOG(SSH_LOG_PACKET,"poly1305 verify error");
return SSH_ERROR;
}
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter);
chacha_encrypt_bytes(&keys->k2,
(uint8_t *)complete_packet + sizeof(uint32_t),
out,
encrypted_size);
return SSH_OK;
}
static void chacha20_cleanup(struct ssh_cipher_struct *cipher) {
SAFE_FREE(cipher->chacha20_schedule);
}
const struct ssh_cipher_struct chacha20poly1305_cipher = {
.name = "chacha20-poly1305@openssh.com",
.blocksize = 8,
.lenfield_blocksize = 4,
.keylen = sizeof(struct chacha20_poly1305_keysched),
.keysize = 512,
.tag_size = POLY1305_TAGLEN,
.set_encrypt_key = chacha20_set_encrypt_key,
.set_decrypt_key = chacha20_set_encrypt_key,
.aead_encrypt = chacha20_poly1305_aead_encrypt,
.aead_decrypt_length = chacha20_poly1305_aead_decrypt_length,
.aead_decrypt = chacha20_poly1305_aead_decrypt,
.cleanup = chacha20_cleanup
};
const struct ssh_cipher_struct *ssh_get_chacha20poly1305_cipher(void)
{
return &chacha20poly1305_cipher;
}

View File

@@ -22,9 +22,9 @@
* MA 02111-1307, USA.
*/
#include "config.h"
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
@@ -106,6 +106,7 @@ ssh_channel ssh_channel_new(ssh_session session) {
}
channel->session = session;
channel->version = session->version;
channel->exit_status = -1;
channel->flags = SSH_CHANNEL_FLAG_NOT_BOUND;
@@ -285,14 +286,14 @@ static int channel_open(ssh_channel channel, const char *type, int window,
}
if (payload != NULL) {
if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) {
if (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) {
if (packet_send(session) == SSH_ERROR) {
return err;
}
@@ -345,6 +346,13 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize
uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE;
int rc;
#ifdef WITH_SSH1
if (session->version == 1){
channel->remote_window = new_window;
return SSH_OK;
}
#endif
if(new_window <= channel->local_window){
SSH_LOG(SSH_LOG_PROTOCOL,
"growing window (channel %d:%d) to %d bytes : not needed (%d bytes)",
@@ -366,7 +374,7 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize
goto error;
}
if (ssh_packet_send(session) == SSH_ERROR) {
if (packet_send(session) == SSH_ERROR) {
goto error;
}
@@ -390,6 +398,8 @@ error:
*
* @brief Parse a channel-related packet to resolve it to a ssh_channel.
*
* This works on SSH1 sessions too.
*
* @param[in] session The current SSH session.
*
* @param[in] packet The buffer to parse packet from. The read pointer will
@@ -402,7 +412,11 @@ static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
ssh_channel channel;
uint32_t chan;
int rc;
#ifdef WITH_SSH1
/* With SSH1, the channel is always the first one */
if(session->version==1)
return ssh_get_channel1(session);
#endif
rc = ssh_buffer_unpack(packet,"d",&chan);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL,
@@ -478,10 +492,10 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
if (is_stderr) {
uint32_t ignore;
/* uint32 data type code. we can ignore it */
ssh_buffer_get_u32(packet, &ignore);
buffer_get_u32(packet, &ignore);
}
str = ssh_buffer_get_ssh_string(packet);
str = buffer_get_ssh_string(packet);
if (str == NULL) {
SSH_LOG(SSH_LOG_PACKET, "Invalid data packet!");
@@ -524,38 +538,31 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
ssh_string_free(str);
if (is_stderr) {
buf = channel->stderr_buffer;
} else {
buf = channel->stdout_buffer;
}
ssh_callbacks_iterate(channel->callbacks,
ssh_channel_callbacks,
channel_data_function) {
if (ssh_buffer_get(buf) == NULL) {
break;
if(ssh_callbacks_exists(channel->callbacks, channel_data_function)) {
if(is_stderr) {
buf = channel->stderr_buffer;
} else {
buf = channel->stdout_buffer;
}
rest = ssh_callbacks_iterate_exec(channel_data_function,
channel->session,
channel,
ssh_buffer_get(buf),
ssh_buffer_get_len(buf),
is_stderr);
if (rest > 0) {
if (channel->counter != NULL) {
channel->counter->in_bytes += rest;
}
ssh_buffer_pass_bytes(buf, rest);
rest = channel->callbacks->channel_data_function(channel->session,
channel,
buffer_get_rest(buf),
buffer_get_rest_len(buf),
is_stderr,
channel->callbacks->userdata);
if(rest > 0) {
if (channel->counter != NULL) {
channel->counter->in_bytes += rest;
}
buffer_pass_bytes(buf, rest);
}
}
ssh_callbacks_iterate_end();
if (channel->local_window + ssh_buffer_get_len(buf) < WINDOWLIMIT) {
if (grow_window(session, channel, 0) < 0) {
if (channel->local_window + buffer_get_rest_len(buf) < WINDOWLIMIT) {
if (grow_window(session, channel, 0) < 0) {
return -1;
}
}
}
return SSH_PACKET_USED;
}
@@ -578,11 +585,11 @@ SSH_PACKET_CALLBACK(channel_rcv_eof) {
/* channel->remote_window = 0; */
channel->remote_eof = 1;
ssh_callbacks_execute_list(channel->callbacks,
ssh_channel_callbacks,
channel_eof_function,
channel->session,
channel);
if(ssh_callbacks_exists(channel->callbacks, channel_eof_function)) {
channel->callbacks->channel_eof_function(channel->session,
channel,
channel->callbacks->userdata);
}
return SSH_PACKET_USED;
}
@@ -605,9 +612,9 @@ SSH_PACKET_CALLBACK(channel_rcv_close) {
channel->remote_channel);
if ((channel->stdout_buffer &&
ssh_buffer_get_len(channel->stdout_buffer) > 0) ||
buffer_get_rest_len(channel->stdout_buffer) > 0) ||
(channel->stderr_buffer &&
ssh_buffer_get_len(channel->stderr_buffer) > 0)) {
buffer_get_rest_len(channel->stderr_buffer) > 0)) {
channel->delayed_close = 1;
} else {
channel->state = SSH_CHANNEL_STATE_CLOSED;
@@ -622,12 +629,11 @@ SSH_PACKET_CALLBACK(channel_rcv_close) {
* buffer because the eof is ignored until the buffer is empty.
*/
ssh_callbacks_execute_list(channel->callbacks,
ssh_channel_callbacks,
channel_close_function,
channel->session,
channel);
if(ssh_callbacks_exists(channel->callbacks, channel_close_function)) {
channel->callbacks->channel_close_function(channel->session,
channel,
channel->callbacks->userdata);
}
channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE;
if(channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL)
ssh_channel_do_free(channel);
@@ -662,12 +668,12 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
rc = ssh_buffer_unpack(packet, "d", &channel->exit_status);
SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status);
ssh_callbacks_execute_list(channel->callbacks,
ssh_channel_callbacks,
channel_exit_status_function,
channel->session,
channel,
channel->exit_status);
if(ssh_callbacks_exists(channel->callbacks, channel_exit_status_function)) {
channel->callbacks->channel_exit_status_function(channel->session,
channel,
channel->exit_status,
channel->callbacks->userdata);
}
return SSH_PACKET_USED;
}
@@ -686,13 +692,13 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
SSH_LOG(SSH_LOG_PACKET,
"Remote connection sent a signal SIG %s", sig);
ssh_callbacks_execute_list(channel->callbacks,
ssh_channel_callbacks,
channel_signal_function,
channel->session,
channel,
sig);
SAFE_FREE(sig);
if(ssh_callbacks_exists(channel->callbacks, channel_signal_function)) {
channel->callbacks->channel_signal_function(channel->session,
channel,
sig,
channel->callbacks->userdata);
}
SAFE_FREE(sig);
return SSH_PACKET_USED;
}
@@ -722,15 +728,12 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
SSH_LOG(SSH_LOG_PACKET,
"Remote connection closed by signal SIG %s %s", sig, core);
ssh_callbacks_execute_list(channel->callbacks,
ssh_channel_callbacks,
channel_exit_signal_function,
channel->session,
channel,
sig,
core_dumped,
errmsg,
lang);
if(ssh_callbacks_exists(channel->callbacks, channel_exit_signal_function)) {
channel->callbacks->channel_exit_signal_function(channel->session,
channel,
sig, core_dumped, errmsg, lang,
channel->callbacks->userdata);
}
SAFE_FREE(lang);
SAFE_FREE(errmsg);
@@ -749,7 +752,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
if (rc != SSH_OK) {
return SSH_PACKET_USED;
}
ssh_packet_send(session);
packet_send(session);
return SSH_PACKET_USED;
}
@@ -757,11 +760,10 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
if (strcmp(request, "auth-agent-req@openssh.com") == 0) {
SAFE_FREE(request);
SSH_LOG(SSH_LOG_PROTOCOL, "Received an auth-agent-req request");
ssh_callbacks_execute_list(channel->callbacks,
ssh_channel_callbacks,
channel_auth_agent_req_function,
channel->session,
channel);
if(ssh_callbacks_exists(channel->callbacks, channel_auth_agent_req_function)) {
channel->callbacks->channel_auth_agent_req_function(channel->session, channel,
channel->callbacks->userdata);
}
return SSH_PACKET_USED;
}
@@ -860,6 +862,12 @@ int ssh_channel_open_session(ssh_channel channel) {
return SSH_ERROR;
}
#ifdef WITH_SSH1
if (channel->session->version == 1) {
return channel_open_session1(channel);
}
#endif
return channel_open(channel,
"session",
CHANNEL_INITIAL_WINDOW,
@@ -887,6 +895,12 @@ int ssh_channel_open_auth_agent(ssh_channel channel){
return SSH_ERROR;
}
#ifdef WITH_SSH1
if (channel->session->version == 1) {
return SSH_ERROR;
}
#endif
return channel_open(channel,
"auth-agent@openssh.com",
CHANNEL_INITIAL_WINDOW,
@@ -1014,9 +1028,6 @@ void ssh_channel_do_free(ssh_channel channel){
}
ssh_buffer_free(channel->stdout_buffer);
ssh_buffer_free(channel->stderr_buffer);
if (channel->callbacks != NULL){
ssh_list_free(channel->callbacks);
}
/* debug trick to catch use after frees */
memset(channel, 'X', sizeof(struct ssh_channel_struct));
@@ -1071,7 +1082,7 @@ int ssh_channel_send_eof(ssh_channel channel){
goto error;
}
rc = ssh_packet_send(session);
rc = packet_send(session);
SSH_LOG(SSH_LOG_PACKET,
"Sent a EOF on client channel (%d:%d)",
channel->local_channel,
@@ -1130,7 +1141,7 @@ int ssh_channel_close(ssh_channel channel){
goto error;
}
rc = ssh_packet_send(session);
rc = packet_send(session);
SSH_LOG(SSH_LOG_PACKET,
"Sent a close on client channel (%d:%d)",
channel->local_channel,
@@ -1234,10 +1245,16 @@ static int channel_write_common(ssh_channel channel,
return -1;
}
if (session->session_state == SSH_SESSION_STATE_ERROR) {
if (channel->session->session_state == SSH_SESSION_STATE_ERROR) {
return SSH_ERROR;
}
#ifdef WITH_SSH1
if (channel->version == 1) {
rc = channel_write1(channel, data, len);
return rc;
}
#endif
if (ssh_waitsession_unblocked(session) == 0){
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT,
ssh_waitsession_unblocked, session);
@@ -1259,7 +1276,7 @@ static int channel_write_common(ssh_channel channel,
ssh_channel_waitwindow_termination,channel);
if (rc == SSH_ERROR ||
!ssh_channel_waitwindow_termination(channel) ||
session->session_state == SSH_SESSION_STATE_ERROR ||
channel->session->session_state == SSH_SESSION_STATE_ERROR ||
channel->state == SSH_CHANNEL_STATE_CLOSED)
goto out;
continue;
@@ -1301,7 +1318,7 @@ static int channel_write_common(ssh_channel channel,
goto error;
}
rc = ssh_packet_send(session);
rc = packet_send(session);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
@@ -1332,23 +1349,6 @@ error:
return SSH_ERROR;
}
/**
* @brief Get the remote window size.
*
* This is the maximum amounts of bytes the remote side expects us to send
* before growing the window again.
*
* @param[in] channel The channel to query.
*
* @return The remote window size
*
* @warning A nonzero return value does not guarantee the socket is ready
* to send that much data. Buffering may happen in the local SSH
* packet buffer, so beware of really big window sizes.
*
* @warning A zero return value means ssh_channel_write (default settings)
* will block until the window grows back.
*/
uint32_t ssh_channel_window_size(ssh_channel channel) {
return channel->remote_window;
}
@@ -1414,9 +1414,9 @@ int ssh_channel_is_eof(ssh_channel channel) {
return SSH_ERROR;
}
if ((channel->stdout_buffer &&
ssh_buffer_get_len(channel->stdout_buffer) > 0) ||
buffer_get_rest_len(channel->stdout_buffer) > 0) ||
(channel->stderr_buffer &&
ssh_buffer_get_len(channel->stderr_buffer) > 0)) {
buffer_get_rest_len(channel->stderr_buffer) > 0)) {
return 0;
}
@@ -1445,6 +1445,8 @@ void ssh_channel_set_blocking(ssh_channel channel, int blocking) {
* @internal
*
* @brief handle a SSH_CHANNEL_SUCCESS packet and set the channel state.
*
* This works on SSH1 sessions too.
*/
SSH_PACKET_CALLBACK(ssh_packet_channel_success){
ssh_channel channel;
@@ -1475,6 +1477,8 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_success){
* @internal
*
* @brief Handle a SSH_CHANNEL_FAILURE packet and set the channel state.
*
* This works on SSH1 sessions too.
*/
SSH_PACKET_CALLBACK(ssh_packet_channel_failure){
ssh_channel channel;
@@ -1536,14 +1540,14 @@ static int channel_request(ssh_channel channel, const char *request,
}
if (buffer != NULL) {
if (ssh_buffer_add_data(session->out_buffer, ssh_buffer_get(buffer),
ssh_buffer_get_len(buffer)) < 0) {
if (ssh_buffer_add_data(session->out_buffer, buffer_get_rest(buffer),
buffer_get_rest_len(buffer)) < 0) {
ssh_set_error_oom(session);
goto error;
}
}
channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING;
if (ssh_packet_send(session) == SSH_ERROR) {
if (packet_send(session) == SSH_ERROR) {
return rc;
}
@@ -1627,6 +1631,13 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal,
return rc;
}
#ifdef WITH_SSH1
if (channel->version==1) {
rc = channel_request_pty_size1(channel,terminal, col, row);
return rc;
}
#endif
switch(channel->request_state){
case SSH_CHANNEL_REQ_STATE_NONE:
break;
@@ -1698,6 +1709,14 @@ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) {
ssh_buffer buffer = NULL;
int rc = SSH_ERROR;
#ifdef WITH_SSH1
if (channel->version == 1) {
rc = channel_change_pty_size1(channel,cols,rows);
return rc;
}
#endif
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(session);
@@ -1736,8 +1755,12 @@ int ssh_channel_request_shell(ssh_channel channel) {
if(channel == NULL) {
return SSH_ERROR;
}
return channel_request(channel, "shell", NULL, 1);
#ifdef WITH_SSH1
if (channel->version == 1) {
return channel_request_shell1(channel);
}
#endif
return channel_request(channel, "shell", NULL, 1);
}
/**
@@ -1802,14 +1825,9 @@ static char *generate_cookie(void) {
static const char *hex = "0123456789abcdef";
char s[36];
unsigned char rnd[16];
int ok;
int i;
ok = ssh_get_random(rnd, sizeof(rnd), 0);
if (!ok) {
return NULL;
}
ssh_get_random(rnd,sizeof(rnd),0);
for (i = 0; i < 16; i++) {
s[i*2] = hex[rnd[i] & 0x0f];
s[i*2+1] = hex[rnd[i] >> 4];
@@ -1963,25 +1981,6 @@ ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms) {
return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms, NULL);
}
/**
* @brief Send an "auth-agent-req" channel request over an existing session channel.
*
* This client-side request will enable forwarding the agent over an secure tunnel.
* When the server is ready to open one authentication agent channel, an
* ssh_channel_open_request_auth_agent_callback event will be generated.
*
* @param[in] channel The channel to send signal.
*
* @return SSH_OK on success, SSH_ERROR if an error occurred
*/
int ssh_channel_request_auth_agent(ssh_channel channel) {
if (channel == NULL) {
return SSH_ERROR;
}
return channel_request(channel, "auth-agent-req@openssh.com", NULL, 0);
}
/**
* @internal
*
@@ -2081,8 +2080,8 @@ static int global_request(ssh_session session, const char *request,
if (buffer != NULL) {
rc = ssh_buffer_add_data(session->out_buffer,
ssh_buffer_get(buffer),
ssh_buffer_get_len(buffer));
buffer_get_rest(buffer),
buffer_get_rest_len(buffer));
if (rc < 0) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
@@ -2091,7 +2090,7 @@ static int global_request(ssh_session session, const char *request,
}
session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
rc = ssh_packet_send(session);
rc = packet_send(session);
if (rc == SSH_ERROR) {
return rc;
}
@@ -2378,6 +2377,11 @@ int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
return rc;
}
#ifdef WITH_SSH1
if (channel->version == 1) {
return channel_request_exec1(channel, cmd);
}
#endif
switch(channel->request_state){
case SSH_CHANNEL_REQ_STATE_NONE:
break;
@@ -2448,6 +2452,12 @@ int ssh_channel_request_send_signal(ssh_channel channel, const char *sig) {
return rc;
}
#ifdef WITH_SSH1
if (channel->version == 1) {
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
}
#endif
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(channel->session);
@@ -2467,49 +2477,6 @@ error:
}
/**
* @brief Send a break signal to the server (as described in RFC 4335).
*
* Sends a break signal to the remote process.
* Note, that remote system may not support breaks.
* In such a case this request will be silently ignored.
* Only SSH-v2 is supported.
*
* @param[in] channel The channel to send the break to.
*
* @param[in] length The break-length in milliseconds to send.
*
* @return SSH_OK on success, SSH_ERROR if an error occurred
* (including attempts to send signal via SSH-v1 session).
*/
int ssh_channel_request_send_break(ssh_channel channel, uint32_t length) {
ssh_buffer buffer = NULL;
int rc = SSH_ERROR;
if (channel == NULL) {
return SSH_ERROR;
}
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(channel->session);
goto error;
}
rc = ssh_buffer_pack(buffer, "d", length);
if (rc != SSH_OK) {
ssh_set_error_oom(channel->session);
goto error;
}
rc = channel_request(channel, "break", buffer, 0);
error:
ssh_buffer_free(buffer);
return rc;
}
/**
* @brief Read data from a channel into a buffer.
*
@@ -2598,7 +2565,7 @@ struct ssh_channel_read_termination_struct {
static int ssh_channel_read_termination(void *s){
struct ssh_channel_read_termination_struct *ctx = s;
if (ssh_buffer_get_len(ctx->buffer) >= ctx->count ||
if (buffer_get_rest_len(ctx->buffer) >= ctx->count ||
ctx->channel->remote_eof ||
ctx->channel->session->session_state == SSH_SESSION_STATE_ERROR)
return 1;
@@ -2695,11 +2662,11 @@ int ssh_channel_read_timeout(ssh_channel channel,
SSH_LOG(SSH_LOG_PACKET,
"Read (%d) buffered : %d bytes. Window: %d",
count,
ssh_buffer_get_len(stdbuf),
buffer_get_rest_len(stdbuf),
channel->local_window);
if (count > ssh_buffer_get_len(stdbuf) + channel->local_window) {
if (grow_window(session, channel, count - ssh_buffer_get_len(stdbuf)) < 0) {
if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
if (grow_window(session, channel, count - buffer_get_rest_len(stdbuf)) < 0) {
return -1;
}
}
@@ -2722,17 +2689,17 @@ int ssh_channel_read_timeout(ssh_channel channel,
if (rc == SSH_ERROR){
return rc;
}
if (session->session_state == SSH_SESSION_STATE_ERROR){
if (channel->session->session_state == SSH_SESSION_STATE_ERROR){
return SSH_ERROR;
}
if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) {
if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
return 0;
}
len = ssh_buffer_get_len(stdbuf);
len = buffer_get_rest_len(stdbuf);
/* Read count bytes if len is greater, everything otherwise */
len = (len > count ? count : len);
memcpy(dest, ssh_buffer_get(stdbuf), len);
ssh_buffer_pass_bytes(stdbuf,len);
memcpy(dest, buffer_get_rest(stdbuf), len);
buffer_pass_bytes(stdbuf,len);
if (channel->counter != NULL) {
channel->counter->in_bytes += len;
}
@@ -2787,7 +2754,7 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count
to_read = ssh_channel_poll(channel, is_stderr);
if (to_read <= 0) {
if (session->session_state == SSH_SESSION_STATE_ERROR){
if (channel->session->session_state == SSH_SESSION_STATE_ERROR){
return SSH_ERROR;
}
@@ -2832,7 +2799,7 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
stdbuf = channel->stderr_buffer;
}
if (ssh_buffer_get_len(stdbuf) == 0 && channel->remote_eof == 0) {
if (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
if (channel->session->session_state == SSH_SESSION_STATE_ERROR){
return SSH_ERROR;
}
@@ -2841,15 +2808,15 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
}
}
if (ssh_buffer_get_len(stdbuf) > 0){
return ssh_buffer_get_len(stdbuf);
if (buffer_get_rest_len(stdbuf) > 0){
return buffer_get_rest_len(stdbuf);
}
if (channel->remote_eof) {
return SSH_EOF;
}
return ssh_buffer_get_len(stdbuf);
return buffer_get_rest_len(stdbuf);
}
/**
@@ -2896,7 +2863,7 @@ int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr){
rc = SSH_ERROR;
goto end;
}
rc = ssh_buffer_get_len(stdbuf);
rc = buffer_get_rest_len(stdbuf);
if(rc > 0)
goto end;
if (channel->remote_eof)
@@ -2985,8 +2952,8 @@ static int channel_protocol_select(ssh_channel *rchans, ssh_channel *wchans,
ssh_handle_packets(chan->session, SSH_TIMEOUT_NONBLOCKING);
}
if ((chan->stdout_buffer && ssh_buffer_get_len(chan->stdout_buffer) > 0) ||
(chan->stderr_buffer && ssh_buffer_get_len(chan->stderr_buffer) > 0) ||
if ((chan->stdout_buffer && buffer_get_rest_len(chan->stdout_buffer) > 0) ||
(chan->stderr_buffer && buffer_get_rest_len(chan->stderr_buffer) > 0) ||
chan->remote_eof) {
rout[j] = chan;
j++;
@@ -3087,18 +3054,18 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
}
/* Prepare the outgoing temporary arrays */
rchans = calloc(count_ptrs(readchans) + 1, sizeof(ssh_channel));
rchans = malloc(sizeof(ssh_channel ) * (count_ptrs(readchans) + 1));
if (rchans == NULL) {
return SSH_ERROR;
}
wchans = calloc(count_ptrs(writechans) + 1, sizeof(ssh_channel));
wchans = malloc(sizeof(ssh_channel ) * (count_ptrs(writechans) + 1));
if (wchans == NULL) {
SAFE_FREE(rchans);
return SSH_ERROR;
}
echans = calloc(count_ptrs(exceptchans) + 1, sizeof(ssh_channel));
echans = malloc(sizeof(ssh_channel ) * (count_ptrs(exceptchans) + 1));
if (echans == NULL) {
SAFE_FREE(rchans);
SAFE_FREE(wchans);
@@ -3192,6 +3159,7 @@ void ssh_channel_set_counter(ssh_channel channel,
}
}
#if WITH_SERVER
/**
* @brief Blocking write on a channel stderr.
*
@@ -3209,8 +3177,6 @@ int ssh_channel_write_stderr(ssh_channel channel, const void *data, uint32_t len
return channel_write_common(channel, data, len, 1);
}
#if WITH_SERVER
/**
* @brief Open a TCP/IP reverse forwarding channel.
*
@@ -3365,6 +3331,12 @@ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
return SSH_ERROR;
}
#ifdef WITH_SSH1
if (channel->version == 1) {
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
}
#endif
buffer = ssh_buffer_new();
if (buffer == NULL) {
ssh_set_error_oom(channel->session);
@@ -3414,6 +3386,11 @@ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig,
ssh_set_error_invalid(channel->session);
return rc;
}
#ifdef WITH_SSH1
if (channel->version == 1) {
return SSH_ERROR; // TODO: Add support for SSH-v1 if possible.
}
#endif
buffer = ssh_buffer_new();
if (buffer == NULL) {
@@ -3441,3 +3418,5 @@ error:
#endif
/* @} */
/* vim: set ts=4 sw=4 et cindent: */

396
src/channels1.c Normal file
View File

@@ -0,0 +1,396 @@
/*
* channels1.c - Support for SSH-1 type channels
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2008 by Aris Adamantiadis
* Copyright (c) 2009 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef _WIN32
#include <arpa/inet.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "libssh/priv.h"
#include "libssh/ssh1.h"
#include "libssh/buffer.h"
#include "libssh/packet.h"
#include "libssh/channels.h"
#include "libssh/session.h"
#include "libssh/misc.h"
#ifdef WITH_SSH1
/*
* This is a big hack. In fact, SSH1 doesn't make a clever use of channels.
* The whole packets concerning shells are sent outside of a channel.
* Thus, an inside limitation of this behavior is that you can't only
* request one shell.
* The question is still how they managed to embed two "channel" into one
* protocol.
*/
int channel_open_session1(ssh_channel chan) {
ssh_session session;
if (chan == NULL) {
return -1;
}
session = chan->session;
/*
* We guess we are requesting an *exec* channel. It can only have one exec
* channel. So we abort with an error if we need more than one.
*/
if (session->exec_channel_opened) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"SSH1 supports only one execution channel. "
"One has already been opened");
return -1;
}
session->exec_channel_opened = 1;
chan->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED;
chan->state = SSH_CHANNEL_STATE_OPEN;
chan->local_maxpacket = 32000;
chan->local_window = 64000;
SSH_LOG(SSH_LOG_PACKET, "Opened a SSH1 channel session");
return 0;
}
/* 10 SSH_CMSG_REQUEST_PTY
*
* string TERM environment variable value (e.g. vt100)
* 32-bit int terminal height, rows (e.g., 24)
* 32-bit int terminal width, columns (e.g., 80)
* 32-bit int terminal width, pixels (0 if no graphics) (e.g., 480)
* 32-bit int terminal height, pixels (0 if no graphics) (e.g., 640)
* n bytes tty modes encoded in binary
* Some day, someone should have a look at that nasty tty encoded. It's
* much simplier under ssh2. I just hope the defaults values are ok ...
*/
int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col,
int row) {
ssh_session session;
ssh_string str = NULL;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE &&
channel->request_state != SSH_CHANNEL_REQ_STATE_ACCEPTED){
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
return SSH_ERROR;
}
str = ssh_string_from_char(terminal);
if (str == NULL) {
ssh_set_error_oom(session);
return -1;
}
if (buffer_add_u8(session->out_buffer, SSH_CMSG_REQUEST_PTY) < 0 ||
buffer_add_ssh_string(session->out_buffer, str) < 0) {
ssh_string_free(str);
return -1;
}
ssh_string_free(str);
if (buffer_add_u32(session->out_buffer, ntohl(row)) < 0 ||
buffer_add_u32(session->out_buffer, ntohl(col)) < 0 ||
buffer_add_u32(session->out_buffer, 0) < 0 || /* x */
buffer_add_u32(session->out_buffer, 0) < 0 || /* y */
buffer_add_u8(session->out_buffer, 0) < 0) { /* tty things */
return -1;
}
SSH_LOG(SSH_LOG_FUNCTIONS, "Opening a ssh1 pty");
channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING;
if (packet_send(session) == SSH_ERROR) {
return -1;
}
while (channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING) {
ssh_handle_packets(session, SSH_TIMEOUT_INFINITE);
}
switch(channel->request_state){
case SSH_CHANNEL_REQ_STATE_ERROR:
case SSH_CHANNEL_REQ_STATE_PENDING:
case SSH_CHANNEL_REQ_STATE_NONE:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
return SSH_ERROR;
case SSH_CHANNEL_REQ_STATE_ACCEPTED:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
SSH_LOG(SSH_LOG_RARE, "PTY: Success");
return SSH_OK;
case SSH_CHANNEL_REQ_STATE_DENIED:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
ssh_set_error(session, SSH_REQUEST_DENIED,
"Server denied PTY allocation");
SSH_LOG(SSH_LOG_RARE, "PTY: denied\n");
return SSH_ERROR;
}
// Not reached
return SSH_ERROR;
}
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) {
ssh_session session;
if (channel == NULL) {
return SSH_ERROR;
}
session = channel->session;
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
return SSH_ERROR;
}
if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 ||
buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 ||
buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 ||
buffer_add_u32(session->out_buffer, 0) < 0 ||
buffer_add_u32(session->out_buffer, 0) < 0) {
return SSH_ERROR;
}
channel->request_state=SSH_CHANNEL_REQ_STATE_PENDING;
if (packet_send(session) == SSH_ERROR) {
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_PROTOCOL, "Change pty size send");
while(channel->request_state==SSH_CHANNEL_REQ_STATE_PENDING){
ssh_handle_packets(session, SSH_TIMEOUT_INFINITE);
}
switch(channel->request_state){
case SSH_CHANNEL_REQ_STATE_ERROR:
case SSH_CHANNEL_REQ_STATE_PENDING:
case SSH_CHANNEL_REQ_STATE_NONE:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
return SSH_ERROR;
case SSH_CHANNEL_REQ_STATE_ACCEPTED:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
SSH_LOG(SSH_LOG_PROTOCOL, "pty size changed");
return SSH_OK;
case SSH_CHANNEL_REQ_STATE_DENIED:
channel->request_state=SSH_CHANNEL_REQ_STATE_NONE;
SSH_LOG(SSH_LOG_RARE, "pty size change denied");
ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied");
return SSH_ERROR;
}
// Not reached
return SSH_ERROR;
}
int channel_request_shell1(ssh_channel channel) {
ssh_session session;
if (channel == NULL) {
return -1;
}
session = channel->session;
if (buffer_add_u8(session->out_buffer,SSH_CMSG_EXEC_SHELL) < 0) {
return -1;
}
if (packet_send(session) == SSH_ERROR) {
return -1;
}
SSH_LOG(SSH_LOG_RARE, "Launched a shell");
return 0;
}
int channel_request_exec1(ssh_channel channel, const char *cmd) {
ssh_session session;
ssh_string command = NULL;
if (channel == NULL) {
return -1;
}
session = channel->session;
command = ssh_string_from_char(cmd);
if (command == NULL) {
return -1;
}
if (buffer_add_u8(session->out_buffer, SSH_CMSG_EXEC_CMD) < 0 ||
buffer_add_ssh_string(session->out_buffer, command) < 0) {
ssh_string_free(command);
return -1;
}
ssh_string_free(command);
if(packet_send(session) == SSH_ERROR) {
return -1;
}
SSH_LOG(SSH_LOG_RARE, "Executing %s ...", cmd);
return 0;
}
SSH_PACKET_CALLBACK(ssh_packet_data1){
ssh_channel channel = ssh_get_channel1(session);
ssh_string str = NULL;
int is_stderr=(type==SSH_SMSG_STDOUT_DATA ? 0 : 1);
(void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
str = buffer_get_ssh_string(packet);
if (str == NULL) {
SSH_LOG(SSH_LOG_FUNCTIONS, "Invalid data packet !\n");
return SSH_PACKET_USED;
}
SSH_LOG(SSH_LOG_PROTOCOL,
"Adding %" PRIdS " bytes data in %d",
ssh_string_len(str), is_stderr);
if (channel_default_bufferize(channel, ssh_string_data(str), ssh_string_len(str),
is_stderr) < 0) {
ssh_string_free(str);
return SSH_PACKET_USED;
}
ssh_string_free(str);
return SSH_PACKET_USED;
}
SSH_PACKET_CALLBACK(ssh_packet_close1){
ssh_channel channel = ssh_get_channel1(session);
uint32_t status;
int rc;
(void)type;
(void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
buffer_get_u32(packet, &status);
/*
* It's much more than a channel closing. spec says it's the last
* message sent by server (strange)
*/
/* actually status is lost somewhere */
channel->state = SSH_CHANNEL_STATE_CLOSED;
channel->remote_eof = 1;
rc = buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION);
if (rc < 0) {
return SSH_PACKET_NOT_USED;
}
packet_send(session);
return SSH_PACKET_USED;
}
SSH_PACKET_CALLBACK(ssh_packet_exist_status1){
ssh_channel channel = ssh_get_channel1(session);
uint32_t status;
(void)type;
(void)user;
if (channel == NULL) {
return SSH_PACKET_NOT_USED;
}
buffer_get_u32(packet, &status);
channel->state = SSH_CHANNEL_STATE_CLOSED;
channel->remote_eof = 1;
channel->exit_status = ntohl(status);
return SSH_PACKET_USED;
}
int channel_write1(ssh_channel channel, const void *data, int len) {
ssh_session session;
int origlen = len;
int effectivelen;
const unsigned char *ptr=data;
if (channel == NULL) {
return -1;
}
session = channel->session;
while (len > 0) {
if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) {
return -1;
}
effectivelen = len > 32000 ? 32000 : len;
if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 ||
ssh_buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) {
return -1;
}
ptr += effectivelen;
len -= effectivelen;
if (packet_send(session) == SSH_ERROR) {
return -1;
}
ssh_handle_packets(session, SSH_TIMEOUT_NONBLOCKING);
if (channel->counter != NULL) {
channel->counter->out_bytes += effectivelen;
}
}
if (ssh_blocking_flush(session,SSH_TIMEOUT_USER) == SSH_ERROR)
return -1;
return origlen;
}
ssh_channel ssh_get_channel1(ssh_session session){
struct ssh_iterator *it;
if (session == NULL) {
return NULL;
}
/* With SSH1, the channel is always the first one */
if(session->channels != NULL){
it = ssh_list_get_iterator(session->channels);
if(it)
return ssh_iterator_value(ssh_channel, it);
}
return NULL;
}
#endif /* WITH_SSH1 */
/* vim: set ts=2 sw=2 et cindent: */

View File

@@ -21,9 +21,9 @@
* MA 02111-1307, USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
@@ -90,74 +90,52 @@ static void socket_callback_connected(int code, int errno_code, void *user){
* @param user is a pointer to session
* @returns Number of bytes processed, or zero if the banner is not complete.
*/
static int callback_receive_banner(const void *data, size_t len, void *user)
{
char *buffer = (char *)data;
ssh_session session=(ssh_session) user;
char *str = NULL;
size_t i;
int ret=0;
static int callback_receive_banner(const void *data, size_t len, void *user) {
char *buffer = (char *)data;
ssh_session session=(ssh_session) user;
char *str = NULL;
size_t i;
int ret=0;
if (session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED) {
ssh_set_error(session,SSH_FATAL,
"Wrong state in callback_receive_banner : %d",
session->session_state);
if(session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED){
ssh_set_error(session,SSH_FATAL,"Wrong state in callback_receive_banner : %d",session->session_state);
return SSH_ERROR;
}
for (i = 0; i < len; ++i) {
return SSH_ERROR;
}
for(i=0;i<len;++i){
#ifdef WITH_PCAP
if (session->pcap_ctx && buffer[i] == '\n') {
ssh_pcap_context_write(session->pcap_ctx,
SSH_PCAP_DIR_IN,
buffer,i+1,
i+1);
}
if(session->pcap_ctx && buffer[i] == '\n'){
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
}
#endif
if (buffer[i] == '\r') {
buffer[i] = '\0';
}
if (buffer[i] == '\n') {
int cmp;
buffer[i] = '\0';
/* The server MAY send other lines of data... */
cmp = strncmp(buffer, "SSH-", 4);
if (cmp == 0) {
str = strdup(buffer);
if (str == NULL) {
return SSH_ERROR;
}
/* number of bytes read */
ret = i + 1;
session->serverbanner = str;
session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED;
SSH_LOG(SSH_LOG_PACKET, "Received banner: %s", str);
session->ssh_connection_callback(session);
return ret;
} else {
SSH_LOG(SSH_LOG_DEBUG,
"ssh_protocol_version_exchange: %s",
buffer);
ret = i + 1;
break;
}
}
/* According to RFC 4253 the max banner length is 255 */
if (i > 255) {
/* Too big banner */
session->session_state=SSH_SESSION_STATE_ERROR;
ssh_set_error(session,
SSH_FATAL,
"Receiving banner: too large banner");
return 0;
}
if(buffer[i]=='\r') {
buffer[i]='\0';
}
if (buffer[i]=='\n') {
buffer[i] = '\0';
str = strdup(buffer);
if (str == NULL) {
return SSH_ERROR;
}
/* number of bytes read */
ret = i + 1;
session->serverbanner = str;
session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED;
SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str);
session->ssh_connection_callback(session);
return ret;
return ret;
}
if(i>127){
/* Too big banner */
session->session_state=SSH_SESSION_STATE_ERROR;
ssh_set_error(session,SSH_FATAL,"Receiving banner: too large banner");
return 0;
}
}
return ret;
}
/** @internal
@@ -169,69 +147,46 @@ static int callback_receive_banner(const void *data, size_t len, void *user)
*
* @return 0 on success, < 0 on error.
*/
int ssh_send_banner(ssh_session session, int server)
{
const char *banner = CLIENT_BANNER_SSH2;
const char *terminator = "\r\n";
/* The maximum banner length is 255 for SSH2 */
char buffer[256] = {0};
size_t len;
int rc = SSH_ERROR;
int ssh_send_banner(ssh_session session, int server) {
const char *banner = NULL;
char buffer[128] = {0};
int err=SSH_ERROR;
if (server == 1) {
if (session->opts.custombanner == NULL){
len = strlen(banner);
session->serverbanner = strdup(banner);
if (session->serverbanner == NULL) {
goto end;
}
} else {
len = strlen(session->opts.custombanner);
session->serverbanner = malloc(len + 8 + 1);
if(session->serverbanner == NULL) {
goto end;
}
snprintf(session->serverbanner,
len + 8 + 1,
"SSH-2.0-%s",
session->opts.custombanner);
}
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
snprintf(buffer,
sizeof(buffer),
"%s%s",
session->serverbanner,
terminator);
if (server) {
if(session->opts.custombanner == NULL){
session->serverbanner = strdup(banner);
} else {
session->clientbanner = strdup(banner);
if (session->clientbanner == NULL) {
goto end;
}
snprintf(buffer,
sizeof(buffer),
"%s%s",
session->clientbanner,
terminator);
session->serverbanner = malloc(strlen(session->opts.custombanner) + 9);
if(!session->serverbanner)
goto end;
strcpy(session->serverbanner, "SSH-2.0-");
strcat(session->serverbanner, session->opts.custombanner);
}
rc = ssh_socket_write(session->socket, buffer, strlen(buffer));
if (rc == SSH_ERROR) {
goto end;
if (session->serverbanner == NULL) {
goto end;
}
snprintf(buffer, 128, "%s\n", session->serverbanner);
} else {
session->clientbanner = strdup(banner);
if (session->clientbanner == NULL) {
goto end;
}
snprintf(buffer, 128, "%s\n", session->clientbanner);
}
if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) {
goto end;
}
#ifdef WITH_PCAP
if (session->pcap_ctx != NULL) {
ssh_pcap_context_write(session->pcap_ctx,
SSH_PCAP_DIR_OUT,
buffer,
strlen(buffer),
strlen(buffer));
}
if(session->pcap_ctx)
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer));
#endif
rc = SSH_OK;
err=SSH_OK;
end:
return rc;
return err;
}
/** @internal
@@ -254,13 +209,10 @@ static int dh_handshake(ssh_session session) {
break;
#ifdef HAVE_ECDH
case SSH_KEX_ECDH_SHA2_NISTP256:
case SSH_KEX_ECDH_SHA2_NISTP384:
case SSH_KEX_ECDH_SHA2_NISTP521:
rc = ssh_client_ecdh_init(session);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_init(session);
break;
@@ -331,7 +283,7 @@ int ssh_service_request(ssh_session session, const char *service) {
return SSH_ERROR;
}
session->auth_service_state=SSH_AUTH_SERVICE_SENT;
if (ssh_packet_send(session) == SSH_ERROR) {
if (packet_send(session) == SSH_ERROR) {
ssh_set_error(session, SSH_FATAL,
"Sending SSH2_MSG_SERVICE_REQUEST failed.");
return SSH_ERROR;
@@ -356,6 +308,8 @@ pending:
rc=SSH_AGAIN;
break;
case SSH_AUTH_SERVICE_NONE:
case SSH_AUTH_SERVICE_USER_SENT:
/* Invalid state, SSH1 specific */
rc=SSH_ERROR;
break;
}
@@ -375,86 +329,113 @@ pending:
* @brief A function to be called each time a step has been done in the
* connection.
*/
static void ssh_client_connection_callback(ssh_session session)
{
int rc;
static void ssh_client_connection_callback(ssh_session session){
int ssh1,ssh2;
switch(session->session_state) {
case SSH_SESSION_STATE_NONE:
case SSH_SESSION_STATE_CONNECTING:
break;
case SSH_SESSION_STATE_SOCKET_CONNECTED:
ssh_set_fd_towrite(session);
ssh_send_banner(session, 0);
switch(session->session_state){
case SSH_SESSION_STATE_NONE:
case SSH_SESSION_STATE_CONNECTING:
case SSH_SESSION_STATE_SOCKET_CONNECTED:
break;
case SSH_SESSION_STATE_BANNER_RECEIVED:
if (session->serverbanner == NULL) {
goto error;
}
set_status(session, 0.4f);
SSH_LOG(SSH_LOG_RARE,
"SSH server banner: %s", session->serverbanner);
break;
case SSH_SESSION_STATE_BANNER_RECEIVED:
if (session->serverbanner == NULL) {
goto error;
}
set_status(session, 0.4f);
SSH_LOG(SSH_LOG_RARE,
"SSH server banner: %s", session->serverbanner);
/* Here we analyze the different protocols the server allows. */
rc = ssh_analyze_banner(session, 0);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"No version of SSH protocol usable (banner: %s)",
session->serverbanner);
goto error;
}
ssh_packet_register_socket_callback(session, session->socket);
ssh_packet_set_default_callbacks(session);
session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
set_status(session, 0.5f);
break;
case SSH_SESSION_STATE_INITIAL_KEX:
/* TODO: This state should disappear in favor of get_key handle */
break;
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session,0.6f);
ssh_list_kex(&session->next_crypto->server_kex);
if (ssh_set_client_kex(session) < 0) {
goto error;
}
if (ssh_kex_select_methods(session) == SSH_ERROR)
goto error;
if (ssh_send_kex(session, 0) < 0) {
goto error;
}
set_status(session,0.8f);
session->session_state=SSH_SESSION_STATE_DH;
if (dh_handshake(session) == SSH_ERROR) {
goto error;
}
/* Here we analyze the different protocols the server allows. */
if (ssh_analyze_banner(session, 0, &ssh1, &ssh2) < 0) {
goto error;
}
/* Here we decide which version of the protocol to use. */
if (ssh2 && session->opts.ssh2) {
session->version = 2;
#ifdef WITH_SSH1
} else if(ssh1 && session->opts.ssh1) {
session->version = 1;
#endif
} else if(ssh1 && !session->opts.ssh1){
#ifdef WITH_SSH1
ssh_set_error(session, SSH_FATAL,
"SSH-1 protocol not available (configure session to allow SSH-1)");
goto error;
#else
ssh_set_error(session, SSH_FATAL,
"SSH-1 protocol not available (libssh compiled without SSH-1 support)");
goto error;
#endif
} else {
ssh_set_error(session, SSH_FATAL,
"No version of SSH protocol usable (banner: %s)",
session->serverbanner);
goto error;
}
/* from now, the packet layer is handling incoming packets */
if(session->version==2)
session->socket_callbacks.data=ssh_packet_socket_callback;
#ifdef WITH_SSH1
else
session->socket_callbacks.data=ssh_packet_socket_callback1;
#endif
ssh_packet_set_default_callbacks(session);
session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
ssh_send_banner(session, 0);
set_status(session, 0.5f);
break;
case SSH_SESSION_STATE_INITIAL_KEX:
/* TODO: This state should disappear in favor of get_key handle */
#ifdef WITH_SSH1
if(session->version==1){
if (ssh_get_kex1(session) < 0)
goto error;
set_status(session,0.6f);
session->connected = 1;
break;
}
#endif
break;
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session,0.6f);
ssh_list_kex(&session->next_crypto->server_kex);
if (set_client_kex(session) < 0) {
goto error;
}
if (ssh_kex_select_methods(session) == SSH_ERROR)
goto error;
if (ssh_send_kex(session, 0) < 0) {
goto error;
}
set_status(session,0.8f);
session->session_state=SSH_SESSION_STATE_DH;
if (dh_handshake(session) == SSH_ERROR) {
goto error;
}
/* FALL THROUGH */
case SSH_SESSION_STATE_DH:
if(session->dh_handshake_state==DH_STATE_FINISHED){
set_status(session,1.0f);
session->connected = 1;
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
else
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
}
break;
case SSH_SESSION_STATE_AUTHENTICATING:
break;
case SSH_SESSION_STATE_ERROR:
goto error;
default:
ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
}
case SSH_SESSION_STATE_DH:
if(session->dh_handshake_state==DH_STATE_FINISHED){
set_status(session,1.0f);
session->connected = 1;
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
else
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
}
break;
case SSH_SESSION_STATE_AUTHENTICATING:
break;
case SSH_SESSION_STATE_ERROR:
goto error;
default:
ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
}
return;
return;
error:
ssh_socket_close(session->socket);
session->alive = 0;
session->session_state=SSH_SESSION_STATE_ERROR;
ssh_socket_close(session->socket);
session->alive = 0;
session->session_state=SSH_SESSION_STATE_ERROR;
}
@@ -505,6 +486,9 @@ int ssh_connect(ssh_session session) {
session->alive = 0;
session->client = 1;
if (ssh_init() < 0) {
return SSH_ERROR;
}
if (session->opts.fd == SSH_INVALID_SOCKET &&
session->opts.host == NULL &&
session->opts.ProxyCommand == NULL) {
@@ -650,22 +634,19 @@ void ssh_disconnect(ssh_session session) {
if (session->socket != NULL && ssh_socket_is_open(session->socket)) {
rc = ssh_buffer_pack(session->out_buffer,
"bdss",
"bds",
SSH2_MSG_DISCONNECT,
SSH2_DISCONNECT_BY_APPLICATION,
"Bye Bye",
""); /* language tag */
"Bye Bye");
if (rc != SSH_OK){
ssh_set_error_oom(session);
goto error;
}
ssh_packet_send(session);
packet_send(session);
ssh_socket_close(session->socket);
}
error:
session->recv_seq = 0;
session->send_seq = 0;
session->alive = 0;
if (session->socket != NULL){
ssh_socket_reset(session->socket);
@@ -681,13 +662,6 @@ error:
crypto_free(session->current_crypto);
session->current_crypto=NULL;
}
if (session->next_crypto) {
crypto_free(session->next_crypto);
session->next_crypto = crypto_new();
if (session->next_crypto == NULL) {
ssh_set_error_oom(session);
}
}
if (session->in_buffer) {
ssh_buffer_reinit(session->in_buffer);
}
@@ -721,10 +695,10 @@ error:
}
const char *ssh_copyright(void) {
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2018 "
"Aris Adamantiadis, Andreas Schneider "
"and libssh contributors. "
"Distributed under the LGPL, please refer to COPYING "
"file for information about your rights";
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2014 Aris Adamantiadis, Andreas Schneider, "
"and libssh contributors. Distributed under the LGPL, please refer to COPYING "
"file for information about your rights";
}
/** @} */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -27,32 +27,20 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_GLOB_H
# include <glob.h>
#endif
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/misc.h"
#include "libssh/options.h"
#define MAX_LINE_SIZE 1024
enum ssh_config_opcode_e {
/* Unknown opcode */
SOC_UNKNOWN = -3,
/* Known and not applicable to libssh */
SOC_NA = -2,
/* Known but not supported by current libssh version */
SOC_UNSUPPORTED = -1,
SOC_HOST,
SOC_MATCH,
SOC_HOSTNAME,
SOC_PORT,
SOC_USERNAME,
SOC_IDENTITY,
SOC_CIPHERS,
SOC_MACS,
SOC_COMPRESSION,
SOC_TIMEOUT,
SOC_PROTOCOL,
@@ -62,18 +50,6 @@ enum ssh_config_opcode_e {
SOC_GSSAPISERVERIDENTITY,
SOC_GSSAPICLIENTIDENTITY,
SOC_GSSAPIDELEGATECREDENTIALS,
SOC_INCLUDE,
SOC_BINDADDRESS,
SOC_GLOBALKNOWNHOSTSFILE,
SOC_LOGLEVEL,
SOC_HOSTKEYALGORITHMS,
SOC_KEXALGORITHMS,
SOC_GSSAPIAUTHENTICATION,
SOC_KBDINTERACTIVEAUTHENTICATION,
SOC_PASSWORDAUTHENTICATION,
SOC_PUBKEYAUTHENTICATION,
SOC_END /* Keep this one last in the list */
};
struct ssh_config_keyword_table_s {
@@ -83,13 +59,11 @@ struct ssh_config_keyword_table_s {
static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "host", SOC_HOST },
{ "match", SOC_MATCH },
{ "hostname", SOC_HOSTNAME },
{ "port", SOC_PORT },
{ "user", SOC_USERNAME },
{ "identityfile", SOC_IDENTITY },
{ "ciphers", SOC_CIPHERS },
{ "macs", SOC_MACS },
{ "compression", SOC_COMPRESSION },
{ "connecttimeout", SOC_TIMEOUT },
{ "protocol", SOC_PROTOCOL },
@@ -97,96 +71,11 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "userknownhostsfile", SOC_KNOWNHOSTS },
{ "proxycommand", SOC_PROXYCOMMAND },
{ "gssapiserveridentity", SOC_GSSAPISERVERIDENTITY },
{ "gssapiclientidentity", SOC_GSSAPICLIENTIDENTITY },
{ "gssapiserveridentity", SOC_GSSAPICLIENTIDENTITY },
{ "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
{ "include", SOC_INCLUDE },
{ "bindaddress", SOC_BINDADDRESS},
{ "globalknownhostsfile", SOC_GLOBALKNOWNHOSTSFILE},
{ "loglevel", SOC_LOGLEVEL},
{ "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
{ "kexalgorithms", SOC_KEXALGORITHMS},
{ "mac", SOC_UNSUPPORTED}, /* SSHv1 */
{ "gssapiauthentication", SOC_GSSAPIAUTHENTICATION},
{ "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
{ "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
{ "pubkeyauthentication", SOC_PUBKEYAUTHENTICATION},
{ "addkeystoagent", SOC_UNSUPPORTED},
{ "addressfamily", SOC_UNSUPPORTED},
{ "batchmode", SOC_UNSUPPORTED},
{ "canonicaldomains", SOC_UNSUPPORTED},
{ "canonicalizefallbacklocal", SOC_UNSUPPORTED},
{ "canonicalizehostname", SOC_UNSUPPORTED},
{ "canonicalizemaxdots", SOC_UNSUPPORTED},
{ "canonicalizepermittedcnames", SOC_UNSUPPORTED},
{ "certificatefile", SOC_UNSUPPORTED},
{ "challengeresponseauthentication", SOC_UNSUPPORTED},
{ "checkhostip", SOC_UNSUPPORTED},
{ "cipher", SOC_UNSUPPORTED}, /* SSHv1 */
{ "compressionlevel", SOC_UNSUPPORTED}, /* SSHv1 */
{ "connectionattempts", SOC_UNSUPPORTED},
{ "enablesshkeysign", SOC_UNSUPPORTED},
{ "fingerprinthash", SOC_UNSUPPORTED},
{ "forwardagent", SOC_UNSUPPORTED},
{ "gssapikeyexchange", SOC_UNSUPPORTED},
{ "gssapirenewalforcesrekey", SOC_UNSUPPORTED},
{ "gssapitrustdns", SOC_UNSUPPORTED},
{ "hashknownhosts", SOC_UNSUPPORTED},
{ "hostbasedauthentication", SOC_UNSUPPORTED},
{ "hostbasedkeytypes", SOC_UNSUPPORTED},
{ "hostkeyalias", SOC_UNSUPPORTED},
{ "identitiesonly", SOC_UNSUPPORTED},
{ "identityagent", SOC_UNSUPPORTED},
{ "ipqos", SOC_UNSUPPORTED},
{ "kbdinteractivedevices", SOC_UNSUPPORTED},
{ "nohostauthenticationforlocalhost", SOC_UNSUPPORTED},
{ "numberofpasswordprompts", SOC_UNSUPPORTED},
{ "pkcs11provider", SOC_UNSUPPORTED},
{ "preferredauthentications", SOC_UNSUPPORTED},
{ "proxyjump", SOC_UNSUPPORTED},
{ "proxyusefdpass", SOC_UNSUPPORTED},
{ "pubkeyacceptedtypes", SOC_UNSUPPORTED},
{ "rekeylimit", SOC_UNSUPPORTED},
{ "remotecommand", SOC_UNSUPPORTED},
{ "revokedhostkeys", SOC_UNSUPPORTED},
{ "rhostsrsaauthentication", SOC_UNSUPPORTED},
{ "rsaauthentication", SOC_UNSUPPORTED}, /* SSHv1 */
{ "serveralivecountmax", SOC_UNSUPPORTED},
{ "serveraliveinterval", SOC_UNSUPPORTED},
{ "streamlocalbindmask", SOC_UNSUPPORTED},
{ "streamlocalbindunlink", SOC_UNSUPPORTED},
{ "syslogfacility", SOC_UNSUPPORTED},
{ "tcpkeepalive", SOC_UNSUPPORTED},
{ "updatehostkeys", SOC_UNSUPPORTED},
{ "useprivilegedport", SOC_UNSUPPORTED},
{ "verifyhostkeydns", SOC_UNSUPPORTED},
{ "visualhostkey", SOC_UNSUPPORTED},
{ "clearallforwardings", SOC_NA},
{ "controlmaster", SOC_NA},
{ "controlpersist", SOC_NA},
{ "controlpath", SOC_NA},
{ "dynamicforward", SOC_NA},
{ "escapechar", SOC_NA},
{ "exitonforwardfailure", SOC_NA},
{ "forwardx11", SOC_NA},
{ "forwardx11timeout", SOC_NA},
{ "forwardx11trusted", SOC_NA},
{ "gatewayports", SOC_NA},
{ "ignoreunknown", SOC_NA},
{ "localcommand", SOC_NA},
{ "localforward", SOC_NA},
{ "permitlocalcommand", SOC_NA},
{ "remoteforward", SOC_NA},
{ "requesttty", SOC_NA},
{ "sendenv", SOC_NA},
{ "tunnel", SOC_NA},
{ "tunneldevice", SOC_NA},
{ "xauthlocation", SOC_NA},
{ NULL, SOC_UNKNOWN }
{ NULL, SOC_UNSUPPORTED }
};
static int ssh_config_parse_line(ssh_session session, const char *line,
unsigned int count, int *parsing, int seen[]);
static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
int i;
@@ -196,7 +85,7 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
}
}
return SOC_UNKNOWN;
return SOC_UNSUPPORTED;
}
static char *ssh_config_get_cmd(char **str) {
@@ -251,9 +140,9 @@ out:
return r;
}
static long ssh_config_get_long(char **str, long notfound) {
static int ssh_config_get_int(char **str, int notfound) {
char *p, *endp;
long i;
int i;
p = ssh_config_get_token(str);
if (p && *p) {
@@ -295,63 +184,8 @@ static int ssh_config_get_yesno(char **str, int notfound) {
return notfound;
}
static void local_parse_file(ssh_session session, const char *filename, int *parsing, int seen[]) {
FILE *f;
char line[MAX_LINE_SIZE] = {0};
unsigned int count = 0;
if ((f = fopen(filename, "r")) == NULL) {
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
filename);
return;
}
SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s", filename);
while (fgets(line, sizeof(line), f)) {
count++;
if (ssh_config_parse_line(session, line, count, parsing, seen) < 0) {
fclose(f);
return;
}
}
fclose(f);
return;
}
#ifdef HAVE_GLOB
static void local_parse_glob(ssh_session session,
const char *fileglob,
int *parsing,
int seen[])
{
glob_t globbuf = {
.gl_flags = 0,
};
int rt;
u_int i;
rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
if (rt == GLOB_NOMATCH) {
globfree(&globbuf);
return;
} else if (rt != 0) {
SSH_LOG(SSH_LOG_RARE, "Glob error: %s",
fileglob);
globfree(&globbuf);
return;
}
for (i = 0; i < globbuf.gl_pathc; i++) {
local_parse_file(session, globbuf.gl_pathv[i], parsing, seen);
}
globfree(&globbuf);
}
#endif /* HAVE_GLOB */
static int ssh_config_parse_line(ssh_session session, const char *line,
unsigned int count, int *parsing, int seen[]) {
unsigned int count, int *parsing) {
enum ssh_config_opcode_e opcode;
const char *p;
char *s, *x;
@@ -359,7 +193,6 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
char *lowerhost;
size_t len;
int i;
long l;
x = s = strdup(line);
if (s == NULL) {
@@ -383,63 +216,42 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
opcode = ssh_config_get_opcode(keyword);
if (*parsing == 1 && opcode != SOC_HOST && opcode != SOC_UNSUPPORTED && opcode != SOC_INCLUDE) {
if (seen[opcode] != 0) {
SAFE_FREE(x);
return 0;
}
seen[opcode] = 1;
}
switch (opcode) {
case SOC_INCLUDE: /* recursive include of other files */
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
#ifdef HAVE_GLOB
local_parse_glob(session, p, parsing, seen);
#else
local_parse_file(session, p, parsing, seen);
#endif /* HAVE_GLOB */
}
break;
case SOC_HOST: {
int ok = 0;
case SOC_HOST:
*parsing = 0;
lowerhost = (session->opts.host) ? ssh_lowercase(session->opts.host) : NULL;
for (p = ssh_config_get_str_tok(&s, NULL);
p != NULL && p[0] != '\0';
p = ssh_config_get_str_tok(&s, NULL)) {
if (ok >= 0) {
ok = match_hostname(lowerhost, p, strlen(p));
if (ok < 0) {
*parsing = 0;
} else if (ok > 0) {
*parsing = 1;
}
char *z = ssh_path_expand_escape(session, p);
int ok;
if (z == NULL) {
z = strdup(p);
}
ok = match_hostname(lowerhost, z, strlen(z));
if (ok) {
*parsing = 1;
}
free(z);
}
SAFE_FREE(lowerhost);
break;
}
case SOC_HOSTNAME:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
char *z = ssh_path_expand_escape(session, p);
if (z == NULL) {
z = strdup(p);
}
ssh_options_set(session, SSH_OPTIONS_HOST, z);
free(z);
ssh_options_set(session, SSH_OPTIONS_HOST, p);
}
break;
case SOC_PORT:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
}
break;
if (session->opts.port == 0) {
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
}
}
break;
case SOC_USERNAME:
if (session->opts.username == NULL) {
p = ssh_config_get_str_tok(&s, NULL);
@@ -461,13 +273,6 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, p);
}
break;
case SOC_MACS:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, p);
ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, p);
}
break;
case SOC_COMPRESSION:
i = ssh_config_get_yesno(&s, -1);
if (i >= 0 && *parsing) {
@@ -489,11 +294,14 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
return -1;
}
i = 0;
ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
ssh_options_set(session, SSH_OPTIONS_SSH2, &i);
for (a = strtok(b, ","); a; a = strtok(NULL, ",")) {
switch (atoi(a)) {
case 1:
i = 1;
ssh_options_set(session, SSH_OPTIONS_SSH1, &i);
break;
case 2:
i = 1;
@@ -507,9 +315,9 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
break;
case SOC_TIMEOUT:
l = ssh_config_get_long(&s, -1);
if (l >= 0 && *parsing) {
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &l);
i = ssh_config_get_int(&s, -1);
if (i >= 0 && *parsing) {
ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &i);
}
break;
case SOC_STRICTHOSTKEYCHECK:
@@ -548,94 +356,12 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
ssh_options_set(session, SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, &i);
}
break;
case SOC_BINDADDRESS:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_BINDADDR, p);
}
break;
case SOC_GLOBALKNOWNHOSTSFILE:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, p);
}
break;
case SOC_LOGLEVEL:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
int value = -1;
if (strcasecmp(p, "quiet") == 0) {
value = SSH_LOG_NONE;
} else if (strcasecmp(p, "fatal") == 0 ||
strcasecmp(p, "error")== 0 ||
strcasecmp(p, "info") == 0) {
value = SSH_LOG_WARN;
} else if (strcasecmp(p, "verbose") == 0) {
value = SSH_LOG_INFO;
} else if (strcasecmp(p, "DEBUG") == 0 ||
strcasecmp(p, "DEBUG1") == 0) {
value = SSH_LOG_DEBUG;
} else if (strcasecmp(p, "DEBUG2") == 0 ||
strcasecmp(p, "DEBUG3") == 0) {
value = SSH_LOG_TRACE;
}
if (value != -1) {
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &value);
}
}
break;
case SOC_HOSTKEYALGORITHMS:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, p);
}
break;
case SOC_KEXALGORITHMS:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
}
break;
case SOC_GSSAPIAUTHENTICATION:
case SOC_KBDINTERACTIVEAUTHENTICATION:
case SOC_PASSWORDAUTHENTICATION:
case SOC_PUBKEYAUTHENTICATION:
i = ssh_config_get_yesno(&s, 0);
if (i>=0 && *parsing) {
switch(opcode){
case SOC_GSSAPIAUTHENTICATION:
ssh_options_set(session, SSH_OPTIONS_GSSAPI_AUTH, &i);
break;
case SOC_KBDINTERACTIVEAUTHENTICATION:
ssh_options_set(session, SSH_OPTIONS_KBDINT_AUTH, &i);
break;
case SOC_PASSWORDAUTHENTICATION:
ssh_options_set(session, SSH_OPTIONS_PASSWORD_AUTH, &i);
break;
case SOC_PUBKEYAUTHENTICATION:
ssh_options_set(session, SSH_OPTIONS_PUBKEY_AUTH, &i);
break;
/* make gcc happy */
default:
break;
}
}
break;
case SOC_NA:
SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d\n",
keyword, count);
break;
case SOC_UNSUPPORTED:
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d",
keyword, count);
break;
case SOC_UNKNOWN:
SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d\n",
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d\n",
keyword, count);
break;
default:
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d\n",
opcode);
SAFE_FREE(x);
return -1;
@@ -648,11 +374,10 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
/* ssh_config_parse_file */
int ssh_config_parse_file(ssh_session session, const char *filename) {
char line[MAX_LINE_SIZE] = {0};
char line[1024] = {0};
unsigned int count = 0;
FILE *f;
int parsing;
int seen[SOC_END - SOC_UNSUPPORTED] = {0};
if ((f = fopen(filename, "r")) == NULL) {
return 0;
@@ -663,7 +388,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) {
parsing = 1;
while (fgets(line, sizeof(line), f)) {
count++;
if (ssh_config_parse_line(session, line, count, &parsing, seen) < 0) {
if (ssh_config_parse_line(session, line, count, &parsing) < 0) {
fclose(f);
return -1;
}

View File

@@ -74,7 +74,6 @@
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif /* _WIN32 */
@@ -204,7 +203,7 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host,
}
/* s is connected ? */
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout");
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout\n");
ret = ssh_socket_set_blocking(s);
if (ret < 0) {
ssh_set_error(session, SSH_FATAL,
@@ -217,12 +216,6 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host,
return s;
}
static int set_tcp_nodelay(socket_t socket)
{
int opt = 1;
return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
}
/**
* @internal
*
@@ -259,7 +252,7 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
struct addrinfo *bind_ai;
struct addrinfo *bind_itr;
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
SSH_LOG(SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
rc = getai(bind_addr, 0, &bind_ai);
if (rc != 0) {
@@ -353,7 +346,7 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
struct addrinfo *bind_ai;
struct addrinfo *bind_itr;
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
SSH_LOG(SSH_LOG_PACKET, "Resolving %s\n", bind_addr);
rc = getai(bind_addr, 0, &bind_ai);
if (rc != 0) {
@@ -394,18 +387,6 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
continue;
}
if (session->opts.nodelay) {
/* For winsock, socket options are only effective before connect */
rc = set_tcp_nodelay(s);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to set TCP_NODELAY on socket: %s", strerror(errno));
ssh_connect_socket_close(s);
s = -1;
continue;
}
}
errno = 0;
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
@@ -537,3 +518,5 @@ out:
}
/** @} */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -1,636 +0,0 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2015 by Aris Adamantiadis <aris@badcode.be>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/priv.h"
#include "libssh/poll.h"
#include "libssh/callbacks.h"
#include "libssh/session.h"
#include <stdlib.h>
#define CHUNKSIZE 4096
#ifdef _WIN32
# ifdef HAVE_IO_H
# include <io.h>
# undef open
# define open _open
# undef close
# define close _close
# undef read
# define read _read
# undef unlink
# define unlink _unlink
# endif /* HAVE_IO_H */
#endif
struct ssh_connector_struct {
ssh_session session;
ssh_channel in_channel;
ssh_channel out_channel;
socket_t in_fd;
socket_t out_fd;
ssh_poll_handle in_poll;
ssh_poll_handle out_poll;
ssh_event event;
int in_available;
int out_wontblock;
struct ssh_channel_callbacks_struct in_channel_cb;
struct ssh_channel_callbacks_struct out_channel_cb;
enum ssh_connector_flags_e in_flags;
enum ssh_connector_flags_e out_flags;
};
static int ssh_connector_channel_data_cb(ssh_session session,
ssh_channel channel,
void *data,
uint32_t len,
int is_stderr,
void *userdata);
static int ssh_connector_channel_write_wontblock_cb(ssh_session session,
ssh_channel channel,
size_t bytes,
void *userdata);
ssh_connector ssh_connector_new(ssh_session session)
{
ssh_connector connector;
connector = calloc(1, sizeof(struct ssh_connector_struct));
if (connector == NULL){
ssh_set_error_oom(session);
return NULL;
}
connector->session = session;
connector->in_fd = SSH_INVALID_SOCKET;
connector->out_fd = SSH_INVALID_SOCKET;
ssh_callbacks_init(&connector->in_channel_cb);
ssh_callbacks_init(&connector->out_channel_cb);
connector->in_channel_cb.userdata = connector;
connector->in_channel_cb.channel_data_function = ssh_connector_channel_data_cb;
connector->out_channel_cb.userdata = connector;
connector->out_channel_cb.channel_write_wontblock_function =
ssh_connector_channel_write_wontblock_cb;
return connector;
}
void ssh_connector_free (ssh_connector connector)
{
if (connector->in_channel != NULL) {
ssh_remove_channel_callbacks(connector->in_channel,
&connector->in_channel_cb);
}
if (connector->out_channel != NULL) {
ssh_remove_channel_callbacks(connector->out_channel,
&connector->out_channel_cb);
}
if (connector->event != NULL){
ssh_connector_remove_event(connector);
}
if (connector->in_poll != NULL) {
ssh_poll_free(connector->in_poll);
connector->in_poll = NULL;
}
if (connector->out_poll != NULL) {
ssh_poll_free(connector->out_poll);
connector->out_poll = NULL;
}
free(connector);
}
int ssh_connector_set_in_channel(ssh_connector connector,
ssh_channel channel,
enum ssh_connector_flags_e flags)
{
connector->in_channel = channel;
connector->in_fd = SSH_INVALID_SOCKET;
connector->in_flags = flags;
/* Fallback to default value for invalid flags */
if (!(flags & SSH_CONNECTOR_STDOUT) && !(flags & SSH_CONNECTOR_STDERR)) {
connector->in_flags = SSH_CONNECTOR_STDOUT;
}
return ssh_add_channel_callbacks(channel, &connector->in_channel_cb);
}
int ssh_connector_set_out_channel(ssh_connector connector,
ssh_channel channel,
enum ssh_connector_flags_e flags)
{
connector->out_channel = channel;
connector->out_fd = SSH_INVALID_SOCKET;
connector->out_flags = flags;
/* Fallback to default value for invalid flags */
if (!(flags & SSH_CONNECTOR_STDOUT) && !(flags & SSH_CONNECTOR_STDERR)) {
connector->in_flags = SSH_CONNECTOR_STDOUT;
}
return ssh_add_channel_callbacks(channel, &connector->out_channel_cb);
}
void ssh_connector_set_in_fd(ssh_connector connector, socket_t fd)
{
connector->in_fd = fd;
connector->in_channel = NULL;
}
void ssh_connector_set_out_fd(ssh_connector connector, socket_t fd)
{
connector->out_fd = fd;
connector->out_channel = NULL;
}
/* TODO */
static void ssh_connector_except(ssh_connector connector, socket_t fd)
{
(void) connector;
(void) fd;
}
/* TODO */
static void ssh_connector_except_channel(ssh_connector connector,
ssh_channel channel)
{
(void) connector;
(void) channel;
}
/**
* @internal
*
* @brief Reset the poll events to be followed for each file descriptors.
*/
static void ssh_connector_reset_pollevents(ssh_connector connector)
{
if (connector->in_fd != SSH_INVALID_SOCKET) {
if (connector->in_available) {
ssh_poll_remove_events(connector->in_poll, POLLIN);
} else {
ssh_poll_add_events(connector->in_poll, POLLIN);
}
}
if (connector->out_fd != SSH_INVALID_SOCKET) {
if (connector->out_wontblock) {
ssh_poll_remove_events(connector->out_poll, POLLOUT);
} else {
ssh_poll_add_events(connector->out_poll, POLLOUT);
}
}
}
/**
* @internal
*
* @brief Callback called when a poll event is received on an input fd.
*/
static void ssh_connector_fd_in_cb(ssh_connector connector)
{
unsigned char buffer[CHUNKSIZE];
int r;
int toread = CHUNKSIZE;
int w;
int total = 0;
int rc;
SSH_LOG(SSH_LOG_TRACE, "connector POLLIN event for fd %d", connector->in_fd);
if (connector->out_wontblock) {
if (connector->out_channel != NULL) {
size_t size = ssh_channel_window_size(connector->out_channel);
/* Don't attempt reading more than the window */
toread = MIN(size, CHUNKSIZE);
}
r = read(connector->in_fd, buffer, toread);
if (r < 0) {
ssh_connector_except(connector, connector->in_fd);
return;
}
if (connector->out_channel != NULL) {
if (r == 0) {
rc = ssh_channel_send_eof(connector->out_channel);
(void)rc; /* TODO Handle rc? */
} else if (r> 0) {
/* loop around ssh_channel_write in case our window reduced due to a race */
while (total != r){
if (connector->out_flags & SSH_CONNECTOR_STDOUT) {
w = ssh_channel_write(connector->out_channel,
buffer + total,
r - total);
} else {
w = ssh_channel_write_stderr(connector->out_channel,
buffer + total,
r - total);
}
if (w == SSH_ERROR) {
return;
}
total += w;
}
}
} else if (connector->out_fd != SSH_INVALID_SOCKET) {
if (r == 0){
close (connector->out_fd);
connector->out_fd = SSH_INVALID_SOCKET;
} else {
/*
* Loop around write in case the write blocks even for CHUNKSIZE
* bytes
*/
while (total != r) {
w = write(connector->out_fd, buffer + total, r - total);
if (w < 0){
ssh_connector_except(connector, connector->out_fd);
return;
}
total += w;
}
}
} else {
ssh_set_error(connector->session, SSH_FATAL, "output socket or channel closed");
return;
}
connector->out_wontblock = 0;
connector->in_available = 0;
} else {
connector->in_available = 1;
}
}
/** @internal
* @brief Callback called when a poll event is received on an output fd
*/
static void ssh_connector_fd_out_cb(ssh_connector connector){
unsigned char buffer[CHUNKSIZE];
int r;
int w;
int total = 0;
SSH_LOG(SSH_LOG_TRACE, "connector POLLOUT event for fd %d", connector->out_fd);
if(connector->in_available){
if (connector->in_channel != NULL){
r = ssh_channel_read_nonblocking(connector->in_channel, buffer, CHUNKSIZE, 0);
if(r == SSH_ERROR){
ssh_connector_except_channel(connector, connector->in_channel);
return;
} else if(r == 0 && ssh_channel_is_eof(connector->in_channel)){
close(connector->out_fd);
connector->out_fd = SSH_INVALID_SOCKET;
return;
} else if(r>0) {
/* loop around write in case the write blocks even for CHUNKSIZE bytes */
while (total != r){
w = write(connector->out_fd, buffer + total, r - total);
if (w < 0){
ssh_connector_except(connector, connector->out_fd);
return;
}
total += w;
}
}
} else if (connector->in_fd != SSH_INVALID_SOCKET){
/* fallback on the socket input callback */
connector->out_wontblock = 1;
ssh_connector_fd_in_cb(connector);
} else {
ssh_set_error(connector->session,
SSH_FATAL,
"Output socket or channel closed");
return;
}
connector->in_available = 0;
connector->out_wontblock = 0;
} else {
connector->out_wontblock = 1;
}
}
/**
* @internal
*
* @brief Callback called when a poll event is received on a file descriptor.
*
* This is for (input or output.
*
* @param[in] fd file descriptor receiving the event
*
* @param[in] revents received Poll(2) events
*
* @param[in] userdata connector
*
* @returns 0
*/
static int ssh_connector_fd_cb(ssh_poll_handle p,
socket_t fd,
int revents,
void *userdata)
{
ssh_connector connector = userdata;
(void)p;
if (revents & POLLERR) {
ssh_connector_except(connector, fd);
} else if((revents & (POLLIN|POLLHUP)) && fd == connector->in_fd) {
ssh_connector_fd_in_cb(connector);
} else if(((revents & POLLOUT) || (revents & POLLHUP)) &&
fd == connector->out_fd) {
ssh_connector_fd_out_cb(connector);
}
ssh_connector_reset_pollevents(connector);
return 0;
}
/**
* @internal
*
* @brief Callback called when data is received on channel.
*
* @param[in] data Pointer to the data
*
* @param[in] len Length of data
*
* @param[in] is_stderr Set to 1 if the data are out of band
*
* @param[in] userdata The ssh connector
*
* @returns Amount of data bytes consumed
*/
static int ssh_connector_channel_data_cb(ssh_session session,
ssh_channel channel,
void *data,
uint32_t len,
int is_stderr,
void *userdata)
{
ssh_connector connector = userdata;
int w;
size_t window;
(void) session;
(void) channel;
(void) is_stderr;
SSH_LOG(SSH_LOG_TRACE,"connector data on channel");
if (is_stderr && !(connector->in_flags & SSH_CONNECTOR_STDERR)) {
/* ignore stderr */
return 0;
} else if (!is_stderr && !(connector->in_flags & SSH_CONNECTOR_STDOUT)) {
/* ignore stdout */
return 0;
}
if (connector->out_wontblock) {
if (connector->out_channel != NULL) {
int window_len;
window = ssh_channel_window_size(connector->out_channel);
window_len = MIN(window, len);
/* Route the data to the right exception channel */
if (is_stderr && (connector->out_flags & SSH_CONNECTOR_STDERR)) {
w = ssh_channel_write_stderr(connector->out_channel,
data,
window_len);
} else if (!is_stderr &&
(connector->out_flags & SSH_CONNECTOR_STDOUT)) {
w = ssh_channel_write(connector->out_channel,
data,
window_len);
} else if (connector->out_flags & SSH_CONNECTOR_STDOUT) {
w = ssh_channel_write(connector->out_channel,
data,
window_len);
} else {
w = ssh_channel_write_stderr(connector->out_channel,
data,
window_len);
}
if (w == SSH_ERROR) {
ssh_connector_except_channel(connector, connector->out_channel);
}
} else if (connector->out_fd != SSH_INVALID_SOCKET) {
w = write(connector->out_fd, data, len);
if (w < 0)
ssh_connector_except(connector, connector->out_fd);
} else {
ssh_set_error(session, SSH_FATAL, "output socket or channel closed");
return SSH_ERROR;
}
connector->out_wontblock = 0;
connector->in_available = 0;
if ((unsigned int)w < len) {
connector->in_available = 1;
}
ssh_connector_reset_pollevents(connector);
return w;
} else {
connector->in_available = 1;
return 0;
}
}
/**
* @internal
*
* @brief Callback called when the channel is free to write.
*
* @param[in] bytes Amount of bytes that can be written without blocking
*
* @param[in] userdata The ssh connector
*
* @returns Amount of data bytes consumed
*/
static int ssh_connector_channel_write_wontblock_cb(ssh_session session,
ssh_channel channel,
size_t bytes,
void *userdata)
{
ssh_connector connector = userdata;
uint8_t buffer[CHUNKSIZE];
int r, w;
(void) channel;
SSH_LOG(SSH_LOG_TRACE, "Channel write won't block");
if (connector->in_available) {
if (connector->in_channel != NULL) {
size_t len = MIN(CHUNKSIZE, bytes);
r = ssh_channel_read_nonblocking(connector->in_channel,
buffer,
len,
0);
if (r == SSH_ERROR) {
ssh_connector_except_channel(connector, connector->in_channel);
} else if(r == 0 && ssh_channel_is_eof(connector->in_channel)){
ssh_channel_send_eof(connector->out_channel);
} else if (r > 0) {
w = ssh_channel_write(connector->out_channel, buffer, r);
if (w == SSH_ERROR) {
ssh_connector_except_channel(connector,
connector->out_channel);
}
}
} else if (connector->in_fd != SSH_INVALID_SOCKET) {
/* fallback on on the socket input callback */
connector->out_wontblock = 1;
ssh_connector_fd_in_cb(connector);
ssh_connector_reset_pollevents(connector);
} else {
ssh_set_error(session,
SSH_FATAL,
"Output socket or channel closed");
return 0;
}
connector->in_available = 0;
connector->out_wontblock = 0;
} else {
connector->out_wontblock = 1;
}
return 0;
}
int ssh_connector_set_event(ssh_connector connector, ssh_event event)
{
int rc = SSH_OK;
if ((connector->in_fd == SSH_INVALID_SOCKET &&
connector->in_channel == NULL)
|| (connector->out_fd == SSH_INVALID_SOCKET &&
connector->out_channel == NULL)) {
rc = SSH_ERROR;
ssh_set_error(connector->session,SSH_FATAL,"Connector not complete");
goto error;
}
connector->event = event;
if (connector->in_fd != SSH_INVALID_SOCKET) {
if (connector->in_poll == NULL) {
connector->in_poll = ssh_poll_new(connector->in_fd,
POLLIN|POLLERR,
ssh_connector_fd_cb,
connector);
}
rc = ssh_event_add_poll(event, connector->in_poll);
if (rc != SSH_OK) {
goto error;
}
}
if (connector->out_fd != SSH_INVALID_SOCKET) {
if (connector->out_poll == NULL) {
connector->out_poll = ssh_poll_new(connector->out_fd,
POLLOUT|POLLERR,
ssh_connector_fd_cb,
connector);
}
rc = ssh_event_add_poll(event, connector->out_poll);
if (rc != SSH_OK) {
goto error;
}
}
if (connector->in_channel != NULL) {
rc = ssh_event_add_session(event,
ssh_channel_get_session(connector->in_channel));
if (rc != SSH_OK)
goto error;
if (ssh_channel_poll_timeout(connector->in_channel, 0, 0) > 0){
connector->in_available = 1;
}
}
if(connector->out_channel != NULL) {
ssh_session session = ssh_channel_get_session(connector->out_channel);
rc = ssh_event_add_session(event, session);
if (rc != SSH_OK) {
goto error;
}
if (ssh_channel_window_size(connector->out_channel) > 0) {
connector->out_wontblock = 1;
}
}
error:
return rc;
}
int ssh_connector_remove_event(ssh_connector connector) {
ssh_session session;
if (connector->in_poll != NULL) {
ssh_event_remove_poll(connector->event, connector->in_poll);
ssh_poll_free(connector->in_poll);
connector->in_poll = NULL;
}
if (connector->out_poll != NULL) {
ssh_event_remove_poll(connector->event, connector->out_poll);
ssh_poll_free(connector->out_poll);
connector->out_poll = NULL;
}
if (connector->in_channel != NULL) {
session = ssh_channel_get_session(connector->in_channel);
ssh_event_remove_session(connector->event, session);
connector->in_channel = NULL;
}
if (connector->out_channel != NULL) {
session = ssh_channel_get_session(connector->out_channel);
ssh_event_remove_session(connector->event, session);
connector->out_channel = NULL;
}
connector->event = NULL;
return SSH_OK;
}

95
src/crc32.c Normal file
View File

@@ -0,0 +1,95 @@
/*
* crc32.c - simple CRC32 code
*
* This file is part of the SSH Library
*
* Copyright (c) 2005 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/priv.h"
#include "libssh/crc32.h"
static uint32_t crc_table[] = {
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
0x2d02ef8dUL
};
uint32_t ssh_crc32(const char *buf, uint32_t len) {
uint32_t ret = 0;
while(len > 0) {
ret = crc_table[(ret ^ *buf) & 0xff] ^ (ret >> 8);
--len;
++buf;
}
return ret;
}
/* vim: set ts=2 sw=2 et cindent: */

View File

@@ -1,6 +1,6 @@
/*
* curve25519.c - Curve25519 ECDH functions for key exchange
* curve25519-sha256@libssh.org and curve25519-sha256
* curve25519-sha256@libssh.org
*
* This file is part of the SSH Library
*
@@ -40,14 +40,13 @@
#include "libssh/bignum.h"
/** @internal
* @brief Starts curve25519-sha256@libssh.org / curve25519-sha256 key exchange
* @brief Starts curve25519-sha256@libssh.org key exchange
*/
int ssh_client_curve25519_init(ssh_session session){
int rc;
int ok;
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (!ok) {
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (rc == 0){
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
@@ -65,27 +64,18 @@ int ssh_client_curve25519_init(ssh_session session){
return SSH_ERROR;
}
rc = ssh_packet_send(session);
rc = packet_send(session);
return rc;
}
static int ssh_curve25519_build_k(ssh_session session) {
ssh_curve25519_pubkey k;
#ifdef HAVE_LIBCRYPTO
session->next_crypto->k = bignum_new();
if (session->next_crypto->k == NULL) {
return SSH_ERROR;
}
#elif defined HAVE_LIBMBEDCRYPTO
session->next_crypto->k = bignum_new();
if (session->next_crypto->k == NULL) {
return SSH_ERROR;
}
#endif
if (session->server)
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
@@ -94,13 +84,7 @@ static int ssh_curve25519_build_k(ssh_session session) {
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_server_pubkey);
#ifdef HAVE_LIBGCRYPT
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->k);
#elif defined HAVE_LIBCRYPTO
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
#elif defined HAVE_LIBMBEDCRYPTO
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
#endif
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Session server cookie",
@@ -119,26 +103,19 @@ static int ssh_curve25519_build_k(ssh_session session) {
*/
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
ssh_string q_s_string = NULL;
ssh_string pubkey_blob = NULL;
ssh_string pubkey = NULL;
ssh_string signature = NULL;
int rc;
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
pubkey = buffer_get_ssh_string(packet);
if (pubkey == NULL){
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
/* this is the server host key */
session->next_crypto->server_pubkey = pubkey;
pubkey = NULL;
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
ssh_string_free(pubkey_blob);
if (rc != 0) {
ssh_set_error(session,
SSH_FATAL,
"Failed to import next public key");
goto error;
}
q_s_string = ssh_buffer_get_ssh_string(packet);
q_s_string = buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
goto error;
@@ -152,7 +129,7 @@ int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE);
ssh_string_free(q_s_string);
signature = ssh_buffer_get_ssh_string(packet);
signature = buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
@@ -166,11 +143,11 @@ int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
}
/* Send the MSG_NEWKEYS */
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=ssh_packet_send(session);
rc=packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
error:
@@ -186,16 +163,14 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
/* ECDH keys */
ssh_string q_c_string;
ssh_string q_s_string;
ssh_string server_pubkey_blob = NULL;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
int ok;
int rc;
/* Extract the client pubkey from the init packet */
q_c_string = ssh_buffer_get_ssh_string(packet);
q_c_string = buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
return SSH_ERROR;
@@ -212,8 +187,8 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
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) {
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (rc == 0){
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
@@ -221,7 +196,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
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);
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
@@ -240,22 +215,15 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
goto error;
}
rc = ssh_make_sessionid(session);
rc = make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
goto error;
}
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL, "Could not export server public key");
goto error;
}
/* add host's public key */
rc = ssh_buffer_add_ssh_string(session->out_buffer,
server_pubkey_blob);
ssh_string_free(server_pubkey_blob);
rc = buffer_add_ssh_string(session->out_buffer,
session->next_crypto->server_pubkey);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
@@ -271,7 +239,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
rc = ssh_buffer_add_ssh_string(session->out_buffer, q_s_string);
rc = buffer_add_ssh_string(session->out_buffer, q_s_string);
ssh_string_free(q_s_string);
if (rc < 0) {
ssh_set_error_oom(session);
@@ -284,7 +252,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
goto error;
}
rc = ssh_buffer_add_ssh_string(session->out_buffer, sig_blob);
rc = buffer_add_ssh_string(session->out_buffer, sig_blob);
ssh_string_free(sig_blob);
if (rc < 0) {
ssh_set_error_oom(session);
@@ -292,19 +260,19 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent");
rc = ssh_packet_send(session);
rc = packet_send(session);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
/* Send the MSG_NEWKEYS */
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
goto error;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = ssh_packet_send(session);
rc = packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;

469
src/dh.c
View File

@@ -68,7 +68,6 @@
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include "libssh/libcrypto.h"
#endif
static unsigned char p_group1_value[] = {
@@ -116,102 +115,128 @@ static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */
static bignum g;
static bignum p_group1;
static bignum p_group14;
static int dh_crypto_initialized;
static int ssh_crypto_initialized;
static bignum select_p(enum ssh_key_exchange_e type) {
return type == SSH_KEX_DH_GROUP14_SHA1 ? p_group14 : p_group1;
}
/**
* @internal
* @brief Initialize global constants used in DH key agreement
* @return SSH_OK on success, SSH_ERROR otherwise.
int ssh_get_random(void *where, int len, int strong){
#ifdef HAVE_LIBGCRYPT
/* variable not used in gcrypt */
(void) strong;
/* not using GCRY_VERY_STRONG_RANDOM which is a bit overkill */
gcry_randomize(where,len,GCRY_STRONG_RANDOM);
return 1;
#elif defined HAVE_LIBCRYPTO
if (strong) {
return RAND_bytes(where,len);
} else {
return RAND_pseudo_bytes(where,len);
}
#endif
/* never reached */
return 1;
}
/*
* This inits the values g and p which are used for DH key agreement
* FIXME: Make the function thread safe by adding a semaphore or mutex.
*/
int ssh_dh_init(void)
{
if (dh_crypto_initialized) {
return SSH_OK;
int ssh_crypto_init(void) {
if (ssh_crypto_initialized == 0) {
#ifdef HAVE_LIBGCRYPT
gcry_check_version(NULL);
if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P,0)) {
gcry_control(GCRYCTL_INIT_SECMEM, 4096);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED,0);
}
#endif
g = bignum_new();
if (g == NULL) {
return SSH_ERROR;
return -1;
}
bignum_set_word(g,g_int);
#if defined(HAVE_LIBGCRYPT)
#ifdef HAVE_LIBGCRYPT
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, &p_group1);
if (p_group1 == NULL) {
bignum_safe_free(g);
return SSH_ERROR;
bignum_free(g);
g = NULL;
return -1;
}
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14);
if (p_group14 == NULL) {
bignum_safe_free(g);
bignum_safe_free(p_group1);
return SSH_ERROR;
bignum_free(g);
bignum_free(p_group1);
g = NULL;
p_group1 = NULL;
return -1;
}
#elif defined(HAVE_LIBCRYPTO)
#elif defined HAVE_LIBCRYPTO
p_group1 = bignum_new();
if (p_group1 == NULL) {
bignum_safe_free(g);
return SSH_ERROR;
bignum_free(g);
g = NULL;
return -1;
}
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
p_group14 = bignum_new();
if (p_group14 == NULL) {
bignum_safe_free(g);
bignum_safe_free(p_group1);
return SSH_ERROR;
bignum_free(g);
bignum_free(p_group1);
g = NULL;
p_group1 = NULL;
return -1;
}
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
#elif defined(HAVE_LIBMBEDCRYPTO)
p_group1 = bignum_new();
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
p_group14 = bignum_new();
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
OpenSSL_add_all_algorithms();
#endif
dh_crypto_initialized = 1;
return 0;
}
/**
* @internal
* @brief Finalize and free global constants used in DH key agreement
*/
void ssh_dh_finalize(void)
{
if (!dh_crypto_initialized) {
return;
}
bignum_safe_free(g);
bignum_safe_free(p_group1);
bignum_safe_free(p_group14);
dh_crypto_initialized = 0;
}
int ssh_dh_generate_x(ssh_session session) {
int keysize;
if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1) {
keysize = 1023;
} else {
keysize = 2047;
ssh_crypto_initialized = 1;
}
return 0;
}
void ssh_crypto_finalize(void) {
if (ssh_crypto_initialized) {
bignum_free(g);
g = NULL;
bignum_free(p_group1);
p_group1 = NULL;
bignum_free(p_group14);
p_group14 = NULL;
#ifdef HAVE_LIBGCRYPT
gcry_control(GCRYCTL_TERM_SECMEM);
#elif defined HAVE_LIBCRYPTO
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#endif
ssh_crypto_initialized=0;
}
}
int dh_generate_x(ssh_session session) {
session->next_crypto->x = bignum_new();
if (session->next_crypto->x == NULL) {
return -1;
}
bignum_rand(session->next_crypto->x, keysize);
#ifdef HAVE_LIBGCRYPT
bignum_rand(session->next_crypto->x, 128);
#elif defined HAVE_LIBCRYPTO
bignum_rand(session->next_crypto->x, 128, 0, -1);
#endif
/* not harder than this */
#ifdef DEBUG_CRYPTO
@@ -222,19 +247,17 @@ int ssh_dh_generate_x(ssh_session session) {
}
/* used by server */
int ssh_dh_generate_y(ssh_session session) {
int keysize;
if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1) {
keysize = 1023;
} else {
keysize = 2047;
}
session->next_crypto->y = bignum_new();
int dh_generate_y(ssh_session session) {
session->next_crypto->y = bignum_new();
if (session->next_crypto->y == NULL) {
return -1;
}
bignum_rand(session->next_crypto->y, keysize);
#ifdef HAVE_LIBGCRYPT
bignum_rand(session->next_crypto->y, 128);
#elif defined HAVE_LIBCRYPTO
bignum_rand(session->next_crypto->y, 128, 0, -1);
#endif
/* not harder than this */
#ifdef DEBUG_CRYPTO
@@ -245,7 +268,7 @@ int ssh_dh_generate_y(ssh_session session) {
}
/* used by server */
int ssh_dh_generate_e(ssh_session session) {
int dh_generate_e(ssh_session session) {
#ifdef HAVE_LIBCRYPTO
bignum_CTX ctx = bignum_ctx_new();
if (ctx == NULL) {
@@ -267,9 +290,6 @@ int ssh_dh_generate_e(ssh_session session) {
#elif defined HAVE_LIBCRYPTO
bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
select_p(session->next_crypto->kex_type), ctx);
#elif defined HAVE_LIBMBEDCRYPTO
bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
select_p(session->next_crypto->kex_type), NULL);
#endif
#ifdef DEBUG_CRYPTO
@@ -283,7 +303,7 @@ int ssh_dh_generate_e(ssh_session session) {
return 0;
}
int ssh_dh_generate_f(ssh_session session) {
int dh_generate_f(ssh_session session) {
#ifdef HAVE_LIBCRYPTO
bignum_CTX ctx = bignum_ctx_new();
if (ctx == NULL) {
@@ -305,9 +325,6 @@ int ssh_dh_generate_f(ssh_session session) {
#elif defined HAVE_LIBCRYPTO
bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
select_p(session->next_crypto->kex_type), ctx);
#elif defined HAVE_LIBMBEDCRYPTO
bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
select_p(session->next_crypto->kex_type), NULL);
#endif
#ifdef DEBUG_CRYPTO
@@ -321,30 +338,21 @@ int ssh_dh_generate_f(ssh_session session) {
return 0;
}
ssh_string ssh_dh_get_e(ssh_session session) {
return ssh_make_bignum_string(session->next_crypto->e);
ssh_string dh_get_e(ssh_session session) {
return make_bignum_string(session->next_crypto->e);
}
/* used by server */
ssh_string ssh_dh_get_f(ssh_session session) {
return ssh_make_bignum_string(session->next_crypto->f);
ssh_string dh_get_f(ssh_session session) {
return make_bignum_string(session->next_crypto->f);
}
int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
{
return ssh_pki_import_pubkey_blob(pubkey_blob,
&session->current_crypto->server_pubkey);
void dh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
session->next_crypto->server_pubkey = pubkey_string;
}
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
{
return ssh_pki_import_pubkey_blob(pubkey_blob,
&session->next_crypto->server_pubkey);
}
int ssh_dh_import_f(ssh_session session, ssh_string f_string) {
session->next_crypto->f = ssh_make_string_bn(f_string);
int dh_import_f(ssh_session session, ssh_string f_string) {
session->next_crypto->f = make_string_bn(f_string);
if (session->next_crypto->f == NULL) {
return -1;
}
@@ -357,8 +365,8 @@ int ssh_dh_import_f(ssh_session session, ssh_string f_string) {
}
/* used by the server implementation */
int ssh_dh_import_e(ssh_session session, ssh_string e_string) {
session->next_crypto->e = ssh_make_string_bn(e_string);
int dh_import_e(ssh_session session, ssh_string e_string) {
session->next_crypto->e = make_string_bn(e_string);
if (session->next_crypto->e == NULL) {
return -1;
}
@@ -370,7 +378,7 @@ int ssh_dh_import_e(ssh_session session, ssh_string e_string) {
return 0;
}
int ssh_dh_build_k(ssh_session session) {
int dh_build_k(ssh_session session) {
#ifdef HAVE_LIBCRYPTO
bignum_CTX ctx = bignum_ctx_new();
if (ctx == NULL) {
@@ -403,14 +411,6 @@ int ssh_dh_build_k(ssh_session session) {
bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
session->next_crypto->y, select_p(session->next_crypto->kex_type), ctx);
}
#elif defined HAVE_LIBMBEDCRYPTO
if (session->client) {
bignum_mod_exp(session->next_crypto->k, session->next_crypto->f,
session->next_crypto->x, select_p(session->next_crypto->kex_type), NULL);
} else {
bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
session->next_crypto->y, select_p(session->next_crypto->kex_type), NULL);
}
#endif
#ifdef DEBUG_CRYPTO
@@ -435,14 +435,14 @@ int ssh_client_dh_init(ssh_session session){
ssh_string e = NULL;
int rc;
if (ssh_dh_generate_x(session) < 0) {
if (dh_generate_x(session) < 0) {
goto error;
}
if (ssh_dh_generate_e(session) < 0) {
if (dh_generate_e(session) < 0) {
goto error;
}
e = ssh_dh_get_e(session);
e = dh_get_e(session);
if (e == NULL) {
goto error;
}
@@ -456,7 +456,7 @@ int ssh_client_dh_init(ssh_session session){
ssh_string_free(e);
e=NULL;
rc = ssh_packet_send(session);
rc = packet_send(session);
return rc;
error:
if(e != NULL){
@@ -469,28 +469,22 @@ int ssh_client_dh_init(ssh_session session){
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){
ssh_string f;
ssh_string pubkey_blob = NULL;
ssh_string pubkey = NULL;
ssh_string signature = NULL;
int rc;
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL){
pubkey = buffer_get_ssh_string(packet);
if (pubkey == NULL){
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
dh_import_pubkey(session, pubkey);
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
ssh_string_free(pubkey_blob);
if (rc != 0) {
goto error;
}
f = ssh_buffer_get_ssh_string(packet);
f = buffer_get_ssh_string(packet);
if (f == NULL) {
ssh_set_error(session,SSH_FATAL, "No F number in packet");
goto error;
}
rc = ssh_dh_import_f(session, f);
rc = dh_import_f(session, f);
ssh_string_burn(f);
ssh_string_free(f);
if (rc < 0) {
@@ -498,36 +492,35 @@ int ssh_client_dh_reply(ssh_session session, ssh_buffer packet){
goto error;
}
signature = ssh_buffer_get_ssh_string(packet);
signature = buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
}
session->next_crypto->dh_server_signature = signature;
signature=NULL; /* ownership changed */
if (ssh_dh_build_k(session) < 0) {
if (dh_build_k(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
/* Send the MSG_NEWKEYS */
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=ssh_packet_send(session);
rc=packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
error:
return SSH_ERROR;
}
int ssh_make_sessionid(ssh_session session) {
int make_sessionid(ssh_session session) {
ssh_string num = NULL;
ssh_buffer server_hash = NULL;
ssh_buffer client_hash = NULL;
ssh_buffer buf = NULL;
ssh_string server_pubkey_blob = NULL;
int rc = SSH_ERROR;
buf = ssh_buffer_new();
@@ -557,42 +550,37 @@ int ssh_make_sessionid(ssh_session session) {
* boolean first_kex_packet_follows
* uint32 0 (reserved for future extension)
*/
rc = ssh_buffer_add_u8(server_hash, 0);
rc = buffer_add_u8(server_hash, 0);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_u32(server_hash, 0);
rc = buffer_add_u32(server_hash, 0);
if (rc < 0) {
goto error;
}
/* These fields are handled for the server case in ssh_packet_kexinit. */
if (session->client) {
rc = ssh_buffer_add_u8(client_hash, 0);
rc = buffer_add_u8(client_hash, 0);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_u32(client_hash, 0);
rc = buffer_add_u32(client_hash, 0);
if (rc < 0) {
goto error;
}
}
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_buffer_pack(buf,
"dPdPS",
ssh_buffer_get_len(client_hash),
ssh_buffer_get_len(client_hash),
ssh_buffer_get(client_hash),
ssh_buffer_get_len(server_hash),
ssh_buffer_get_len(server_hash),
ssh_buffer_get(server_hash),
server_pubkey_blob);
ssh_string_free(server_pubkey_blob);
buffer_get_rest_len(client_hash),
buffer_get_rest_len(client_hash),
buffer_get_rest(client_hash),
buffer_get_rest_len(server_hash),
buffer_get_rest_len(server_hash),
buffer_get_rest(server_hash),
session->next_crypto->server_pubkey);
if(rc != SSH_OK){
goto error;
}
@@ -608,9 +596,7 @@ int ssh_make_sessionid(ssh_session session) {
}
#ifdef HAVE_ECDH
} else if ((session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) ||
(session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP384) ||
(session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP521)) {
} else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
if (session->next_crypto->ecdh_client_pubkey == NULL ||
session->next_crypto->ecdh_server_pubkey == NULL) {
SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing");
@@ -625,8 +611,7 @@ int ssh_make_sessionid(ssh_session session) {
}
#endif
#ifdef HAVE_CURVE25519
} else if ((session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256) ||
(session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG)) {
} else if (session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG) {
rc = ssh_buffer_pack(buf,
"dPdP",
CURVE25519_PUBKEY_SIZE,
@@ -645,7 +630,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_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
#endif
switch (session->next_crypto->kex_type) {
@@ -658,11 +643,10 @@ int ssh_make_sessionid(ssh_session session) {
ssh_set_error_oom(session);
goto error;
}
sha1(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
session->next_crypto->secret_hash);
break;
case SSH_KEX_ECDH_SHA2_NISTP256:
case SSH_KEX_CURVE25519_SHA256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA256;
@@ -671,29 +655,7 @@ int ssh_make_sessionid(ssh_session session) {
ssh_set_error_oom(session);
goto error;
}
sha256(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
session->next_crypto->secret_hash);
break;
case SSH_KEX_ECDH_SHA2_NISTP384:
session->next_crypto->digest_len = SHA384_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA384;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
if (session->next_crypto->secret_hash == NULL) {
ssh_set_error_oom(session);
goto error;
}
sha384(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
session->next_crypto->secret_hash);
break;
case SSH_KEX_ECDH_SHA2_NISTP521:
session->next_crypto->digest_len = SHA512_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA512;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
if (session->next_crypto->secret_hash == NULL) {
ssh_set_error_oom(session);
goto error;
}
sha512(ssh_buffer_get(buf), ssh_buffer_get_len(buf),
sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
session->next_crypto->secret_hash);
break;
}
@@ -730,22 +692,13 @@ error:
return rc;
}
int ssh_hashbufout_add_cookie(ssh_session session) {
int rc;
int hashbufout_add_cookie(ssh_session session) {
session->out_hashbuf = ssh_buffer_new();
if (session->out_hashbuf == NULL) {
return -1;
}
rc = ssh_buffer_allocate_size(session->out_hashbuf,
sizeof(uint8_t) + 16);
if (rc < 0) {
ssh_buffer_reinit(session->out_hashbuf);
return -1;
}
if (ssh_buffer_add_u8(session->out_hashbuf, 20) < 0) {
if (buffer_add_u8(session->out_hashbuf, 20) < 0) {
ssh_buffer_reinit(session->out_hashbuf);
return -1;
}
@@ -767,22 +720,13 @@ int ssh_hashbufout_add_cookie(ssh_session session) {
return 0;
}
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
int rc;
int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) {
session->in_hashbuf = ssh_buffer_new();
if (session->in_hashbuf == NULL) {
return -1;
}
rc = ssh_buffer_allocate_size(session->in_hashbuf,
sizeof(uint8_t) + 20 + 16);
if (rc < 0) {
ssh_buffer_reinit(session->in_hashbuf);
return -1;
}
if (ssh_buffer_add_u8(session->in_hashbuf, 20) < 0) {
if (buffer_add_u8(session->in_hashbuf, 20) < 0) {
ssh_buffer_reinit(session->in_hashbuf);
return -1;
}
@@ -833,12 +777,12 @@ static int generate_one_key(ssh_string k,
return 0;
}
int ssh_generate_session_keys(ssh_session session) {
int generate_session_keys(ssh_session session) {
ssh_string k_string = NULL;
struct ssh_crypto_struct *crypto = session->next_crypto;
int rc = -1;
k_string = ssh_make_bignum_string(crypto->k);
k_string = make_bignum_string(crypto->k);
if (k_string == NULL) {
ssh_set_error_oom(session);
goto error;
@@ -943,55 +887,39 @@ error:
* @deprecated Use ssh_get_publickey_hash()
*/
int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
ssh_key pubkey = NULL;
ssh_string pubkey_blob = NULL;
MD5CTX ctx;
unsigned char *h;
int rc;
ssh_string pubkey;
MD5CTX ctx;
unsigned char *h;
if (session == NULL || hash == NULL) {
return SSH_ERROR;
}
*hash = NULL;
if (session->current_crypto == NULL ||
session->current_crypto->server_pubkey == NULL) {
ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
return SSH_ERROR;
}
if (session == NULL || hash == NULL) {
return SSH_ERROR;
}
*hash = NULL;
if (session->current_crypto == NULL ||
session->current_crypto->server_pubkey == NULL){
ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
return SSH_ERROR;
}
h = calloc(MD5_DIGEST_LEN, sizeof(unsigned char));
if (h == NULL) {
return SSH_ERROR;
}
h = malloc(sizeof(unsigned char) * MD5_DIGEST_LEN);
if (h == NULL) {
return SSH_ERROR;
}
ctx = md5_init();
if (ctx == NULL) {
SAFE_FREE(h);
return SSH_ERROR;
}
ctx = md5_init();
if (ctx == NULL) {
SAFE_FREE(h);
return SSH_ERROR;
}
rc = ssh_get_server_publickey(session, &pubkey);
if (rc != SSH_OK) {
md5_final(h, ctx);
SAFE_FREE(h);
return SSH_ERROR;
}
pubkey = session->current_crypto->server_pubkey;
rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob);
ssh_key_free(pubkey);
if (rc != SSH_OK) {
md5_final(h, ctx);
SAFE_FREE(h);
return SSH_ERROR;
}
md5_update(ctx, ssh_string_data(pubkey), ssh_string_len(pubkey));
md5_final(h, ctx);
md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob));
ssh_string_free(pubkey_blob);
md5_final(h, ctx);
*hash = h;
*hash = h;
return MD5_DIGEST_LEN;
return MD5_DIGEST_LEN;
}
/**
@@ -1021,59 +949,16 @@ void ssh_clean_pubkey_hash(unsigned char **hash) {
*
* @see ssh_key_free()
*/
int ssh_get_server_publickey(ssh_session session, ssh_key *key)
int ssh_get_publickey(ssh_session session, ssh_key *key)
{
ssh_key pubkey = NULL;
if (session == NULL ||
session->current_crypto == NULL ||
if (session==NULL ||
session->current_crypto ==NULL ||
session->current_crypto->server_pubkey == NULL) {
return SSH_ERROR;
}
pubkey = ssh_key_dup(session->current_crypto->server_pubkey);
if (pubkey == NULL) {
return SSH_ERROR;
}
*key = pubkey;
return SSH_OK;
}
ssh_key ssh_dh_get_current_server_publickey(ssh_session session)
{
return session->current_crypto->server_pubkey;
}
/* Caller need to free the blob */
int ssh_dh_get_current_server_publickey_blob(ssh_session session,
ssh_string *pubkey_blob)
{
const ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
return ssh_pki_export_pubkey_blob(pubkey, pubkey_blob);
}
ssh_key ssh_dh_get_next_server_publickey(ssh_session session)
{
return session->next_crypto->server_pubkey;
}
/* Caller need to free the blob */
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
ssh_string *pubkey_blob)
{
const ssh_key pubkey = ssh_dh_get_next_server_publickey(session);
return ssh_pki_export_pubkey_blob(pubkey, pubkey_blob);
}
/**
* @deprecated Use ssh_get_server_publickey()
*/
int ssh_get_publickey(ssh_session session, ssh_key *key)
{
return ssh_get_server_publickey(session, key);
return ssh_pki_import_pubkey_blob(session->current_crypto->server_pubkey,
key);
}
/**
@@ -1099,7 +984,7 @@ int ssh_get_publickey(ssh_session session, ssh_key *key)
* you at making things secure.
* OpenSSH uses SHA1 to print public key digests.
*
* @see ssh_session_update_known_hosts()
* @see ssh_is_server_known()
* @see ssh_get_hexa()
* @see ssh_print_hexa()
* @see ssh_clean_pubkey_hash()
@@ -1229,9 +1114,11 @@ void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
if (hexa == NULL) {
return;
}
fprintf(stderr, "%s: %s\n", descr, hexa);
printf("%s: %s\n", descr, hexa);
free(hexa);
}
/** @} */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -29,6 +29,148 @@
#include "libssh/bignum.h"
#ifdef HAVE_ECDH
#include <openssl/ecdh.h>
#define NISTP256 NID_X9_62_prime256v1
#define NISTP384 NID_secp384r1
#define NISTP521 NID_secp521r1
/** @internal
* @brief Starts ecdh-sha2-nistp256 key exchange
*/
int ssh_client_ecdh_init(ssh_session session){
EC_KEY *key;
const EC_GROUP *group;
const EC_POINT *pubkey;
ssh_string client_pubkey;
int len;
int rc;
bignum_CTX ctx = BN_CTX_new();
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
if (rc < 0) {
BN_CTX_free(ctx);
return SSH_ERROR;
}
key = EC_KEY_new_by_curve_name(NISTP256);
if (key == NULL) {
BN_CTX_free(ctx);
return SSH_ERROR;
}
group = EC_KEY_get0_group(key);
EC_KEY_generate_key(key);
pubkey=EC_KEY_get0_public_key(key);
len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
NULL,0,ctx);
client_pubkey = ssh_string_new(len);
if (client_pubkey == NULL) {
BN_CTX_free(ctx);
EC_KEY_free(key);
return SSH_ERROR;
}
EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
ssh_string_data(client_pubkey),len,ctx);
BN_CTX_free(ctx);
rc = buffer_add_ssh_string(session->out_buffer,client_pubkey);
if (rc < 0) {
EC_KEY_free(key);
ssh_string_free(client_pubkey);
return SSH_ERROR;
}
session->next_crypto->ecdh_privkey = key;
session->next_crypto->ecdh_client_pubkey = client_pubkey;
rc = packet_send(session);
return rc;
}
static void ecdh_import_pubkey(ssh_session session, ssh_string pubkey_string) {
session->next_crypto->server_pubkey = pubkey_string;
}
static int ecdh_build_k(ssh_session session) {
const EC_GROUP *group = EC_KEY_get0_group(session->next_crypto->ecdh_privkey);
EC_POINT *pubkey;
void *buffer;
int rc;
int len = (EC_GROUP_get_degree(group) + 7) / 8;
bignum_CTX ctx = bignum_ctx_new();
if (ctx == NULL) {
return -1;
}
session->next_crypto->k = bignum_new();
if (session->next_crypto->k == NULL) {
bignum_ctx_free(ctx);
return -1;
}
pubkey = EC_POINT_new(group);
if (pubkey == NULL) {
bignum_ctx_free(ctx);
return -1;
}
if (session->server) {
rc = EC_POINT_oct2point(group,
pubkey,
ssh_string_data(session->next_crypto->ecdh_client_pubkey),
ssh_string_len(session->next_crypto->ecdh_client_pubkey),
ctx);
} else {
rc = EC_POINT_oct2point(group,
pubkey,
ssh_string_data(session->next_crypto->ecdh_server_pubkey),
ssh_string_len(session->next_crypto->ecdh_server_pubkey),
ctx);
}
bignum_ctx_free(ctx);
if (rc <= 0) {
EC_POINT_clear_free(pubkey);
return -1;
}
buffer = malloc(len);
if (buffer == NULL) {
EC_POINT_clear_free(pubkey);
return -1;
}
rc = ECDH_compute_key(buffer,
len,
pubkey,
session->next_crypto->ecdh_privkey,
NULL);
EC_POINT_clear_free(pubkey);
if (rc <= 0) {
free(buffer);
return -1;
}
bignum_bin2bn(buffer, len, session->next_crypto->k);
free(buffer);
EC_KEY_free(session->next_crypto->ecdh_privkey);
session->next_crypto->ecdh_privkey = NULL;
#ifdef DEBUG_CRYPTO
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("Shared secret key", session->next_crypto->k);
#endif
return 0;
}
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
@@ -36,29 +178,23 @@
*/
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
ssh_string q_s_string = NULL;
ssh_string pubkey_blob = NULL;
ssh_string pubkey = NULL;
ssh_string signature = NULL;
int rc;
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
pubkey = buffer_get_ssh_string(packet);
if (pubkey == NULL){
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
ecdh_import_pubkey(session, pubkey);
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
ssh_string_free(pubkey_blob);
if (rc != 0) {
goto error;
}
q_s_string = ssh_buffer_get_ssh_string(packet);
q_s_string = buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
goto error;
}
session->next_crypto->ecdh_server_pubkey = q_s_string;
signature = ssh_buffer_get_ssh_string(packet);
signature = buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
@@ -72,15 +208,142 @@ int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
}
/* Send the MSG_NEWKEYS */
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=ssh_packet_send(session);
rc=packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
error:
return SSH_ERROR;
}
#ifdef WITH_SERVER
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
* SSH_MSG_KEXDH_REPLY
*/
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
/* ECDH keys */
ssh_string q_c_string;
ssh_string q_s_string;
EC_KEY *ecdh_key;
const EC_GROUP *group;
const EC_POINT *ecdh_pubkey;
bignum_CTX ctx;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
int len;
int rc;
/* Extract the client pubkey from the init packet */
q_c_string = buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
return SSH_ERROR;
}
session->next_crypto->ecdh_client_pubkey = q_c_string;
/* Build server's keypair */
ctx = BN_CTX_new();
ecdh_key = EC_KEY_new_by_curve_name(NISTP256);
if (ecdh_key == NULL) {
ssh_set_error_oom(session);
BN_CTX_free(ctx);
return SSH_ERROR;
}
group = EC_KEY_get0_group(ecdh_key);
EC_KEY_generate_key(ecdh_key);
ecdh_pubkey = EC_KEY_get0_public_key(ecdh_key);
len = EC_POINT_point2oct(group,
ecdh_pubkey,
POINT_CONVERSION_UNCOMPRESSED,
NULL,
0,
ctx);
q_s_string = ssh_string_new(len);
if (q_s_string == NULL) {
EC_KEY_free(ecdh_key);
BN_CTX_free(ctx);
return SSH_ERROR;
}
EC_POINT_point2oct(group,
ecdh_pubkey,
POINT_CONVERSION_UNCOMPRESSED,
ssh_string_data(q_s_string),
len,
ctx);
BN_CTX_free(ctx);
session->next_crypto->ecdh_privkey = ecdh_key;
session->next_crypto->ecdh_server_pubkey = q_s_string;
/* build k and session_id */
rc = ecdh_build_k(session);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
return SSH_ERROR;
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
rc = make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
return SSH_ERROR;
}
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
return SSH_ERROR;
}
rc = ssh_buffer_pack(session->out_buffer,
"bSSS",
SSH2_MSG_KEXDH_REPLY,
session->next_crypto->server_pubkey, /* host's pubkey */
q_s_string, /* ecdh public key */
sig_blob); /* signature blob */
ssh_string_free(sig_blob);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
rc = packet_send(session);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
/* Send the MSG_NEWKEYS */
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
return SSH_ERROR;;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
}
#endif /* WITH_SERVER */
#endif /* HAVE_ECDH */

View File

@@ -1,336 +0,0 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2011-2013 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/session.h"
#include "libssh/ecdh.h"
#include "libssh/dh.h"
#include "libssh/buffer.h"
#include "libssh/ssh2.h"
#include "libssh/pki.h"
#include "libssh/bignum.h"
#ifdef HAVE_ECDH
#include <openssl/ecdh.h>
#define NISTP256 NID_X9_62_prime256v1
#define NISTP384 NID_secp384r1
#define NISTP521 NID_secp521r1
/** @internal
* @brief Map the given key exchange enum value to its curve name.
*/
static int ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
return NISTP256;
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
return NISTP384;
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
return NISTP521;
}
return SSH_ERROR;
}
/** @internal
* @brief Starts ecdh-sha2-nistp256 key exchange
*/
int ssh_client_ecdh_init(ssh_session session){
EC_KEY *key;
const EC_GROUP *group;
const EC_POINT *pubkey;
ssh_string client_pubkey;
int curve;
int len;
int rc;
bignum_CTX ctx = BN_CTX_new();
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
if (rc < 0) {
BN_CTX_free(ctx);
return SSH_ERROR;
}
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
if (curve == SSH_ERROR) {
BN_CTX_free(ctx);
return SSH_ERROR;
}
key = EC_KEY_new_by_curve_name(curve);
if (key == NULL) {
BN_CTX_free(ctx);
return SSH_ERROR;
}
group = EC_KEY_get0_group(key);
EC_KEY_generate_key(key);
pubkey=EC_KEY_get0_public_key(key);
len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
NULL,0,ctx);
client_pubkey = ssh_string_new(len);
if (client_pubkey == NULL) {
BN_CTX_free(ctx);
EC_KEY_free(key);
return SSH_ERROR;
}
EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED,
ssh_string_data(client_pubkey),len,ctx);
BN_CTX_free(ctx);
rc = ssh_buffer_add_ssh_string(session->out_buffer,client_pubkey);
if (rc < 0) {
EC_KEY_free(key);
ssh_string_free(client_pubkey);
return SSH_ERROR;
}
session->next_crypto->ecdh_privkey = key;
session->next_crypto->ecdh_client_pubkey = client_pubkey;
rc = ssh_packet_send(session);
return rc;
}
int ecdh_build_k(ssh_session session) {
const EC_GROUP *group = EC_KEY_get0_group(session->next_crypto->ecdh_privkey);
EC_POINT *pubkey;
void *buffer;
int rc;
int len = (EC_GROUP_get_degree(group) + 7) / 8;
bignum_CTX ctx = bignum_ctx_new();
if (ctx == NULL) {
return -1;
}
session->next_crypto->k = bignum_new();
if (session->next_crypto->k == NULL) {
bignum_ctx_free(ctx);
return -1;
}
pubkey = EC_POINT_new(group);
if (pubkey == NULL) {
bignum_ctx_free(ctx);
return -1;
}
if (session->server) {
rc = EC_POINT_oct2point(group,
pubkey,
ssh_string_data(session->next_crypto->ecdh_client_pubkey),
ssh_string_len(session->next_crypto->ecdh_client_pubkey),
ctx);
} else {
rc = EC_POINT_oct2point(group,
pubkey,
ssh_string_data(session->next_crypto->ecdh_server_pubkey),
ssh_string_len(session->next_crypto->ecdh_server_pubkey),
ctx);
}
bignum_ctx_free(ctx);
if (rc <= 0) {
EC_POINT_clear_free(pubkey);
return -1;
}
buffer = malloc(len);
if (buffer == NULL) {
EC_POINT_clear_free(pubkey);
return -1;
}
rc = ECDH_compute_key(buffer,
len,
pubkey,
session->next_crypto->ecdh_privkey,
NULL);
EC_POINT_clear_free(pubkey);
if (rc <= 0) {
free(buffer);
return -1;
}
bignum_bin2bn(buffer, len, session->next_crypto->k);
free(buffer);
EC_KEY_free(session->next_crypto->ecdh_privkey);
session->next_crypto->ecdh_privkey = NULL;
#ifdef DEBUG_CRYPTO
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("Shared secret key", session->next_crypto->k);
#endif
return 0;
}
#ifdef WITH_SERVER
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
* SSH_MSG_KEXDH_REPLY
*/
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
/* ECDH keys */
ssh_string q_c_string;
ssh_string q_s_string;
EC_KEY *ecdh_key;
const EC_GROUP *group;
const EC_POINT *ecdh_pubkey;
bignum_CTX ctx;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
ssh_string pubkey_blob = NULL;
int curve;
int len;
int rc;
/* Extract the client pubkey from the init packet */
q_c_string = ssh_buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
return SSH_ERROR;
}
session->next_crypto->ecdh_client_pubkey = q_c_string;
/* Build server's keypair */
ctx = BN_CTX_new();
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
if (curve == SSH_ERROR) {
BN_CTX_free(ctx);
return SSH_ERROR;
}
ecdh_key = EC_KEY_new_by_curve_name(curve);
if (ecdh_key == NULL) {
ssh_set_error_oom(session);
BN_CTX_free(ctx);
return SSH_ERROR;
}
group = EC_KEY_get0_group(ecdh_key);
EC_KEY_generate_key(ecdh_key);
ecdh_pubkey = EC_KEY_get0_public_key(ecdh_key);
len = EC_POINT_point2oct(group,
ecdh_pubkey,
POINT_CONVERSION_UNCOMPRESSED,
NULL,
0,
ctx);
q_s_string = ssh_string_new(len);
if (q_s_string == NULL) {
EC_KEY_free(ecdh_key);
BN_CTX_free(ctx);
return SSH_ERROR;
}
EC_POINT_point2oct(group,
ecdh_pubkey,
POINT_CONVERSION_UNCOMPRESSED,
ssh_string_data(q_s_string),
len,
ctx);
BN_CTX_free(ctx);
session->next_crypto->ecdh_privkey = ecdh_key;
session->next_crypto->ecdh_server_pubkey = q_s_string;
/* build k and session_id */
rc = ecdh_build_k(session);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
return SSH_ERROR;
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
rc = ssh_make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
return SSH_ERROR;
}
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
return SSH_ERROR;
}
rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not export server public key");
ssh_string_free(sig_blob);
return SSH_ERROR;
}
rc = ssh_buffer_pack(session->out_buffer,
"bSSS",
SSH2_MSG_KEXDH_REPLY,
pubkey_blob, /* host's pubkey */
q_s_string, /* ecdh public key */
sig_blob); /* signature blob */
ssh_string_free(sig_blob);
ssh_string_free(pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
rc = ssh_packet_send(session);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
/* Send the MSG_NEWKEYS */
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
return SSH_ERROR;;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = ssh_packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
}
#endif /* WITH_SERVER */
#endif /* HAVE_ECDH */

View File

@@ -1,384 +0,0 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2011-2013 by Aris Adamantiadis
* Copyright (C) 2016 g10 Code GmbH
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/session.h"
#include "libssh/ecdh.h"
#include "libssh/dh.h"
#include "libssh/buffer.h"
#include "libssh/ssh2.h"
#include "libssh/pki.h"
#include "libssh/bignum.h"
#include "libssh/libgcrypt.h"
#ifdef HAVE_ECDH
#include <gcrypt.h>
/** @internal
* @brief Map the given key exchange enum value to its curve name.
*/
static const char *ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
return "NIST P-256";
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
return "NIST P-384";
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
return "NIST P-521";
}
return NULL;
}
/** @internal
* @brief Starts ecdh-sha2-nistp{256,384,521} key exchange.
*/
int ssh_client_ecdh_init(ssh_session session)
{
int rc;
gpg_error_t err;
ssh_string client_pubkey = NULL;
gcry_sexp_t param = NULL;
gcry_sexp_t key = NULL;
const char *curve = NULL;
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
if (curve == NULL) {
rc = SSH_ERROR;
goto out;
}
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
if (rc < 0) {
rc = SSH_ERROR;
goto out;
}
err = gcry_sexp_build(&param,
NULL,
"(genkey(ecdh(curve %s)))",
curve);
if (err) {
rc = SSH_ERROR;
goto out;
}
err = gcry_pk_genkey(&key, param);
if (err) {
rc = SSH_ERROR;
goto out;
}
client_pubkey = ssh_sexp_extract_mpi(key,
"q",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (client_pubkey == NULL) {
rc = SSH_ERROR;
goto out;
}
rc = ssh_buffer_add_ssh_string(session->out_buffer, client_pubkey);
if (rc < 0) {
rc = SSH_ERROR;
goto out;
}
session->next_crypto->ecdh_privkey = key;
key = NULL;
session->next_crypto->ecdh_client_pubkey = client_pubkey;
client_pubkey = NULL;
rc = ssh_packet_send(session);
out:
gcry_sexp_release(param);
gcry_sexp_release(key);
ssh_string_free(client_pubkey);
return rc;
}
int ecdh_build_k(ssh_session session)
{
gpg_error_t err;
gcry_sexp_t data = NULL;
gcry_sexp_t result = NULL;
/* We need to get the x coordinate. Libgcrypt 1.7 and above
offers a suitable API for that. */
#if (GCRYPT_VERSION_NUMBER >= 0x010700)
gcry_mpi_t s = NULL;
gcry_mpi_point_t point;
#else
size_t k_len = 0;
enum ssh_key_exchange_e kex_type = session->next_crypto->kex_type;
ssh_string s;
#endif
ssh_string pubkey_raw;
gcry_sexp_t pubkey = NULL;
ssh_string privkey = NULL;
int rc = SSH_ERROR;
const char *curve = NULL;
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
if (curve == NULL) {
goto out;
}
pubkey_raw = session->server
? session->next_crypto->ecdh_client_pubkey
: session->next_crypto->ecdh_server_pubkey;
err = gcry_sexp_build(&pubkey,
NULL,
"(key-data(public-key(ecdh(curve %s)(q %b))))",
curve,
ssh_string_len(pubkey_raw),
ssh_string_data(pubkey_raw));
if (err) {
goto out;
}
privkey = ssh_sexp_extract_mpi(session->next_crypto->ecdh_privkey,
"d",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (privkey == NULL) {
goto out;
}
err = gcry_sexp_build(&data, NULL,
"(data(flags raw)(value %b))",
ssh_string_len(privkey),
ssh_string_data(privkey));
if (err) {
goto out;
}
err = gcry_pk_encrypt(&result, data, pubkey);
if (err) {
goto out;
}
#if (GCRYPT_VERSION_NUMBER >= 0x010700)
err = gcry_sexp_extract_param(result, "", "s", &s, NULL);
if (err) {
goto out;
}
point = gcry_mpi_point_new(0);
if (point == NULL) {
gcry_mpi_release(s);
goto out;
}
err = gcry_mpi_ec_decode_point(point, s, NULL);
gcry_mpi_release(s);
if (err) {
goto out;
}
session->next_crypto->k = gcry_mpi_new(0);
gcry_mpi_point_snatch_get(session->next_crypto->k, NULL, NULL, point);
#else
s = ssh_sexp_extract_mpi(result, "s", GCRYMPI_FMT_USG, GCRYMPI_FMT_USG);
if (s == NULL) {
goto out;
}
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
k_len = 65;
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
k_len = 97;
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
k_len = 133;
} else {
ssh_string_burn(s);
ssh_string_free(s);
goto out;
}
if (ssh_string_len(s) != k_len) {
ssh_string_burn(s);
ssh_string_free(s);
goto out;
}
err = gcry_mpi_scan(&session->next_crypto->k,
GCRYMPI_FMT_USG,
(const char *)ssh_string_data(s) + 1,
k_len / 2,
NULL);
ssh_string_burn(s);
ssh_string_free(s);
if (err) {
goto out;
}
#endif
rc = SSH_OK;
gcry_sexp_release(session->next_crypto->ecdh_privkey);
session->next_crypto->ecdh_privkey = NULL;
#ifdef DEBUG_CRYPTO
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("Shared secret key", session->next_crypto->k);
#endif
out:
gcry_sexp_release(pubkey);
gcry_sexp_release(data);
gcry_sexp_release(result);
ssh_string_burn(privkey);
ssh_string_free(privkey);
return rc;
}
#ifdef WITH_SERVER
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
* SSH_MSG_KEXDH_REPLY
*/
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) {
gpg_error_t err;
/* ECDH keys */
ssh_string q_c_string;
ssh_string q_s_string;
gcry_sexp_t param = NULL;
gcry_sexp_t key = NULL;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
ssh_string pubkey_blob = NULL;
int rc = SSH_ERROR;
const char *curve = NULL;
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
if (curve == NULL) {
goto out;
}
/* Extract the client pubkey from the init packet */
q_c_string = ssh_buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet");
goto out;
}
session->next_crypto->ecdh_client_pubkey = q_c_string;
/* Build server's keypair */
err = gcry_sexp_build(&param, NULL, "(genkey(ecdh(curve %s)))",
curve);
if (err) {
goto out;
}
err = gcry_pk_genkey(&key, param);
if (err)
goto out;
q_s_string = ssh_sexp_extract_mpi(key,
"q",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (q_s_string == NULL) {
goto out;
}
session->next_crypto->ecdh_privkey = key;
key = NULL;
session->next_crypto->ecdh_server_pubkey = q_s_string;
/* build k and session_id */
rc = ecdh_build_k(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto out;
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
if (rc != SSH_OK) {
goto out;
}
rc = ssh_make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
goto out;
}
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
rc = SSH_ERROR;
goto out;
}
rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not export server public key");
ssh_string_free(sig_blob);
goto out;
}
rc = ssh_buffer_pack(session->out_buffer,
"bSSS",
SSH2_MSG_KEXDH_REPLY,
pubkey_blob, /* host's pubkey */
q_s_string, /* ecdh public key */
sig_blob); /* signature blob */
ssh_string_free(sig_blob);
ssh_string_free(pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
goto out;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
rc = ssh_packet_send(session);
if (rc != SSH_OK) {
goto out;
}
/* Send the MSG_NEWKEYS */
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc != SSH_OK) {
goto out;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = ssh_packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
out:
gcry_sexp_release(param);
gcry_sexp_release(key);
return rc;
}
#endif /* WITH_SERVER */
#endif /* HAVE_ECDH */

View File

@@ -1,305 +0,0 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2017 Sartura d.o.o.
*
* Author: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/session.h"
#include "libssh/ecdh.h"
#include "libssh/buffer.h"
#include "libssh/ssh2.h"
#include "libssh/dh.h"
#include "libssh/pki.h"
#include "libssh/bignum.h"
#include "libssh/libmbedcrypto.h"
#include <mbedtls/ecdh.h>
#include <mbedtls/ecp.h>
#ifdef HAVE_ECDH
static mbedtls_ecp_group_id ecdh_kex_type_to_curve(enum ssh_key_exchange_e kex_type) {
if (kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
return MBEDTLS_ECP_DP_SECP256R1;
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP384) {
return MBEDTLS_ECP_DP_SECP384R1;
} else if (kex_type == SSH_KEX_ECDH_SHA2_NISTP521) {
return MBEDTLS_ECP_DP_SECP521R1;
}
return MBEDTLS_ECP_DP_NONE;
}
int ssh_client_ecdh_init(ssh_session session)
{
ssh_string client_pubkey = NULL;
mbedtls_ecp_group grp;
int rc;
mbedtls_ecp_group_id curve;
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
if (curve == MBEDTLS_ECP_DP_NONE) {
return SSH_ERROR;
}
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
if (rc < 0) {
return SSH_ERROR;
}
session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
if (session->next_crypto->ecdh_privkey == NULL) {
return SSH_ERROR;
}
mbedtls_ecp_keypair_init(session->next_crypto->ecdh_privkey);
mbedtls_ecp_group_init(&grp);
rc = mbedtls_ecp_group_load(&grp, curve);
if (rc != 0) {
rc = SSH_ERROR;
goto out;
}
rc = mbedtls_ecp_gen_keypair(&grp, &session->next_crypto->ecdh_privkey->d,
&session->next_crypto->ecdh_privkey->Q, mbedtls_ctr_drbg_random,
&ssh_mbedtls_ctr_drbg);
if (rc != 0) {
rc = SSH_ERROR;
goto out;
}
client_pubkey = make_ecpoint_string(&grp,
&session->next_crypto->ecdh_privkey->Q);
if (client_pubkey == NULL) {
rc = SSH_ERROR;
goto out;
}
rc = ssh_buffer_add_ssh_string(session->out_buffer, client_pubkey);
if (rc < 0) {
rc = SSH_ERROR;
goto out;
}
session->next_crypto->ecdh_client_pubkey = client_pubkey;
client_pubkey = NULL;
rc = ssh_packet_send(session);
out:
mbedtls_ecp_group_free(&grp);
ssh_string_free(client_pubkey);
return rc;
}
int ecdh_build_k(ssh_session session)
{
mbedtls_ecp_group grp;
mbedtls_ecp_point pubkey;
int rc;
mbedtls_ecp_group_id curve;
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
if (curve == MBEDTLS_ECP_DP_NONE) {
return SSH_ERROR;
}
mbedtls_ecp_group_init(&grp);
mbedtls_ecp_point_init(&pubkey);
rc = mbedtls_ecp_group_load(&grp, curve);
if (rc != 0) {
rc = SSH_ERROR;
goto out;
}
if (session->server) {
rc = mbedtls_ecp_point_read_binary(&grp, &pubkey,
ssh_string_data(session->next_crypto->ecdh_client_pubkey),
ssh_string_len(session->next_crypto->ecdh_client_pubkey));
} else {
rc = mbedtls_ecp_point_read_binary(&grp, &pubkey,
ssh_string_data(session->next_crypto->ecdh_server_pubkey),
ssh_string_len(session->next_crypto->ecdh_server_pubkey));
}
if (rc != 0) {
rc = SSH_ERROR;
goto out;
}
session->next_crypto->k = malloc(sizeof(mbedtls_mpi));
if (session->next_crypto->k == NULL) {
rc = SSH_ERROR;
goto out;
}
mbedtls_mpi_init(session->next_crypto->k);
rc = mbedtls_ecdh_compute_shared(&grp, session->next_crypto->k, &pubkey,
&session->next_crypto->ecdh_privkey->d, mbedtls_ctr_drbg_random,
&ssh_mbedtls_ctr_drbg);
if (rc != 0) {
rc = SSH_ERROR;
goto out;
}
out:
mbedtls_ecp_keypair_free(session->next_crypto->ecdh_privkey);
SAFE_FREE(session->next_crypto->ecdh_privkey);
mbedtls_ecp_group_free(&grp);
mbedtls_ecp_point_free(&pubkey);
return rc;
}
#ifdef WITH_SERVER
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet)
{
ssh_string q_c_string = NULL;
ssh_string q_s_string = NULL;
mbedtls_ecp_group grp;
ssh_key privkey = NULL;
ssh_string sig_blob = NULL;
ssh_string pubkey_blob = NULL;
int rc;
mbedtls_ecp_group_id curve;
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
if (curve == MBEDTLS_ECP_DP_NONE) {
return SSH_ERROR;
}
q_c_string = ssh_buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet");
return SSH_ERROR;
}
session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
if (session->next_crypto->ecdh_privkey == NULL) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
session->next_crypto->ecdh_client_pubkey = q_c_string;
mbedtls_ecp_group_init(&grp);
mbedtls_ecp_keypair_init(session->next_crypto->ecdh_privkey);
rc = mbedtls_ecp_group_load(&grp, curve);
if (rc != 0) {
rc = SSH_ERROR;
goto out;
}
rc = mbedtls_ecp_gen_keypair(&grp, &session->next_crypto->ecdh_privkey->d,
&session->next_crypto->ecdh_privkey->Q, mbedtls_ctr_drbg_random,
&ssh_mbedtls_ctr_drbg);
if (rc != 0) {
rc = SSH_ERROR;
goto out;
}
q_s_string = make_ecpoint_string(&grp, &session->next_crypto->ecdh_privkey->Q);
if (q_s_string == NULL) {
rc = SSH_ERROR;
goto out;
}
session->next_crypto->ecdh_server_pubkey = q_s_string;
/* build k and session_id */
rc = ecdh_build_k(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto out;
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
if (rc == SSH_ERROR) {
rc = SSH_ERROR;
goto out;
}
rc = ssh_make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
rc = SSH_ERROR;
goto out;
}
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
rc = SSH_ERROR;
goto out;
}
rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not export server public key");
ssh_string_free(sig_blob);
goto out;
}
rc = ssh_buffer_pack(session->out_buffer, "bSSS",
SSH2_MSG_KEXDH_REPLY,
pubkey_blob, /* host's pubkey */
q_s_string, /* ecdh public key */
sig_blob); /* signature blob */
ssh_string_free(sig_blob);
ssh_string_free(pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto out;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
rc = ssh_packet_send(session);
if (rc != SSH_OK) {
rc = SSH_ERROR;
goto out;
}
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
rc = SSH_ERROR;
goto out;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = ssh_packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
out:
mbedtls_ecp_group_free(&grp);
return rc;
}
#endif /* WITH_SERVER */
#endif

View File

@@ -21,8 +21,6 @@
* MA 02111-1307, USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include "libssh/priv.h"
@@ -137,3 +135,5 @@ int ssh_get_error_code(void *error) {
}
/** @} */
/* vim: set ts=4 sw=4 et cindent: */

Some files were not shown because too many files have changed in this diff Show More