mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
Compare commits
245 Commits
ef50a3c0f0
...
libssh-0.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
319129399d | ||
|
|
87ae95eb3c | ||
|
|
055f102601 | ||
|
|
2d6862ddb9 | ||
|
|
22aa60d506 | ||
|
|
4b02bbbd32 | ||
|
|
31ded2070e | ||
|
|
df3d53e561 | ||
|
|
f28c3099da | ||
|
|
32a106c70d | ||
|
|
5d75090d9f | ||
|
|
32a3cfe661 | ||
|
|
1c59844dfe | ||
|
|
f071954a76 | ||
|
|
a033b93c61 | ||
|
|
b7856780a9 | ||
|
|
8b3425865a | ||
|
|
a30e234c03 | ||
|
|
bbf172a79c | ||
|
|
f28748578d | ||
|
|
36f7d1a614 | ||
|
|
71241ca68c | ||
|
|
bfbf9283d0 | ||
|
|
d75573e665 | ||
|
|
8fe36e3d07 | ||
|
|
f2e9ce68e7 | ||
|
|
cfb4d27c47 | ||
|
|
d366e289f3 | ||
|
|
2fc8347504 | ||
|
|
2691ed595e | ||
|
|
7b133cf9f5 | ||
|
|
9b59f1a222 | ||
|
|
8f21f879d3 | ||
|
|
67752dabfc | ||
|
|
34ac4e4248 | ||
|
|
1928fb6a85 | ||
|
|
5b1678f197 | ||
|
|
8aff91dfcb | ||
|
|
c0cc12d582 | ||
|
|
a162071f9a | ||
|
|
2091dab273 | ||
|
|
7f18ec4620 | ||
|
|
8e698382db | ||
|
|
ce10d40325 | ||
|
|
3fed9a5aff | ||
|
|
da0c77fdb1 | ||
|
|
818c80baed | ||
|
|
bb55bb2daf | ||
|
|
fdced9d544 | ||
|
|
96db44ff17 | ||
|
|
70dbbfa320 | ||
|
|
1118fc2adf | ||
|
|
257449a0b6 | ||
|
|
8752460df4 | ||
|
|
6f089a098b | ||
|
|
8b3be050c9 | ||
|
|
ade33474be | ||
|
|
dbf7749696 | ||
|
|
2db45dd547 | ||
|
|
87145387aa | ||
|
|
d027460792 | ||
|
|
3fdd82f2a8 | ||
|
|
6cd94a63ff | ||
|
|
e85b20ba82 | ||
|
|
78d5d64b38 | ||
|
|
f73a44c223 | ||
|
|
1cccfdf8a0 | ||
|
|
abe4ed0e75 | ||
|
|
e7f831f0a3 | ||
|
|
4ea4e12df2 | ||
|
|
fb49e194df | ||
|
|
13f4e31ad1 | ||
|
|
da5fa4ef66 | ||
|
|
dca415a38e | ||
|
|
56f86cd4a1 | ||
|
|
f265afacfb | ||
|
|
99f8b2b803 | ||
|
|
22edaf43ee | ||
|
|
497bd31364 | ||
|
|
8ed0c0b3c8 | ||
|
|
ce39d2fa73 | ||
|
|
90d3768f0f | ||
|
|
6f66032209 | ||
|
|
c571cd8402 | ||
|
|
b049e12652 | ||
|
|
785682ac28 | ||
|
|
f29f10876a | ||
|
|
45d28c7682 | ||
|
|
2786565e77 | ||
|
|
96ad690c80 | ||
|
|
0d82186503 | ||
|
|
5157d96958 | ||
|
|
6a0787a366 | ||
|
|
709e921942 | ||
|
|
43a69b0a65 | ||
|
|
18506f697c | ||
|
|
15bede0c0e | ||
|
|
92dde09a37 | ||
|
|
809d76cbf2 | ||
|
|
f78a74c160 | ||
|
|
b3b3045a81 | ||
|
|
72fd3a73df | ||
|
|
cf19770ede | ||
|
|
7f42f5a3c9 | ||
|
|
6223e05b23 | ||
|
|
634671db11 | ||
|
|
1f689261ec | ||
|
|
4919771f0f | ||
|
|
8aad24c062 | ||
|
|
0e5510bb99 | ||
|
|
de464cb74e | ||
|
|
c41f32bcca | ||
|
|
61e701caaa | ||
|
|
1c36642fed | ||
|
|
ad287371fb | ||
|
|
ebfdfd9a14 | ||
|
|
c9a1be5a85 | ||
|
|
fc0db4d982 | ||
|
|
8f1a350b6e | ||
|
|
15ed51cf20 | ||
|
|
7b2e07ecbc | ||
|
|
0404d45c29 | ||
|
|
f2215d14de | ||
|
|
ebbf7988b9 | ||
|
|
ec307d9862 | ||
|
|
2068973ff3 | ||
|
|
6eea08a9ef | ||
|
|
3ba2e7ace7 | ||
|
|
15c64b2981 | ||
|
|
ce5d421753 | ||
|
|
fd77439a12 | ||
|
|
a633deb985 | ||
|
|
50b9a182f5 | ||
|
|
bb88b637a9 | ||
|
|
60d5824760 | ||
|
|
397be918cd | ||
|
|
880fdb4b52 | ||
|
|
6a74677cef | ||
|
|
2c66eeaf75 | ||
|
|
91edc0ee21 | ||
|
|
46bda45d95 | ||
|
|
9773c0852a | ||
|
|
f1c56e4309 | ||
|
|
1fdc1025a8 | ||
|
|
a375b6c996 | ||
|
|
ecb01e05a2 | ||
|
|
b3911d0fa2 | ||
|
|
1ee687ea6f | ||
|
|
73e1f2691f | ||
|
|
84e29f9c06 | ||
|
|
23837b2080 | ||
|
|
4884f1d6fc | ||
|
|
ead1c4b168 | ||
|
|
3e11cb8071 | ||
|
|
78e78642e7 | ||
|
|
7ab0e3fe62 | ||
|
|
5da02d6de2 | ||
|
|
94db978218 | ||
|
|
78ea8608b0 | ||
|
|
7d9940d6eb | ||
|
|
9f4fa22250 | ||
|
|
330f6c73f6 | ||
|
|
4a3934da48 | ||
|
|
68b996bdbf | ||
|
|
d364374422 | ||
|
|
00af5bd582 | ||
|
|
1ab5abf0e6 | ||
|
|
f5d1d813fb | ||
|
|
92928a7d8d | ||
|
|
651c173e72 | ||
|
|
f76cd8b6d5 | ||
|
|
2bbeebd505 | ||
|
|
fef32b4c14 | ||
|
|
2eaff2b363 | ||
|
|
2b3e69fd5f | ||
|
|
cd992a90fb | ||
|
|
6ea111fd8a | ||
|
|
cda641176d | ||
|
|
5581645500 | ||
|
|
3e64ef3bf5 | ||
|
|
7372cd837a | ||
|
|
1ecf7003f6 | ||
|
|
70c54d9445 | ||
|
|
e52ff2c8ff | ||
|
|
9bf9d52e21 | ||
|
|
965000129e | ||
|
|
0940c6f1b0 | ||
|
|
2e6dbe8d3d | ||
|
|
8bf6907c1d | ||
|
|
6e9e13cc24 | ||
|
|
5bc32bfd88 | ||
|
|
7c8a793b0a | ||
|
|
e9b0a8210d | ||
|
|
fb63887c16 | ||
|
|
b113b78dfc | ||
|
|
646112b4e4 | ||
|
|
ba4346f089 | ||
|
|
401865d725 | ||
|
|
d312af1ed5 | ||
|
|
3cfd8a126b | ||
|
|
24ebbb8b39 | ||
|
|
447ee309b0 | ||
|
|
6c213c913b | ||
|
|
f8f6eb0ce6 | ||
|
|
54f89af6d3 | ||
|
|
0e4a1b1f66 | ||
|
|
5eeadf533f | ||
|
|
a4e2e01d3e | ||
|
|
3911046f7e | ||
|
|
2727af0fe6 | ||
|
|
c42da23348 | ||
|
|
e0adcea90d | ||
|
|
a62399fcd5 | ||
|
|
0ee68ac2a1 | ||
|
|
796d285eaf | ||
|
|
b5f71f35a3 | ||
|
|
b98ea81903 | ||
|
|
beeca3c650 | ||
|
|
9f5abdb526 | ||
|
|
02f80eb288 | ||
|
|
5b7f07b484 | ||
|
|
ec5278e34d | ||
|
|
e554f0dc0d | ||
|
|
e8e1916d2e | ||
|
|
58893352b0 | ||
|
|
cdcc92e344 | ||
|
|
29b3a94032 | ||
|
|
8f2b26a837 | ||
|
|
42c07f379d | ||
|
|
f79c4fd7a3 | ||
|
|
7b2aee90f0 | ||
|
|
aaacd18031 | ||
|
|
9f60352497 | ||
|
|
70c796e8b8 | ||
|
|
5b7a696cf2 | ||
|
|
c59568c3c1 | ||
|
|
6f10422685 | ||
|
|
44f851d287 | ||
|
|
3d158fffa0 | ||
|
|
c8be0201c6 | ||
|
|
a8969c4be6 | ||
|
|
8ec8d35e1a | ||
|
|
666db37e21 | ||
|
|
391bd88355 | ||
|
|
5f90b77a1b |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
||||
build
|
||||
cscope.*
|
||||
tags
|
||||
build
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -1,7 +1,7 @@
|
||||
Author(s):
|
||||
Aris Adamantiadis <aris@0xbadc0de.be> (project initiator)
|
||||
|
||||
Andreas Schneider <mail@cynapses.org> (developer)
|
||||
Andreas Schneider <asn@cryptomilk.org> (developer)
|
||||
|
||||
Nick Zitzmann <seiryu (at) comcast (dot) net> (mostly client SFTP stuff)
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ cmake_minimum_required(VERSION 2.6.0)
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
|
||||
set(APPLICATION_VERSION_MAJOR "0")
|
||||
set(APPLICATION_VERSION_MINOR "5")
|
||||
set(APPLICATION_VERSION_PATCH "90")
|
||||
set(APPLICATION_VERSION_MINOR "6")
|
||||
set(APPLICATION_VERSION_PATCH "4")
|
||||
|
||||
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
|
||||
|
||||
@@ -19,7 +19,7 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO
|
||||
# Increment AGE. Set REVISION to 0
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.3.0")
|
||||
set(LIBRARY_VERSION "4.5.0")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
@@ -39,10 +39,6 @@ include(CPackConfig.cmake)
|
||||
include(MacroEnsureOutOfSourceBuild)
|
||||
macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there.")
|
||||
|
||||
# add macros
|
||||
include(MacroAddPlugin)
|
||||
include(MacroCopyFile)
|
||||
|
||||
# search for libraries
|
||||
if (WITH_ZLIB)
|
||||
find_package(ZLIB REQUIRED)
|
||||
@@ -71,6 +67,13 @@ if (WITH_GSSAPI)
|
||||
find_package(GSSAPI)
|
||||
endif (WITH_GSSAPI)
|
||||
|
||||
if (WITH_NACL)
|
||||
find_package(NaCl)
|
||||
if (NOT NACL_FOUND)
|
||||
set(WITH_NACL OFF)
|
||||
endif (NOT NACL_FOUND)
|
||||
endif (WITH_NACL)
|
||||
|
||||
# config.h checks
|
||||
include(ConfigureChecks.cmake)
|
||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
@@ -94,22 +97,28 @@ install(
|
||||
)
|
||||
|
||||
# cmake config files
|
||||
configure_file(libssh-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libssh-config.cmake @ONLY)
|
||||
configure_file(libssh-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libssh-config-version.cmake @ONLY)
|
||||
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)
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libssh-config-version.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_DIR}
|
||||
${CMAKE_INSTALL_DIR}/${PROJECT_NAME}
|
||||
COMPONENT
|
||||
devel
|
||||
)
|
||||
|
||||
|
||||
# in tree build settings
|
||||
configure_file(libssh-build-tree-settings.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libssh-build-tree-settings.cmake @ONLY)
|
||||
|
||||
add_subdirectory(examples)
|
||||
if (WITH_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif (WITH_EXAMPLES)
|
||||
|
||||
if (WITH_TESTING)
|
||||
find_package(CMocka REQUIRED)
|
||||
@@ -123,6 +132,7 @@ message(STATUS "********** ${PROJECT_NAME} build options : **********")
|
||||
|
||||
message(STATUS "zlib support: ${WITH_ZLIB}")
|
||||
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
|
||||
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}")
|
||||
|
||||
@@ -11,15 +11,15 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
|
||||
|
||||
|
||||
### versions
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "5")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "90")
|
||||
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 "TGZ")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;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}")
|
||||
|
||||
if (WIN32)
|
||||
|
||||
42
ChangeLog
42
ChangeLog
@@ -1,16 +1,56 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.6.0 (released 2013-XX-XX)
|
||||
version 0.6.4 (released 2014-12-19)
|
||||
* Fixed CVE-2014-8132.
|
||||
* Added SHA-2 for session ID signing with ECDSA keys.
|
||||
* Added support for ECDSA host keys.
|
||||
* Added support for more ECDSA hostkey algorithms.
|
||||
* Added ssh_pki_key_ecdsa_name() API.
|
||||
* Fixed setting the bindfd only after successful listen.
|
||||
* Fixed issues with user created sockets.
|
||||
* Fixed several issues in libssh C++ wrapper.
|
||||
* Fixed several documentation issues.
|
||||
* Fixed channel exit-signal request.
|
||||
* Fixed X11 request screen number in messages.
|
||||
* Fixed several memory leaks.
|
||||
|
||||
version 0.6.3 (released 2014-03-04)
|
||||
* Fixed CVE-2014-0017.
|
||||
* Fixed memory leak with ecdsa signatures.
|
||||
|
||||
version 0.6.2 (released 2014-03-04)
|
||||
* security: fix for vulnerability CVE-2014-0017
|
||||
|
||||
version 0.6.1 (released 2014-02-08)
|
||||
* Added support for libgcrypt 1.6.
|
||||
* Added ssh_channel_accept_forward().
|
||||
* Added known_hosts heuristic during connection (#138).
|
||||
* Added getters for session cipher names.
|
||||
* Fixed decrypt of zero length buffer.
|
||||
* Fixed padding in RSA signature blobs.
|
||||
* Fixed DSA signature extraction.
|
||||
* Fixed some memory leaks.
|
||||
* Fixed read of non-connected socket.
|
||||
* Fixed thread dectection.
|
||||
|
||||
version 0.6.0 (released 2014-01-08)
|
||||
* Added new publicy key API.
|
||||
* Added new userauth API.
|
||||
* Added ssh_get_publickey_hash() function.
|
||||
* Added ssh_get_poll_flags() function.
|
||||
* Added gssapi-mic userauth.
|
||||
* Added GSSAPIServerIdentity option.
|
||||
* Added GSSAPIClientIdentity option.
|
||||
* Added GSSAPIDelegateCredentials option.
|
||||
* Added new callback based server API.
|
||||
* Added Elliptic Curve DSA (ECDSA) support (with OpenSSL).
|
||||
* Added Elliptic Curve Diffie Hellman (ECDH) support.
|
||||
* Added Curve25519 for ECDH key exchange.
|
||||
* Added improved logging system.
|
||||
* Added SSH-agent forwarding.
|
||||
* Added key-reexchange.
|
||||
* Added more unit tests.
|
||||
* Improved documentation.
|
||||
* Fixed timeout handling.
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ check_include_file(argp.h HAVE_ARGP_H)
|
||||
check_include_file(pty.h HAVE_PTY_H)
|
||||
check_include_file(termios.h HAVE_TERMIOS_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
check_include_file(util.h HAVE_UTIL_H)
|
||||
check_include_file(sys/time.h HAVE_SYS_TIME_H)
|
||||
|
||||
if (WIN32)
|
||||
check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H)
|
||||
@@ -93,6 +95,7 @@ endif (NOT WITH_GCRYPT)
|
||||
|
||||
# FUNCTIONS
|
||||
|
||||
check_function_exists(isblank HAVE_ISBLANK)
|
||||
check_function_exists(strncpy HAVE_STRNCPY)
|
||||
check_function_exists(vsnprintf HAVE_VSNPRINTF)
|
||||
check_function_exists(snprintf HAVE_SNPRINTF)
|
||||
@@ -167,11 +170,9 @@ if (GCRYPT_FOUND)
|
||||
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
|
||||
endif (GCRYPT_FOUND)
|
||||
|
||||
if (CMAKE_HAVE_THREADS_LIBRARY)
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(HAVE_PTHREAD 1)
|
||||
endif (CMAKE_USE_PTHREADS_INIT)
|
||||
endif (CMAKE_HAVE_THREADS_LIBRARY)
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(HAVE_PTHREAD 1)
|
||||
endif (CMAKE_USE_PTHREADS_INIT)
|
||||
|
||||
# OPTIONS
|
||||
check_c_source_compiles("
|
||||
|
||||
@@ -12,7 +12,8 @@ option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
|
||||
option(WITH_TESTING "Build with unit tests" OFF)
|
||||
option(WITH_CLIENT_TESTING "Build with client tests; requires a running sshd" OFF)
|
||||
option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
|
||||
|
||||
option(WITH_EXAMPLES "Build examples" ON)
|
||||
option(WITH_NACL "Build with libnacl (curve25519" ON)
|
||||
if (WITH_ZLIB)
|
||||
set(WITH_LIBZ ON)
|
||||
else (WITH_ZLIB)
|
||||
@@ -26,3 +27,7 @@ endif(WITH_BENCHMARKS)
|
||||
if (WITH_TESTING)
|
||||
set(WITH_STATIC_LIB ON)
|
||||
endif (WITH_TESTING)
|
||||
|
||||
if (WITH_NACL)
|
||||
set(WITH_NACL ON)
|
||||
endif (WITH_NACL)
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# Script to build libssh on UNIX.
|
||||
#
|
||||
# Copyright (c) 2006-2007 Andreas Schneider <mail@cynapses.org>
|
||||
# Copyright (c) 2006-2007 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
|
||||
SOURCE_DIR=".."
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# - ADD_CHECK_TEST(test_name test_source linklib1 ... linklibN)
|
||||
|
||||
# Copyright (c) 2007 Daniel Gollub <dgollub@suse.de>
|
||||
# Copyright (c) 2007-2010 Andreas Schneider <asn@cynapses.org>
|
||||
# Copyright (c) 2007-2010 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
@@ -25,3 +25,6 @@ if (NOT CMAKE_BUILD_TYPE)
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
|
||||
)
|
||||
endif (NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
# Create the compile command database for clang by default
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
@@ -75,3 +75,10 @@ if (MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
||||
endif (MSVC)
|
||||
|
||||
# This removes this annoying warning
|
||||
# "warning: 'BN_CTX_free' is deprecated: first deprecated in OS X 10.7 [-Wdeprecated-declarations]"
|
||||
if (OSX)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
|
||||
endif (OSX)
|
||||
|
||||
|
||||
@@ -26,3 +26,7 @@ endif (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "OS2")
|
||||
set(OS2 TRUE)
|
||||
endif (CMAKE_SYSTEM_NAME MATCHES "OS2")
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
set (OSX TRUE)
|
||||
endif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# ARGP_LIBRARIES - Link these to use Argp
|
||||
# ARGP_DEFINITIONS - Compiler switches required for using Argp
|
||||
#
|
||||
# Copyright (c) 2010 Andreas Schneider <asn@cynapses.org>
|
||||
# Copyright (c) 2010 Andreas Schneider <asn@cryptomilk.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
|
||||
61
cmake/Modules/FindNaCl.cmake
Normal file
61
cmake/Modules/FindNaCl.cmake
Normal file
@@ -0,0 +1,61 @@
|
||||
# - Try to find NaCl
|
||||
# Once done this will define
|
||||
#
|
||||
# NACL_FOUND - system has NaCl
|
||||
# NACL_INCLUDE_DIRS - the NaCl include directory
|
||||
# NACL_LIBRARIES - Link these to use NaCl
|
||||
# NACL_DEFINITIONS - Compiler switches required for using NaCl
|
||||
#
|
||||
# Copyright (c) 2010 Andreas Schneider <asn@cryptomilk.org>
|
||||
# Copyright (c) 2013 Aris Adamantiadis <aris@badcode.be>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
|
||||
if (NACL_LIBRARIES AND NACL_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(NACL_FOUND TRUE)
|
||||
else (NACL_LIBRARIES AND NACL_INCLUDE_DIRS)
|
||||
|
||||
find_path(NACL_INCLUDE_DIR
|
||||
NAMES
|
||||
nacl/crypto_box_curve25519xsalsa20poly1305.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
)
|
||||
|
||||
find_library(NACL_LIBRARY
|
||||
NAMES
|
||||
nacl
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
)
|
||||
|
||||
set(NACL_INCLUDE_DIRS
|
||||
${NACL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if (NACL_LIBRARY)
|
||||
set(NACL_LIBRARIES
|
||||
${NACL_LIBRARIES}
|
||||
${NACL_LIBRARY}
|
||||
)
|
||||
endif (NACL_LIBRARY)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(NaCl DEFAULT_MSG NACL_LIBRARIES NACL_INCLUDE_DIRS)
|
||||
|
||||
# show the NACL_INCLUDE_DIRS and NACL_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(NACL_INCLUDE_DIRS NACL_LIBRARIES)
|
||||
|
||||
endif (NACL_LIBRARIES AND NACL_INCLUDE_DIRS)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# - MACRO_ADD_COMPILE_FLAGS(target_name flag1 ... flagN)
|
||||
|
||||
# Copyright (c) 2006, Oswald Buddenhagen, <ossi@kde.org>
|
||||
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
|
||||
macro (MACRO_ADD_COMPILE_FLAGS _target)
|
||||
|
||||
get_target_property(_flags ${_target} COMPILE_FLAGS)
|
||||
if (_flags)
|
||||
set(_flags ${_flags} ${ARGN})
|
||||
else (_flags)
|
||||
set(_flags ${ARGN})
|
||||
endif (_flags)
|
||||
|
||||
set_target_properties(${_target} PROPERTIES COMPILE_FLAGS ${_flags})
|
||||
|
||||
endmacro (MACRO_ADD_COMPILE_FLAGS)
|
||||
@@ -1,20 +0,0 @@
|
||||
# - MACRO_ADD_LINK_FLAGS(target_name flag1 ... flagN)
|
||||
|
||||
# Copyright (c) 2006, Oswald Buddenhagen, <ossi@kde.org>
|
||||
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
macro (MACRO_ADD_LINK_FLAGS _target)
|
||||
|
||||
get_target_property(_flags ${_target} LINK_FLAGS)
|
||||
if (_flags)
|
||||
set(_flags "${_flags} ${ARGN}")
|
||||
else (_flags)
|
||||
set(_flags "${ARGN}")
|
||||
endif (_flags)
|
||||
|
||||
set_target_properties(${_target} PROPERTIES LINK_FLAGS "${_flags}")
|
||||
|
||||
endmacro (MACRO_ADD_LINK_FLAGS)
|
||||
@@ -1,30 +0,0 @@
|
||||
# - MACRO_ADD_PLUGIN(name [WITH_PREFIX] file1 .. fileN)
|
||||
#
|
||||
# Create a plugin from the given source files.
|
||||
# If WITH_PREFIX is given, the resulting plugin will have the
|
||||
# prefix "lib", otherwise it won't.
|
||||
#
|
||||
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
|
||||
# Copyright (c) 2006, Laurent Montel, <montel@kde.org>
|
||||
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
|
||||
macro (MACRO_ADD_PLUGIN _target_NAME _with_PREFIX)
|
||||
|
||||
if (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
set(_first_SRC)
|
||||
else (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
set(_first_SRC ${_with_PREFIX})
|
||||
endif (${_with_PREFIX} STREQUAL "WITH_PREFIX")
|
||||
|
||||
add_library(${_target_NAME} MODULE ${_first_SRC} ${ARGN})
|
||||
|
||||
if (_first_SRC)
|
||||
set_target_properties(${_target_NAME} PROPERTIES PREFIX "")
|
||||
endif (_first_SRC)
|
||||
|
||||
endmacro (MACRO_ADD_PLUGIN _name _sources)
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# - macro_copy_file(_src _dst)
|
||||
# Copies a file to ${_dst} only if ${_src} is different (newer) than ${_dst}
|
||||
#
|
||||
# Example:
|
||||
# macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/icon.png ${CMAKE_CURRENT_BINARY_DIR}/.)
|
||||
# Copies file icon.png to ${CMAKE_CURRENT_BINARY_DIR} directory
|
||||
#
|
||||
# Copyright (c) 2006-2007 Wengo
|
||||
# Copyright (c) 2006-2008 Andreas Schneider <mail@cynapses.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING file.
|
||||
|
||||
|
||||
macro (macro_copy_file _src _dst)
|
||||
# Removes all path containing .svn or CVS or CMakeLists.txt during the copy
|
||||
if (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*")
|
||||
|
||||
if (CMAKE_VERBOSE_MAKEFILE)
|
||||
message(STATUS "Copy file from ${_src} to ${_dst}")
|
||||
endif (CMAKE_VERBOSE_MAKEFILE)
|
||||
|
||||
# Creates directory if necessary
|
||||
get_filename_component(_path ${_dst} PATH)
|
||||
file(MAKE_DIRECTORY ${_path})
|
||||
|
||||
execute_process(
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E copy_if_different ${_src} ${_dst}
|
||||
OUTPUT_QUIET
|
||||
)
|
||||
endif (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*")
|
||||
endmacro (macro_copy_file)
|
||||
@@ -2,10 +2,18 @@
|
||||
#
|
||||
# Adds a doxygen target that runs doxygen to generate the html
|
||||
# and optionally the LaTeX API documentation.
|
||||
# The doxygen target is added to the doc target as dependency.
|
||||
# The doxygen target is added to the doc target as a dependency.
|
||||
# i.e.: the API documentation is built with:
|
||||
# make doc
|
||||
#
|
||||
# USAGE: GLOBAL INSTALL
|
||||
#
|
||||
# Install it with:
|
||||
# cmake ./ && sudo make install
|
||||
# Add the following to the CMakeLists.txt of your project:
|
||||
# include(UseDoxygen OPTIONAL)
|
||||
# Optionally copy Doxyfile.in in the directory of CMakeLists.txt and edit it.
|
||||
#
|
||||
# USAGE: INCLUDE IN PROJECT
|
||||
#
|
||||
# set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -13,88 +21,120 @@
|
||||
# Add the Doxyfile.in and UseDoxygen.cmake files to the projects source directory.
|
||||
#
|
||||
#
|
||||
# CONFIGURATION
|
||||
#
|
||||
# To configure Doxygen you can edit Doxyfile.in and set some variables in cmake.
|
||||
# Variables you may define are:
|
||||
# DOXYFILE_OUTPUT_DIR - Path where the Doxygen output is stored. Defaults to "doc".
|
||||
#
|
||||
# DOXYFILE_LATEX_DIR - Directory where the Doxygen LaTeX output is stored. Defaults to "latex".
|
||||
#
|
||||
# DOXYFILE_HTML_DIR - Directory where the Doxygen html output is stored. Defaults to "html".
|
||||
# DOXYFILE_SOURCE_DIR - Path where the Doxygen input files are.
|
||||
# Defaults to the current source directory.
|
||||
# DOXYFILE_EXTRA_SOURCES - Additional source diretories/files for Doxygen to scan.
|
||||
# The Paths should be in double quotes and separated by space. e.g.:
|
||||
# "${CMAKE_CURRENT_BINARY_DIR}/foo.c" "${CMAKE_CURRENT_BINARY_DIR}/bar/"
|
||||
#
|
||||
# DOXYFILE_OUTPUT_DIR - Path where the Doxygen output is stored.
|
||||
# Defaults to "${CMAKE_CURRENT_BINARY_DIR}/doc".
|
||||
#
|
||||
# DOXYFILE_LATEX - ON/OFF; Set to "ON" if you want the LaTeX documentation
|
||||
# to be built.
|
||||
# DOXYFILE_LATEX_DIR - Directory relative to DOXYFILE_OUTPUT_DIR where
|
||||
# the Doxygen LaTeX output is stored. Defaults to "latex".
|
||||
#
|
||||
# DOXYFILE_HTML_DIR - Directory relative to DOXYFILE_OUTPUT_DIR where
|
||||
# the Doxygen html output is stored. Defaults to "html".
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2009-2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
|
||||
# Copyright (c) 2010 Andreas Schneider <mail@cynapses.org>
|
||||
# Copyright (c) 2009, 2010, 2011 Tobias Rautenkranz <tobias@rautenkranz.ch>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the New
|
||||
# BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
macro(usedoxygen_set_default name value)
|
||||
if(NOT DEFINED "${name}")
|
||||
set("${name}" "${value}")
|
||||
endif()
|
||||
macro(usedoxygen_set_default name value type docstring)
|
||||
if(NOT DEFINED "${name}")
|
||||
set("${name}" "${value}" CACHE "${type}" "${docstring}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
find_package(Doxygen)
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
find_file(DOXYFILE_IN
|
||||
NAMES
|
||||
doxy.config.in
|
||||
PATHS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_ROOT}/Modules/
|
||||
NO_DEFAULT_PATH)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(DOXYFILE_IN DEFAULT_MSG "DOXYFILE_IN")
|
||||
find_file(DOXYFILE_IN "Doxyfile.in"
|
||||
PATHS "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_ROOT}/Modules/"
|
||||
NO_DEFAULT_PATH
|
||||
DOC "Path to the doxygen configuration template file")
|
||||
set(DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(DOXYFILE_IN DEFAULT_MSG "DOXYFILE_IN")
|
||||
endif()
|
||||
|
||||
if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND)
|
||||
add_custom_target(doxygen ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config)
|
||||
usedoxygen_set_default(DOXYFILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc"
|
||||
PATH "Doxygen output directory")
|
||||
usedoxygen_set_default(DOXYFILE_HTML_DIR "html"
|
||||
STRING "Doxygen HTML output directory")
|
||||
usedoxygen_set_default(DOXYFILE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
PATH "Input files source directory")
|
||||
usedoxygen_set_default(DOXYFILE_EXTRA_SOURCE_DIRS ""
|
||||
STRING "Additional source files/directories separated by space")
|
||||
set(DOXYFILE_SOURCE_DIRS "\"${DOXYFILE_SOURCE_DIR}\" ${DOXYFILE_EXTRA_SOURCES}")
|
||||
|
||||
usedoxygen_set_default(DOXYFILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
usedoxygen_set_default(DOXYFILE_HTML_DIR "html")
|
||||
usedoxygen_set_default(DOXYFILE_LATEX YES BOOL "Generate LaTeX API documentation" OFF)
|
||||
usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex" STRING "LaTex output directory")
|
||||
|
||||
set_property(DIRECTORY APPEND PROPERTY
|
||||
ADDITIONAL_MAKE_CLEAN_FILES "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_HTML_DIR}")
|
||||
mark_as_advanced(DOXYFILE_OUTPUT_DIR DOXYFILE_HTML_DIR DOXYFILE_LATEX_DIR
|
||||
DOXYFILE_SOURCE_DIR DOXYFILE_EXTRA_SOURCE_DIRS DOXYFILE_IN)
|
||||
|
||||
set(DOXYFILE_LATEX FALSE)
|
||||
set(DOXYFILE_PDFLATEX FALSE)
|
||||
set(DOXYFILE_DOT FALSE)
|
||||
|
||||
#find_package(LATEX)
|
||||
#if(LATEX_COMPILER AND MAKEINDEX_COMPILER)
|
||||
# set(DOXYFILE_LATEX TRUE)
|
||||
# usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex")
|
||||
#
|
||||
# set_property(DIRECTORY APPEND PROPERTY
|
||||
# ADDITIONAL_MAKE_CLEAN_FILES
|
||||
# "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
|
||||
#
|
||||
# if(PDFLATEX_COMPILER)
|
||||
# set(DOXYFILE_PDFLATEX TRUE)
|
||||
# endif()
|
||||
# if(DOXYGEN_DOT_EXECUTABLE)
|
||||
# set(DOXYFILE_DOT TRUE)
|
||||
# endif()
|
||||
#
|
||||
# add_custom_command(TARGET doxygen
|
||||
# POST_BUILD
|
||||
# COMMAND ${CMAKE_MAKE_PROGRAM}
|
||||
# WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
|
||||
#endif()
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY
|
||||
ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_HTML_DIR}")
|
||||
|
||||
configure_file(${DOXYFILE_IN} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config ESCAPE_QUOTES IMMEDIATE @ONLY)
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doxy.trac.in)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxy.trac.in ${CMAKE_CURRENT_BINARY_DIR}/doxy.trac ESCAPE_QUOTES IMMEDIATE @ONLY)
|
||||
add_custom_target(doxygen-trac ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.trac)
|
||||
endif()
|
||||
add_custom_target(doxygen
|
||||
COMMAND "${DOXYGEN_EXECUTABLE}"
|
||||
"${DOXYFILE}"
|
||||
COMMENT "Writing documentation to ${DOXYFILE_OUTPUT_DIR}..."
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
get_target_property(DOC_TARGET doc TYPE)
|
||||
if(NOT DOC_TARGET)
|
||||
add_custom_target(doc)
|
||||
endif()
|
||||
set(DOXYFILE_DOT "NO")
|
||||
if(DOXYGEN_DOT_EXECUTABLE)
|
||||
set(DOXYFILE_DOT "YES")
|
||||
endif()
|
||||
|
||||
add_dependencies(doc doxygen)
|
||||
## LaTeX
|
||||
set(DOXYFILE_PDFLATEX "NO")
|
||||
|
||||
set_property(DIRECTORY APPEND PROPERTY
|
||||
ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
|
||||
|
||||
if(DOXYFILE_LATEX STREQUAL "ON")
|
||||
set(DOXYFILE_GENERATE_LATEX "YES")
|
||||
find_package(LATEX)
|
||||
find_program(DOXYFILE_MAKE make)
|
||||
mark_as_advanced(DOXYFILE_MAKE)
|
||||
if(LATEX_COMPILER AND MAKEINDEX_COMPILER AND DOXYFILE_MAKE)
|
||||
if(PDFLATEX_COMPILER)
|
||||
set(DOXYFILE_PDFLATEX "YES")
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET doxygen
|
||||
POST_BUILD
|
||||
COMMAND "${DOXYFILE_MAKE}"
|
||||
COMMENT "Running LaTeX for Doxygen documentation in ${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}..."
|
||||
WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
|
||||
else()
|
||||
set(DOXYGEN_LATEX "NO")
|
||||
endif()
|
||||
else()
|
||||
set(DOXYFILE_GENERATE_LATEX "NO")
|
||||
endif()
|
||||
|
||||
|
||||
configure_file("${DOXYFILE_IN}" "${DOXYFILE}" @ONLY)
|
||||
|
||||
add_custom_target(doc)
|
||||
add_dependencies(doc doxygen)
|
||||
endif()
|
||||
|
||||
@@ -20,6 +20,12 @@
|
||||
/* Define to 1 if you have the <pty.h> header file. */
|
||||
#cmakedefine HAVE_PTY_H 1
|
||||
|
||||
/* Define to 1 if you have the <util.h> header file. */
|
||||
#cmakedefine HAVE_UTIL_H 1
|
||||
|
||||
/* 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 <termios.h> header file. */
|
||||
#cmakedefine HAVE_TERMIOS_H 1
|
||||
|
||||
@@ -79,6 +85,9 @@
|
||||
/* Define to 1 if you have the `_vsnprintf_s' function. */
|
||||
#cmakedefine HAVE__VSNPRINTF_S 1
|
||||
|
||||
/* Define to 1 if you have the `isblank' function. */
|
||||
#cmakedefine HAVE_ISBLANK 1
|
||||
|
||||
/* Define to 1 if you have the `strncpy' function. */
|
||||
#cmakedefine HAVE_STRNCPY 1
|
||||
|
||||
@@ -123,7 +132,6 @@
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#cmakedefine HAVE_PTHREAD 1
|
||||
|
||||
|
||||
/**************************** OPTIONS ****************************/
|
||||
|
||||
#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1
|
||||
@@ -155,6 +163,9 @@
|
||||
/* Define to 1 if you want to enable calltrace debug output */
|
||||
#cmakedefine DEBUG_CALLTRACE 1
|
||||
|
||||
/* Define to 1 if you want to enable NaCl support */
|
||||
#cmakedefine WITH_NACL 1
|
||||
|
||||
/*************************** ENDIAN *****************************/
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
|
||||
@@ -1628,7 +1628,7 @@ INCLUDE_FILE_PATTERNS =
|
||||
# undefined via #undef or recursively expanded use the := operator
|
||||
# instead of the = operator.
|
||||
|
||||
PREDEFINED =
|
||||
PREDEFINED = WITH_SERVER WITH_SFTP WITH_PCAP
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
|
||||
# this tag can be used to specify a list of macro names that should be expanded.
|
||||
@@ -285,7 +285,7 @@ int authenticate_kbdint(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ssh_userauth_none(session, NULL, NULL);
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
return rc;
|
||||
}
|
||||
@endcode
|
||||
@@ -304,7 +304,7 @@ int test_several_auth_methods(ssh_session session)
|
||||
{
|
||||
int method, rc;
|
||||
|
||||
rc = ssh_userauth_none(session, NULL, NULL);
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
if (rc != SSH_AUTH_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
119
doc/curve25519-sha256@libssh.org.txt
Normal file
119
doc/curve25519-sha256@libssh.org.txt
Normal file
@@ -0,0 +1,119 @@
|
||||
curve25519-sha256@libssh.org.txt Aris Adamantiadis <aris@badcode.be>
|
||||
21/9/2013
|
||||
|
||||
1. Introduction
|
||||
|
||||
This document describes the key exchange methode curve25519-sha256@libssh.org
|
||||
for SSH version 2 protocol. It is provided as an alternative to the existing
|
||||
key exchange mechanisms based on either Diffie-Hellman or Elliptic Curve Diffie-
|
||||
Hellman [RFC5656].
|
||||
The reason is the following : During summer of 2013, revelations from ex-
|
||||
consultant at NSA Edward Snowden gave proof that NSA willingly inserts backdoors
|
||||
into softwares, hardware components and published standards. While it is still
|
||||
believed that the mathematics behind ECC cryptography are still sound and solid,
|
||||
some people (including Bruce Schneier [SCHNEIER]), showed their lack of confidence
|
||||
in NIST-published curves such as nistp256, nistp384, nistp521, for which constant
|
||||
parameters (including the generator point) are defined without explanation. It
|
||||
is also believed that NSA had a word to say in their definition. These curves
|
||||
are not the most secure or fastest possible for their key sizes [DJB], and
|
||||
researchers think it is possible that NSA have ways of cracking NIST curves.
|
||||
It is also interesting to note that SSH belongs to the list of protocols the NSA
|
||||
claims to be able to eavesdrop. Having a secure replacement would make passive
|
||||
attacks much harder if such a backdoor exists.
|
||||
|
||||
However an alternative exists in the form of Curve25519. This algorithm has been
|
||||
proposed in 2006 by DJB [Curve25519]. Its main stengths are its speed, its
|
||||
constant-time run time (and resistance against side-channel attacks), and its
|
||||
lack of nebulous hard-coded constants.
|
||||
|
||||
The reference version being used in this document is the one described in
|
||||
[Curve25519] as implemented in the library NaCl [NaCl].
|
||||
This document does not attempts to provide alternatives to the ecdsa-sha1-*
|
||||
authentication keys.
|
||||
|
||||
2. Key exchange
|
||||
|
||||
The key exchange procedure is very similar to the one described chapter 4 of
|
||||
[RFC5656]. Public ephemeral keys are transmitted over SSH encapsulated into
|
||||
standard SSH strings.
|
||||
|
||||
The following is an overview of the key exchange process:
|
||||
|
||||
Client Server
|
||||
------ ------
|
||||
Generate ephemeral key pair.
|
||||
SSH_MSG_KEX_ECDH_INIT -------->
|
||||
Verify that client public key
|
||||
length is 32 bytes.
|
||||
Generate ephemeral key pair.
|
||||
Compute shared secret.
|
||||
Generate and sign exchange hash.
|
||||
<-------- SSH_MSG_KEX_ECDH_REPLY
|
||||
Verify that server public key length is 32 bytes.
|
||||
* Verify host keys belong to server.
|
||||
Compute shared secret.
|
||||
Generate exchange hash.
|
||||
Verify server's signature.
|
||||
|
||||
* Optional but strongly recommanded as this protects against MITM attacks.
|
||||
|
||||
This is implemented using the same messages as described in RFC5656 chapter 4
|
||||
|
||||
3. Method Name
|
||||
|
||||
The name of this key exchange method is "curve25519-sha256@libssh.org".
|
||||
|
||||
4. Implementation considerations
|
||||
|
||||
The whole method is based on the curve25519 scalar multiplication. In this
|
||||
method, a private key is a scalar of 256 bits, and a public key is a point
|
||||
of 256 bits.
|
||||
|
||||
4.1. Private key generation
|
||||
|
||||
A 32 bytes private key should be generated for each new connection,
|
||||
using a secure PRNG. The following actions must be done on the private key:
|
||||
mysecret[0] &= 248;
|
||||
mysecret[31] &= 127;
|
||||
mysecret[31] |= 64;
|
||||
In order to keep the key valid. However, many cryptographic libraries will do
|
||||
this automatically.
|
||||
It should be noted that, in opposition to NIST curves, no special validation
|
||||
should be done to ensure the result is a valid and secure private key.
|
||||
|
||||
4.2 Public key generation
|
||||
|
||||
The 32 bytes public key of either a client or a server must be generated using
|
||||
the 32 bytes private key and a common generator base. This base is defined as 9
|
||||
followed by all zeroes:
|
||||
const unsigned char basepoint[32] = {9};
|
||||
|
||||
The public key is calculated using the cryptographic scalar multiplication:
|
||||
const unsigned char privkey[32];
|
||||
unsigned char pubkey[32];
|
||||
crypto_scalarmult (pubkey, privkey, basepoint);
|
||||
However some cryptographic libraries may provide a combined function:
|
||||
crypto_scalarmult_base (pubkey, privkey);
|
||||
|
||||
It should be noted that, in opposition to NIST curves, no special validation
|
||||
should be done to ensure the received public keys are valid curves point. The
|
||||
Curve25519 algorithm ensure that every possible public key maps to a valid
|
||||
ECC Point.
|
||||
|
||||
4.3 Shared secret generation
|
||||
|
||||
The shared secret, k, is defined in SSH specifications to be a big integer.
|
||||
This number is calculated using the following procedure:
|
||||
|
||||
X is the 32 bytes point obtained by the scalar multiplication of the other
|
||||
side's public key and the local private key scalar.
|
||||
|
||||
The whole 32 bytes of the number X are then converted into a big integer k.
|
||||
This conversion follows the network byte order. This step differs from
|
||||
RFC5656.
|
||||
|
||||
[RFC5656] http://tools.ietf.org/html/rfc5656
|
||||
[SCHNEIER] https://www.schneier.com/blog/archives/2013/09/the_nsa_is_brea.html#c1675929
|
||||
[DJB] http://cr.yp.to/talks/2013.05.31/slides-dan+tanja-20130531-4x3.pdf
|
||||
[Curve25519] "Curve25519: new Diffie-Hellman speed records."
|
||||
http://cr.yp.to/ecdh/curve25519-20060209.pdf
|
||||
1546
doc/doxy.trac.in
1546
doc/doxy.trac.in
File diff suppressed because it is too large
Load Diff
@@ -145,7 +145,7 @@ or whatever use you have for it.
|
||||
@subsection libssh_reverse Doing reverse port forwarding with libssh
|
||||
|
||||
To do reverse port forwarding, call ssh_forward_listen(),
|
||||
then ssh_forward_accept().
|
||||
then ssh_channel_accept_forward().
|
||||
|
||||
When you call ssh_forward_listen(), you can let the remote server
|
||||
chose the non-priviledged port it should listen to. Otherwise, you can chose
|
||||
@@ -164,6 +164,7 @@ int web_server(ssh_session session)
|
||||
ssh_channel channel;
|
||||
char buffer[256];
|
||||
int nbytes, nwritten;
|
||||
int port;
|
||||
char *helloworld = ""
|
||||
"HTTP/1.1 200 OK\n"
|
||||
"Content-Type: text/html\n"
|
||||
@@ -186,7 +187,7 @@ int web_server(ssh_session session)
|
||||
return rc;
|
||||
}
|
||||
|
||||
channel = ssh_forward_accept(session, 60000);
|
||||
channel = ssh_channel_accept_forward(session, 60000, &port);
|
||||
if (channel == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error waiting for incoming connection: %s\n",
|
||||
|
||||
@@ -443,11 +443,10 @@ Most of time, the error returned are SSH_FATAL, but some functions
|
||||
(generaly the ssh_request_xxx ones) may fail because of server denying request.
|
||||
In these cases, SSH_REQUEST_DENIED is returned.
|
||||
|
||||
ssh_get_error() and ssh_get_error_code() take a ssh_session as a parameter.
|
||||
That's for thread safety, error messages that can be attached to a session
|
||||
aren't static anymore. Any error that happens during ssh_options_xxx()
|
||||
or ssh_connect() (i.e., outside of any session) can be retrieved by
|
||||
giving NULL as argument.
|
||||
For thread safety, errors are bound to ssh_session objects.
|
||||
As long as your ssh_session object is not NULL, you can retrieve the last error
|
||||
message and error code from the ssh_session using ssh_get_error() and
|
||||
ssh_get_error_code() respectively.
|
||||
|
||||
The SFTP subsystem has its own error codes, in addition to libssh ones.
|
||||
|
||||
|
||||
120
doc/sftp.dox
120
doc/sftp.dox
@@ -210,52 +210,63 @@ results to come.
|
||||
|
||||
Synchronous read is done with sftp_read().
|
||||
|
||||
The following example prints the contents of remote file "/etc/profile". For
|
||||
each 1024 bytes of information read, it waits until the end of the read operation:
|
||||
Files are normally transferred in chunks. A good chunk size is 16 KB. The following
|
||||
example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we
|
||||
request, sftp_read blocks till the data has been received:
|
||||
|
||||
@code
|
||||
// Good chunk size
|
||||
#define MAX_XFER_BUF_SIZE 16384
|
||||
|
||||
int sftp_read_sync(ssh_session session, sftp_session sftp)
|
||||
{
|
||||
int access_type;
|
||||
sftp_file file;
|
||||
char buffer[1024];
|
||||
int nbytes, rc;
|
||||
char buffer[MAX_XFER_BUF_SIZE];
|
||||
int nbytes, nwritten, rc;
|
||||
int fd;
|
||||
|
||||
access_type = O_RDONLY;
|
||||
file = sftp_open(sftp, "/etc/profile",
|
||||
access_type, 0);
|
||||
if (file == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open file for reading: %s\n",
|
||||
ssh_get_error(session));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
nbytes = sftp_read(file, buffer, sizeof(buffer));
|
||||
while (nbytes > 0)
|
||||
{
|
||||
if (write(1, buffer, nbytes) != nbytes)
|
||||
{
|
||||
sftp_close(file);
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Can't open file for reading: %s\n",
|
||||
ssh_get_error(session));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
nbytes = sftp_read(file, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
if (nbytes < 0)
|
||||
{
|
||||
fprintf(stderr, "Error while reading file: %s\n",
|
||||
ssh_get_error(session));
|
||||
sftp_close(file);
|
||||
return SSH_ERROR;
|
||||
fd = open("/path/to/profile", O_CREAT);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Can't open file for writing: %s\n",
|
||||
strerror(errno));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
nbytes = sftp_read(file, buffer, sizeof(buffer));
|
||||
if (nbytes == 0) {
|
||||
break; // EOF
|
||||
} else if (nbytes < 0) {
|
||||
fprintf(stderr, "Error while reading file: %s\n",
|
||||
ssh_get_error(session));
|
||||
sftp_close(file);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
nwritten = write(fd, buf, nbytes);
|
||||
if (nwritten != nbytes) {
|
||||
fprintf(stderr, "Error writing: %s\n",
|
||||
strerror(errno));
|
||||
sftp_close(file);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
rc = sftp_close(file);
|
||||
if (rc != SSH_OK)
|
||||
{
|
||||
fprintf(stderr, "Can't close the read file: %s\n",
|
||||
ssh_get_error(session));
|
||||
return rc;
|
||||
if (rc != SSH_OK) {
|
||||
fprintf(stderr, "Can't close the read file: %s\n",
|
||||
ssh_get_error(session));
|
||||
return rc;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
@@ -274,11 +285,14 @@ The example below reads a very big file in asynchronous, nonblocking, mode. Each
|
||||
time the data are not ready yet, a counter is incrementer.
|
||||
|
||||
@code
|
||||
// Good chunk size
|
||||
#define MAX_XFER_BUF_SIZE 16384
|
||||
|
||||
int sftp_read_async(ssh_session session, sftp_session sftp)
|
||||
{
|
||||
int access_type;
|
||||
sftp_file file;
|
||||
char buffer[1024];
|
||||
char buffer[MAX_XFER_BUF_SIZE];
|
||||
int async_request;
|
||||
int nbytes;
|
||||
long counter;
|
||||
@@ -287,8 +301,7 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
|
||||
access_type = O_RDONLY;
|
||||
file = sftp_open(sftp, "some_very_big_file",
|
||||
access_type, 0);
|
||||
if (file == NULL)
|
||||
{
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Can't open file for reading: %s\n",
|
||||
ssh_get_error(session));
|
||||
return SSH_ERROR;
|
||||
@@ -298,27 +311,31 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
|
||||
async_request = sftp_async_read_begin(file, sizeof(buffer));
|
||||
counter = 0L;
|
||||
usleep(10000);
|
||||
if (async_request >= 0)
|
||||
if (async_request >= 0) {
|
||||
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
|
||||
async_request);
|
||||
else nbytes = -1;
|
||||
while (nbytes > 0 || nbytes == SSH_AGAIN)
|
||||
{
|
||||
if (nbytes > 0)
|
||||
{
|
||||
write(1, buffer, nbytes);
|
||||
async_request = sftp_async_read_begin(file, sizeof(buffer));
|
||||
}
|
||||
else counter++;
|
||||
usleep(10000);
|
||||
if (async_request >= 0)
|
||||
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
|
||||
async_request);
|
||||
else nbytes = -1;
|
||||
} else {
|
||||
nbytes = -1;
|
||||
}
|
||||
|
||||
if (nbytes < 0)
|
||||
{
|
||||
while (nbytes > 0 || nbytes == SSH_AGAIN) {
|
||||
if (nbytes > 0) {
|
||||
write(1, buffer, nbytes);
|
||||
async_request = sftp_async_read_begin(file, sizeof(buffer));
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
usleep(10000);
|
||||
|
||||
if (async_request >= 0) {
|
||||
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
|
||||
async_request);
|
||||
} else {
|
||||
nbytes = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (nbytes < 0) {
|
||||
fprintf(stderr, "Error while reading file: %s\n",
|
||||
ssh_get_error(session));
|
||||
sftp_close(file);
|
||||
@@ -328,8 +345,7 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
|
||||
printf("The counter has reached value: %ld\n", counter);
|
||||
|
||||
rc = sftp_close(file);
|
||||
if (rc != SSH_OK)
|
||||
{
|
||||
if (rc != SSH_OK) {
|
||||
fprintf(stderr, "Can't close the read file: %s\n",
|
||||
ssh_get_error(session));
|
||||
return rc;
|
||||
|
||||
@@ -61,5 +61,6 @@ implement the following methods :
|
||||
- mutex_destroy
|
||||
- thread_id
|
||||
|
||||
libgcrypt 1.6 and bigger backend does not support custom callback. Using anything else than pthreads (ssh_threads_get_pthread()) here will fail.
|
||||
Good luck !
|
||||
*/
|
||||
|
||||
@@ -11,9 +11,9 @@ include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
if (BSD OR SOLARIS)
|
||||
if (BSD OR SOLARIS OR OSX)
|
||||
find_package(Argp)
|
||||
endif (BSD OR SOLARIS)
|
||||
endif (BSD OR SOLARIS OR OSX)
|
||||
|
||||
if (UNIX AND NOT WIN32)
|
||||
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
|
||||
@@ -28,7 +28,7 @@ if (UNIX AND NOT WIN32)
|
||||
if (WITH_SERVER)
|
||||
if (HAVE_LIBUTIL)
|
||||
add_executable(samplesshd-tty samplesshd-tty.c)
|
||||
target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} util)
|
||||
target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES} util)
|
||||
endif (HAVE_LIBUTIL)
|
||||
endif (WITH_SERVER)
|
||||
|
||||
|
||||
@@ -34,14 +34,26 @@ int verify_knownhost(ssh_session session){
|
||||
int state;
|
||||
char buf[10];
|
||||
unsigned char *hash = NULL;
|
||||
int hlen;
|
||||
size_t hlen;
|
||||
ssh_key srv_pubkey;
|
||||
int rc;
|
||||
|
||||
state=ssh_is_server_known(session);
|
||||
|
||||
hlen = ssh_get_pubkey_hash(session, &hash);
|
||||
if (hlen < 0) {
|
||||
return -1;
|
||||
rc = ssh_get_publickey(session, &srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ssh_get_publickey_hash(srv_pubkey,
|
||||
SSH_PUBLICKEY_HASH_SHA1,
|
||||
&hash,
|
||||
&hlen);
|
||||
ssh_key_free(srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(state){
|
||||
case SSH_SERVER_KNOWN_OK:
|
||||
break; /* ok */
|
||||
|
||||
@@ -25,8 +25,15 @@ clients must be made or how a client should react.
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
#ifdef HAVE_PTY_H
|
||||
#include <pty.h>
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_UTIL_H
|
||||
#include <util.h>
|
||||
#endif
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#define SSHD_USER "libssh"
|
||||
#define SSHD_PASSWORD "libssh"
|
||||
|
||||
@@ -38,6 +45,8 @@ clients must be made or how a client should react.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int port = 22;
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
const char *pcap_file="debug.server.pcap";
|
||||
ssh_pcap_file pcap;
|
||||
@@ -80,8 +89,6 @@ static char doc[] = "libssh -- a Secure Shell protocol implementation";
|
||||
/* A description of the arguments we accept. */
|
||||
static char args_doc[] = "BINDADDR";
|
||||
|
||||
static int port = 22;
|
||||
|
||||
/* The options we understand. */
|
||||
static struct argp_option options[] = {
|
||||
{
|
||||
|
||||
@@ -143,13 +143,14 @@ static void select_loop(ssh_session session,ssh_channel channel){
|
||||
if(lus==0){
|
||||
channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else
|
||||
} else {
|
||||
ret = write(2, buffer, lus);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error writing to stderr: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(channel && channel_is_closed(channel)){
|
||||
|
||||
@@ -166,7 +166,7 @@ typedef struct ssh_callbacks_struct *ssh_callbacks;
|
||||
* @param user User that wants to authenticate
|
||||
* @param password Password used for authentication
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @returns SSH_AUTH_OK Authentication is accepted.
|
||||
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
||||
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
||||
* @returns SSH_AUTH_DENIED Authentication failed.
|
||||
*/
|
||||
@@ -179,7 +179,7 @@ typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user
|
||||
* @param session Current session handler
|
||||
* @param user User that wants to authenticate
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @returns SSH_AUTH_OK Authentication is accepted.
|
||||
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
||||
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
||||
* @returns SSH_AUTH_DENIED Authentication failed.
|
||||
*/
|
||||
@@ -191,7 +191,7 @@ typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, vo
|
||||
* @param user Username of the user (can be spoofed)
|
||||
* @param principal Authenticated principal of the user, including realm.
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @returns SSH_AUTH_OK Authentication is accepted.
|
||||
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
||||
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
||||
* @returns SSH_AUTH_DENIED Authentication failed.
|
||||
* @warning Implementations should verify that parameter user matches in some way the principal.
|
||||
@@ -209,7 +209,7 @@ typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *us
|
||||
* SSH_PUBLICKEY_STATE_VALID if the signature is valid. Others values should be
|
||||
* replied with a SSH_AUTH_DENIED.
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @returns SSH_AUTH_OK Authentication is accepted.
|
||||
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
|
||||
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
|
||||
* @returns SSH_AUTH_DENIED Authentication failed.
|
||||
*/
|
||||
@@ -495,6 +495,8 @@ LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
|
||||
* @param len the length of the data
|
||||
* @param is_stderr is 0 for stdout or 1 for stderr
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @returns number of bytes processed by the callee. The remaining bytes will
|
||||
* be sent in the next callback message, when more data is available.
|
||||
*/
|
||||
typedef int (*ssh_channel_data_callback) (ssh_session session,
|
||||
ssh_channel channel,
|
||||
@@ -788,14 +790,21 @@ struct ssh_threads_callbacks_struct {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief sets the thread callbacks necessary if your program is using
|
||||
* libssh in a multithreaded fashion. This function must be called first,
|
||||
* outside of any threading context (in your main() for instance), before
|
||||
* ssh_init().
|
||||
* @param cb pointer to a ssh_threads_callbacks_struct structure, which contains
|
||||
* the different callbacks to be set.
|
||||
* @brief Set the thread callbacks structure.
|
||||
*
|
||||
* This is necessary if your program is using libssh in a multithreaded fashion.
|
||||
* This function must be called first, outside of any threading context (in your
|
||||
* main() function for instance), before you call ssh_init().
|
||||
*
|
||||
* @param[in] cb A pointer to a ssh_threads_callbacks_struct structure, which
|
||||
* contains the different callbacks to be set.
|
||||
*
|
||||
* @returns Always returns SSH_OK.
|
||||
*
|
||||
* @see ssh_threads_callbacks_struct
|
||||
* @see SSH_THREADS_PTHREAD
|
||||
* @bug libgcrypt 1.6 and bigger backend does not support custom callback.
|
||||
* Using anything else than pthreads here will fail.
|
||||
*/
|
||||
LIBSSH_API int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct
|
||||
*cb);
|
||||
@@ -809,9 +818,13 @@ LIBSSH_API int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct
|
||||
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void);
|
||||
|
||||
/**
|
||||
* @brief returns a pointer on the noop threads callbacks, to be used with
|
||||
* ssh_threads_set_callbacks. These callbacks do nothing and are being used by
|
||||
* default.
|
||||
* @brief Get the noop threads callbacks structure
|
||||
*
|
||||
* This can be used with ssh_threads_set_callbacks. These callbacks do nothing
|
||||
* and are being used by default.
|
||||
*
|
||||
* @return Always returns a valid pointer to the noop callbacks structure.
|
||||
*
|
||||
* @see ssh_threads_set_callbacks
|
||||
*/
|
||||
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#endif
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/kex.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
enum ssh_key_exchange_e {
|
||||
/* diffie-hellman-group1-sha1 */
|
||||
@@ -51,7 +52,9 @@ enum ssh_key_exchange_e {
|
||||
/* diffie-hellman-group14-sha1 */
|
||||
SSH_KEX_DH_GROUP14_SHA1,
|
||||
/* ecdh-sha2-nistp256 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP256
|
||||
SSH_KEX_ECDH_SHA2_NISTP256,
|
||||
/* curve25519-sha256@libssh.org */
|
||||
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG
|
||||
};
|
||||
|
||||
struct ssh_crypto_struct {
|
||||
@@ -60,6 +63,11 @@ struct ssh_crypto_struct {
|
||||
EC_KEY *ecdh_privkey;
|
||||
ssh_string ecdh_client_pubkey;
|
||||
ssh_string ecdh_server_pubkey;
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
ssh_curve25519_privkey curve25519_privkey;
|
||||
ssh_curve25519_pubkey curve25519_client_pubkey;
|
||||
ssh_curve25519_pubkey curve25519_server_pubkey;
|
||||
#endif
|
||||
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
||||
size_t digest_len; /* len of all the fields below */
|
||||
|
||||
57
include/libssh/curve25519.h
Normal file
57
include/libssh/curve25519.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
|
||||
*
|
||||
* This 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,
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This 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 this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CURVE25519_H_
|
||||
#define CURVE25519_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh.h"
|
||||
|
||||
#ifdef WITH_NACL
|
||||
|
||||
#include <nacl/crypto_scalarmult_curve25519.h>
|
||||
#define CURVE25519_PUBKEY_SIZE crypto_scalarmult_curve25519_BYTES
|
||||
#define CURVE25519_PRIVKEY_SIZE crypto_scalarmult_curve25519_SCALARBYTES
|
||||
#define crypto_scalarmult_base crypto_scalarmult_curve25519_base
|
||||
#define crypto_scalarmult crypto_scalarmult_curve25519
|
||||
#else
|
||||
|
||||
#define CURVE25519_PUBKEY_SIZE 32
|
||||
#define CURVE25519_PRIVKEY_SIZE 32
|
||||
int crypto_scalarmult_base(unsigned char *q, const unsigned char *n);
|
||||
int crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
|
||||
#endif /* WITH_NACL */
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
#define HAVE_CURVE25519 1
|
||||
#endif
|
||||
|
||||
typedef unsigned char ssh_curve25519_pubkey[CURVE25519_PUBKEY_SIZE];
|
||||
typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
|
||||
|
||||
|
||||
int ssh_client_curve25519_init(ssh_session session);
|
||||
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* CURVE25519_H_ */
|
||||
@@ -49,7 +49,7 @@ int hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
int hashbufout_add_cookie(ssh_session session);
|
||||
int generate_session_keys(ssh_session session);
|
||||
bignum make_string_bn(ssh_string string);
|
||||
void make_string_bn_inplace(ssh_string string, bignum bnout);
|
||||
ssh_string make_bignum_string(bignum num);
|
||||
|
||||
|
||||
#endif /* DH_H_ */
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#ifdef HAVE_OPENSSL_ECDH_H
|
||||
|
||||
#define HAVE_ECDH
|
||||
#ifdef HAVE_ECC
|
||||
#define HAVE_ECDH 1
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_OPENSSL_ECDH_H */
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
27
include/libssh/knownhosts.h
Normal file
27
include/libssh/knownhosts.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 20014 by Aris Adamantiadis <aris@badcode.be>
|
||||
*
|
||||
* This 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.
|
||||
*
|
||||
* This 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 this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef KNOWNHOSTS_H_
|
||||
#define KNOWNHOSTS_H_
|
||||
|
||||
char **ssh_knownhosts_algorithms(ssh_session session);
|
||||
|
||||
#endif /* KNOWNHOSTS_H_ */
|
||||
@@ -38,6 +38,11 @@ typedef SHA_CTX* SHACTX;
|
||||
typedef SHA256_CTX* SHA256CTX;
|
||||
typedef MD5_CTX* MD5CTX;
|
||||
typedef HMAC_CTX* HMACCTX;
|
||||
#ifdef HAVE_ECC
|
||||
typedef EVP_MD_CTX *EVPCTX;
|
||||
#else
|
||||
typedef void *EVPCTX;
|
||||
#endif
|
||||
|
||||
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||
#ifdef MD5_DIGEST_LEN
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
typedef gcry_md_hd_t SHACTX;
|
||||
typedef gcry_md_hd_t MD5CTX;
|
||||
typedef gcry_md_hd_t HMACCTX;
|
||||
typedef void *EVPCTX;
|
||||
#define SHA_DIGEST_LENGTH 20
|
||||
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
|
||||
#define MD5_DIGEST_LEN 16
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 6
|
||||
#define LIBSSH_VERSION_MICRO 0
|
||||
#define LIBSSH_VERSION_MICRO 4
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
@@ -208,10 +208,14 @@ enum ssh_publickey_state_e {
|
||||
SSH_PUBLICKEY_STATE_WRONG=2
|
||||
};
|
||||
|
||||
/* status flags */
|
||||
/* Status flags */
|
||||
/** Socket is closed */
|
||||
#define SSH_CLOSED 0x01
|
||||
/** Reading to socket won't block */
|
||||
#define SSH_READ_PENDING 0x02
|
||||
/** Session was closed due to an error */
|
||||
#define SSH_CLOSED_ERROR 0x04
|
||||
/** Output buffer not empty */
|
||||
#define SSH_WRITE_PENDING 0x08
|
||||
|
||||
enum ssh_server_known_e {
|
||||
@@ -327,7 +331,10 @@ enum ssh_options_e {
|
||||
SSH_OPTIONS_COMPRESSION,
|
||||
SSH_OPTIONS_COMPRESSION_LEVEL,
|
||||
SSH_OPTIONS_KEY_EXCHANGE,
|
||||
SSH_OPTIONS_HOSTKEYS
|
||||
SSH_OPTIONS_HOSTKEYS,
|
||||
SSH_OPTIONS_GSSAPI_SERVER_IDENTITY,
|
||||
SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY,
|
||||
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -370,6 +377,7 @@ LIBSSH_API int ssh_channel_open_x11(ssh_channel channel, const char *orig_addr,
|
||||
LIBSSH_API int ssh_channel_poll(ssh_channel channel, int is_stderr);
|
||||
LIBSSH_API int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr);
|
||||
LIBSSH_API int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr);
|
||||
LIBSSH_API int ssh_channel_read_timeout(ssh_channel channel, void *dest, uint32_t count, int is_stderr, int timeout_ms);
|
||||
LIBSSH_API int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
|
||||
int is_stderr);
|
||||
LIBSSH_API int ssh_channel_request_env(ssh_channel channel, const char *name, const char *value);
|
||||
@@ -398,6 +406,7 @@ LIBSSH_API void ssh_disconnect(ssh_session session);
|
||||
LIBSSH_API char *ssh_dirname (const char *path);
|
||||
LIBSSH_API int ssh_finalize(void);
|
||||
LIBSSH_API ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms);
|
||||
LIBSSH_API ssh_channel ssh_channel_accept_forward(ssh_session session, int timeout_ms, int *destination_port);
|
||||
LIBSSH_API int ssh_forward_cancel(ssh_session session, const char *address, int port);
|
||||
LIBSSH_API int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port);
|
||||
LIBSSH_API void ssh_free(ssh_session session);
|
||||
@@ -408,11 +417,24 @@ LIBSSH_API socket_t ssh_get_fd(ssh_session session);
|
||||
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_publickey(ssh_session session, ssh_key *key);
|
||||
LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash);
|
||||
|
||||
enum ssh_publickey_hash_type {
|
||||
SSH_PUBLICKEY_HASH_SHA1,
|
||||
SSH_PUBLICKEY_HASH_MD5
|
||||
};
|
||||
LIBSSH_API int ssh_get_publickey_hash(const ssh_key key,
|
||||
enum ssh_publickey_hash_type type,
|
||||
unsigned char **hash,
|
||||
size_t *hlen);
|
||||
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash);
|
||||
|
||||
LIBSSH_API int ssh_get_random(void *where,int len,int strong);
|
||||
LIBSSH_API int ssh_get_version(ssh_session session);
|
||||
LIBSSH_API int ssh_get_status(ssh_session session);
|
||||
LIBSSH_API int ssh_get_poll_flags(ssh_session session);
|
||||
LIBSSH_API int ssh_init(void);
|
||||
LIBSSH_API int ssh_is_blocking(ssh_session session);
|
||||
LIBSSH_API int ssh_is_connected(ssh_session session);
|
||||
@@ -493,6 +515,11 @@ LIBSSH_API int ssh_pki_import_privkey_file(const char *filename,
|
||||
ssh_auth_callback auth_fn,
|
||||
void *auth_data,
|
||||
ssh_key *pkey);
|
||||
LIBSSH_API int ssh_pki_export_privkey_file(const ssh_key privkey,
|
||||
const char *passphrase,
|
||||
ssh_auth_callback auth_fn,
|
||||
void *auth_data,
|
||||
const char *filename);
|
||||
|
||||
LIBSSH_API int ssh_pki_import_pubkey_base64(const char *b64_key,
|
||||
enum ssh_keytypes_e type,
|
||||
@@ -507,6 +534,8 @@ LIBSSH_API int ssh_pki_export_pubkey_base64(const ssh_key key,
|
||||
LIBSSH_API int ssh_pki_export_pubkey_file(const ssh_key key,
|
||||
const char *filename);
|
||||
|
||||
LIBSSH_API const char *ssh_pki_key_ecdsa_name(const ssh_key key);
|
||||
|
||||
LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
|
||||
LIBSSH_API int ssh_send_ignore (ssh_session session, const char *data);
|
||||
LIBSSH_API int ssh_send_debug (ssh_session session, const char *message, int always_display);
|
||||
@@ -599,7 +628,10 @@ 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 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);
|
||||
LIBSSH_API const char* ssh_get_cipher_in(ssh_session session);
|
||||
LIBSSH_API const char* ssh_get_cipher_out(ssh_session session);
|
||||
|
||||
#ifndef LIBSSH_LEGACY_0_4
|
||||
#include "libssh/legacy.h"
|
||||
|
||||
@@ -361,8 +361,8 @@ public:
|
||||
* @see ssh_channel_forward_accept
|
||||
* @see Session::listenForward
|
||||
*/
|
||||
Channel *acceptForward(int timeout_ms);
|
||||
/* acceptForward is implemented later in this file */
|
||||
inline Channel *acceptForward(int timeout_ms);
|
||||
/* implemented outside the class due Channel references */
|
||||
|
||||
void_throwable cancelForward(const char *address, int port){
|
||||
int err=ssh_forward_cancel(c_session, address, port);
|
||||
@@ -480,12 +480,30 @@ public:
|
||||
ssh_throw(err);
|
||||
return err;
|
||||
}
|
||||
int read(void *dest, size_t count, bool is_stderr=false){
|
||||
int read(void *dest, size_t count, bool is_stderr){
|
||||
int err;
|
||||
/* handle int overflow */
|
||||
if(count > 0x7fffffff)
|
||||
count = 0x7fffffff;
|
||||
err=ssh_channel_read(channel,dest,count,is_stderr);
|
||||
err=ssh_channel_read_timeout(channel,dest,count,is_stderr,-1);
|
||||
ssh_throw(err);
|
||||
return err;
|
||||
}
|
||||
int read(void *dest, size_t count, int timeout){
|
||||
int err;
|
||||
/* handle int overflow */
|
||||
if(count > 0x7fffffff)
|
||||
count = 0x7fffffff;
|
||||
err=ssh_channel_read_timeout(channel,dest,count,false,timeout);
|
||||
ssh_throw(err);
|
||||
return err;
|
||||
}
|
||||
int read(void *dest, size_t count, bool is_stderr=false, int timeout=-1){
|
||||
int err;
|
||||
/* handle int overflow */
|
||||
if(count > 0x7fffffff)
|
||||
count = 0x7fffffff;
|
||||
err=ssh_channel_read_timeout(channel,dest,count,is_stderr,timeout);
|
||||
ssh_throw(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ struct ssh_key_struct {
|
||||
|
||||
struct ssh_signature_struct {
|
||||
enum ssh_keytypes_e type;
|
||||
const char *type_c;
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_sig;
|
||||
gcry_sexp_t rsa_sig;
|
||||
|
||||
@@ -34,6 +34,7 @@ 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);
|
||||
|
||||
/* SSH Key Functions */
|
||||
ssh_key pki_key_dup(const ssh_key key, int demote);
|
||||
@@ -51,6 +52,11 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
ssh_auth_callback auth_fn,
|
||||
void *auth_data);
|
||||
|
||||
ssh_string pki_private_key_to_pem(const ssh_key key,
|
||||
const char *passphrase,
|
||||
ssh_auth_callback auth_fn,
|
||||
void *auth_data);
|
||||
|
||||
/* SSH Public Key Functions */
|
||||
int pki_pubkey_build_dss(ssh_key key,
|
||||
ssh_string p,
|
||||
|
||||
@@ -67,7 +67,9 @@
|
||||
|
||||
# define strcasecmp _stricmp
|
||||
# define strncasecmp _strnicmp
|
||||
# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
|
||||
# if ! defined(HAVE_ISBLANK)
|
||||
# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
|
||||
# endif
|
||||
|
||||
# define usleep(X) Sleep(((X)+1000)/1000)
|
||||
|
||||
@@ -118,11 +120,24 @@ int gettimeofday(struct timeval *__p, void *__t);
|
||||
#include "libssh/callbacks.h"
|
||||
|
||||
/* some constants */
|
||||
#ifndef MAX_PACKAT_LEN
|
||||
#define MAX_PACKET_LEN 262144
|
||||
#endif
|
||||
#ifndef ERROR_BUFFERLEN
|
||||
#define ERROR_BUFFERLEN 1024
|
||||
#endif
|
||||
#ifndef CLIENTBANNER1
|
||||
#define CLIENTBANNER1 "SSH-1.5-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif
|
||||
#ifndef CLIENTBANNER2
|
||||
#define CLIENTBANNER2 "SSH-2.0-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
|
||||
#endif
|
||||
#ifndef KBDINT_MAX_PROMPT
|
||||
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
|
||||
#endif
|
||||
#ifndef MAX_BUF_SIZE
|
||||
#define MAX_BUF_SIZE 4096
|
||||
#endif
|
||||
|
||||
#ifndef __FUNCTION__
|
||||
#if defined(__SUNPRO_C)
|
||||
@@ -251,7 +266,7 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
/** Overwrite the buffer with '\0' */
|
||||
# define BURN_BUFFER(x, size) do { \
|
||||
if ((x) != NULL) \
|
||||
memset((x), '\0', (size))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
|
||||
memset((x), '\0', (size)); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
|
||||
} while(0)
|
||||
#else /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
|
||||
/** Overwrite a string with '\0' */
|
||||
@@ -262,7 +277,7 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
/** Overwrite the buffer with '\0' */
|
||||
# define BURN_BUFFER(x, size) do { \
|
||||
if ((x) != NULL) \
|
||||
memset((x), '\0', (size))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
|
||||
memset((x), '\0', (size)); \
|
||||
} while(0)
|
||||
#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
|
||||
|
||||
|
||||
@@ -44,7 +44,8 @@ enum ssh_bind_options_e {
|
||||
SSH_BIND_OPTIONS_RSAKEY,
|
||||
SSH_BIND_OPTIONS_BANNER,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||
SSH_BIND_OPTIONS_ECDSAKEY
|
||||
};
|
||||
|
||||
typedef struct ssh_bind_struct* ssh_bind;
|
||||
@@ -80,69 +81,6 @@ typedef struct ssh_bind_callbacks_struct *ssh_bind_callbacks;
|
||||
*/
|
||||
LIBSSH_API ssh_bind ssh_bind_new(void);
|
||||
|
||||
/**
|
||||
* @brief Set the options for the current SSH server bind.
|
||||
*
|
||||
* @param sshbind The ssh server bind to configure.
|
||||
*
|
||||
* @param type The option type to set. This could be one of the
|
||||
* following:
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_BINDADDR
|
||||
* The ip address to bind (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_BINDPORT
|
||||
* The port to bind (unsigned int).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_BINDPORT_STR
|
||||
* The port to bind (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_HOSTKEY
|
||||
* This specifies the file containing the private host key used
|
||||
* by SSHv1. (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_DSAKEY
|
||||
* This specifies the file containing the private host dsa key
|
||||
* used by SSHv2. (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_RSAKEY
|
||||
* This specifies the file containing the private host dsa key
|
||||
* used by SSHv2. (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_BANNER
|
||||
* That the server banner (version string) for SSH.
|
||||
* (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_LOG_VERBOSITY
|
||||
* Set the session logging verbosity (int).\n
|
||||
* \n
|
||||
* The verbosity of the messages. Every log smaller or
|
||||
* equal to verbosity will be shown.
|
||||
* - SSH_LOG_NOLOG: No logging
|
||||
* - SSH_LOG_RARE: Rare conditions or warnings
|
||||
* - SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* - SSH_LOG_PACKET: Packet id and size
|
||||
* - SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_LOG_VERBOSITY_STR
|
||||
* Set the session logging verbosity (const char *).\n
|
||||
* \n
|
||||
* The verbosity of the messages. Every log smaller or
|
||||
* equal to verbosity will be shown.
|
||||
* - SSH_LOG_NOLOG: No logging
|
||||
* - SSH_LOG_RARE: Rare conditions or warnings
|
||||
* - SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* - SSH_LOG_PACKET: Packet id and size
|
||||
* - SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
* \n
|
||||
* See the corresponding numbers in libssh.h.
|
||||
*
|
||||
* @param value The value to set. This is a generic pointer and the
|
||||
* datatype which is used should be set according to the
|
||||
* type set.
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_ERROR on invalid option or parameter.
|
||||
*/
|
||||
LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
|
||||
enum ssh_bind_options_e type, const void *value);
|
||||
|
||||
@@ -382,6 +320,8 @@ 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);
|
||||
|
||||
/* deprecated functions */
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_accept(ssh_session session);
|
||||
SSH_DEPRECATED LIBSSH_API int channel_write_stderr(ssh_channel channel,
|
||||
|
||||
@@ -97,9 +97,6 @@ struct ssh_session_struct {
|
||||
int openssh;
|
||||
uint32_t send_seq;
|
||||
uint32_t recv_seq;
|
||||
/* status flags */
|
||||
int closed;
|
||||
int closed_by_except;
|
||||
|
||||
int connected;
|
||||
/* !=0 when the user got a session handle */
|
||||
@@ -178,6 +175,7 @@ struct ssh_session_struct {
|
||||
char *knownhosts;
|
||||
char *wanted_methods[10];
|
||||
char *ProxyCommand;
|
||||
char *custombanner;
|
||||
unsigned long timeout; /* seconds */
|
||||
unsigned long timeout_usec;
|
||||
unsigned int port;
|
||||
@@ -186,6 +184,9 @@ struct ssh_session_struct {
|
||||
int ssh2;
|
||||
int ssh1;
|
||||
char compressionlevel;
|
||||
char *gss_server_identity;
|
||||
char *gss_client_identity;
|
||||
int gss_delegate_creds;
|
||||
} opts;
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ void ssh_socket_set_write_wontblock(ssh_socket s);
|
||||
void ssh_socket_set_read_wontblock(ssh_socket s);
|
||||
void ssh_socket_set_except(ssh_socket s);
|
||||
int ssh_socket_get_status(ssh_socket s);
|
||||
int ssh_socket_get_poll_flags(ssh_socket s);
|
||||
int ssh_socket_buffered_write_bytes(ssh_socket s);
|
||||
int ssh_socket_data_available(ssh_socket s);
|
||||
int ssh_socket_data_writable(ssh_socket s);
|
||||
|
||||
@@ -53,6 +53,9 @@ void sha1(unsigned char *digest,int len,unsigned char *hash);
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash);
|
||||
|
||||
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen);
|
||||
EVPCTX evp_init(int nid);
|
||||
void evp_update(EVPCTX ctx, const void *data, unsigned long len);
|
||||
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen);
|
||||
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type);
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len);
|
||||
@@ -67,5 +70,6 @@ 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);
|
||||
|
||||
#endif /* WRAPPER_H_ */
|
||||
|
||||
@@ -7,5 +7,7 @@ else()
|
||||
set(LIBSSH_INCLUDE_DIR @INCLUDE_INSTALL_DIR@)
|
||||
endif()
|
||||
|
||||
set(LIBSSH_LIRBARY @LIB_INSTALL_DIR@/libssh.so)
|
||||
set(LIBSSH_LIRBARIES @LIB_INSTALL_DIR@/libssh.so)
|
||||
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@)
|
||||
|
||||
@@ -76,6 +76,18 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
)
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
if (WITH_NACL AND NACL_FOUND)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
${NACL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
${NACL_LIBRARY}
|
||||
)
|
||||
endif (WITH_NACL AND NACL_FOUND)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
CACHE INTERNAL "libssh link libraries"
|
||||
@@ -103,6 +115,7 @@ set(libssh_SRCS
|
||||
client.c
|
||||
config.c
|
||||
connect.c
|
||||
curve25519.c
|
||||
dh.c
|
||||
ecdh.c
|
||||
error.c
|
||||
@@ -192,6 +205,13 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
)
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
if (NOT WITH_NACL)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
curve25519_ref.c
|
||||
)
|
||||
endif (NOT WITH_NACL)
|
||||
|
||||
include_directories(
|
||||
${LIBSSH_PUBLIC_INCLUDE_DIRS}
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
@@ -268,6 +288,6 @@ if (WITH_STATIC_LIB)
|
||||
)
|
||||
endif (WITH_STATIC_LIB)
|
||||
|
||||
if (CMAKE_HAVE_THREADS_LIBRARY)
|
||||
if (Threads_FOUND)
|
||||
add_subdirectory(threads)
|
||||
endif (CMAKE_HAVE_THREADS_LIBRARY)
|
||||
endif (Threads_FOUND)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2008-2009 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
||||
16
src/auth.c
16
src/auth.c
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2011 by Aris Adamantiadis <aris@0xbadc0de.be>
|
||||
* Copyright (c) 2008-2011 Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2003-2013 by Aris Adamantiadis <aris@0xbadc0de.be>
|
||||
* Copyright (c) 2008-2013 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
|
||||
@@ -355,7 +355,7 @@ int ssh_userauth_list(ssh_session session, const char *username)
|
||||
* later.
|
||||
*
|
||||
* @note Most server implementations do not permit changing the username during
|
||||
* authentication. The username should only be set with ssh_optoins_set() only
|
||||
* authentication. The username should only be set with ssh_options_set() only
|
||||
* before you connect to the server.
|
||||
*/
|
||||
int ssh_userauth_none(ssh_session session, const char *username) {
|
||||
@@ -478,7 +478,7 @@ fail:
|
||||
* later.
|
||||
*
|
||||
* @note Most server implementations do not permit changing the username during
|
||||
* authentication. The username should only be set with ssh_optoins_set() only
|
||||
* authentication. The username should only be set with ssh_options_set() only
|
||||
* before you connect to the server.
|
||||
*/
|
||||
int ssh_userauth_try_publickey(ssh_session session,
|
||||
@@ -640,7 +640,7 @@ fail:
|
||||
* later.
|
||||
*
|
||||
* @note Most server implementations do not permit changing the username during
|
||||
* authentication. The username should only be set with ssh_optoins_set() only
|
||||
* authentication. The username should only be set with ssh_options_set() only
|
||||
* before you connect to the server.
|
||||
*/
|
||||
int ssh_userauth_publickey(ssh_session session,
|
||||
@@ -961,7 +961,7 @@ struct ssh_agent_state_struct {
|
||||
* later.
|
||||
*
|
||||
* @note Most server implementations do not permit changing the username during
|
||||
* authentication. The username should only be set with ssh_optoins_set() only
|
||||
* authentication. The username should only be set with ssh_options_set() only
|
||||
* before you connect to the server.
|
||||
*/
|
||||
int ssh_userauth_agent(ssh_session session,
|
||||
@@ -1083,7 +1083,7 @@ struct ssh_auth_auto_state_struct {
|
||||
* later.
|
||||
*
|
||||
* @note Most server implementations do not permit changing the username during
|
||||
* authentication. The username should only be set with ssh_optoins_set() only
|
||||
* authentication. The username should only be set with ssh_options_set() only
|
||||
* before you connect to the server.
|
||||
*/
|
||||
int ssh_userauth_publickey_auto(ssh_session session,
|
||||
@@ -1297,7 +1297,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
||||
* later.
|
||||
*
|
||||
* @note Most server implementations do not permit changing the username during
|
||||
* authentication. The username should only be set with ssh_optoins_set() only
|
||||
* authentication. The username should only be set with ssh_options_set() only
|
||||
* before you connect to the server.
|
||||
*
|
||||
* @see ssh_userauth_none()
|
||||
|
||||
78
src/bind.c
78
src/bind.c
@@ -144,26 +144,19 @@ ssh_bind ssh_bind_new(void) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int ssh_bind_listen(ssh_bind sshbind) {
|
||||
const char *host;
|
||||
socket_t fd;
|
||||
static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
int rc;
|
||||
|
||||
if (ssh_init() < 0) {
|
||||
ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sshbind->ecdsakey == NULL &&
|
||||
sshbind->dsakey == NULL &&
|
||||
sshbind->rsakey == NULL) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"DSA or RSA host key file must be set before listen()");
|
||||
"ECDSA, DSA, or RSA host key file must be set");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
if (sshbind->ecdsakey) {
|
||||
if (sshbind->ecdsa == NULL && sshbind->ecdsakey != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->ecdsakey,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -179,12 +172,13 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"The ECDSA host key has the wrong type");
|
||||
ssh_key_free(sshbind->ecdsa);
|
||||
sshbind->ecdsa = NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sshbind->dsakey) {
|
||||
if (sshbind->dsa == NULL && sshbind->dsakey != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->dsakey,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -201,11 +195,12 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
"The DSA host key has the wrong type: %d",
|
||||
ssh_key_type(sshbind->dsa));
|
||||
ssh_key_free(sshbind->dsa);
|
||||
sshbind->dsa = NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (sshbind->rsakey) {
|
||||
if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
|
||||
rc = ssh_pki_import_privkey_file(sshbind->rsakey,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -222,10 +217,29 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"The RSA host key has the wrong type");
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_bind_listen(ssh_bind sshbind) {
|
||||
const char *host;
|
||||
socket_t fd;
|
||||
int rc;
|
||||
|
||||
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) {
|
||||
host = sshbind->bindaddr;
|
||||
if (host == NULL) {
|
||||
@@ -235,10 +249,11 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
fd = bind_socket(sshbind, host, sshbind->bindport);
|
||||
if (fd == SSH_INVALID_SOCKET) {
|
||||
ssh_key_free(sshbind->dsa);
|
||||
sshbind->dsa = NULL;
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
return -1;
|
||||
}
|
||||
sshbind->bindfd = fd;
|
||||
|
||||
if (listen(fd, 10) < 0) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
@@ -246,9 +261,13 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
fd, strerror(errno));
|
||||
close(fd);
|
||||
ssh_key_free(sshbind->dsa);
|
||||
sshbind->dsa = NULL;
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sshbind->bindfd = fd;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_INFO, "Using app-provided bind socket");
|
||||
}
|
||||
@@ -341,11 +360,18 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
|
||||
/* options */
|
||||
SAFE_FREE(sshbind->banner);
|
||||
SAFE_FREE(sshbind->bindaddr);
|
||||
|
||||
SAFE_FREE(sshbind->dsakey);
|
||||
SAFE_FREE(sshbind->rsakey);
|
||||
SAFE_FREE(sshbind->dsa);
|
||||
SAFE_FREE(sshbind->rsa);
|
||||
SAFE_FREE(sshbind->bindaddr);
|
||||
SAFE_FREE(sshbind->ecdsakey);
|
||||
|
||||
ssh_key_free(sshbind->dsa);
|
||||
sshbind->dsa = NULL;
|
||||
ssh_key_free(sshbind->rsa);
|
||||
sshbind->rsa = NULL;
|
||||
ssh_key_free(sshbind->ecdsa);
|
||||
sshbind->ecdsa = NULL;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (sshbind->wanted_methods[i]) {
|
||||
@@ -357,7 +383,7 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
}
|
||||
|
||||
int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
int i;
|
||||
int i, rc;
|
||||
|
||||
if (session == NULL){
|
||||
ssh_set_error(sshbind, SSH_FATAL,"session is null");
|
||||
@@ -388,7 +414,8 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
}
|
||||
|
||||
session->common.log_verbosity = sshbind->common.log_verbosity;
|
||||
|
||||
if(sshbind->banner != NULL)
|
||||
session->opts.custombanner = strdup(sshbind->banner);
|
||||
ssh_socket_free(session->socket);
|
||||
session->socket = ssh_socket_new(session);
|
||||
if (session->socket == NULL) {
|
||||
@@ -399,6 +426,16 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
ssh_socket_set_fd(session->socket, fd);
|
||||
ssh_socket_get_poll_handle_out(session->socket);
|
||||
|
||||
/* We must try to import any keys that could be imported in case
|
||||
* we are not using ssh_bind_listen (which is the other place
|
||||
* where keys can be imported) on this ssh_bind and are instead
|
||||
* only using ssh_bind_accept_fd to manage sockets ourselves.
|
||||
*/
|
||||
rc = ssh_bind_import_keys(sshbind);
|
||||
if (rc != SSH_OK) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
if (sshbind->ecdsa) {
|
||||
session->srv.ecdsa_key = ssh_key_dup(sshbind->ecdsa);
|
||||
@@ -422,6 +459,8 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
/* force PRNG to change state in case we fork after ssh_bind_accept */
|
||||
ssh_reseed();
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -454,8 +493,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
if (session->socket)
|
||||
ssh_socket_close(session->socket);
|
||||
ssh_socket_free(session->socket);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2009-2013 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
|
||||
|
||||
313
src/channels.c
313
src/channels.c
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2003-2013 by Aris Adamantiadis
|
||||
* Copyright (c) 2009-2013 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
|
||||
@@ -177,7 +177,7 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
|
||||
(long unsigned int) channel->remote_maxpacket);
|
||||
|
||||
channel->state = SSH_CHANNEL_STATE_OPEN;
|
||||
channel->flags = channel->flags & ~SSH_CHANNEL_FLAG_NOT_BOUND;
|
||||
channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
@@ -312,7 +312,11 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
|
||||
type_c, channel->local_channel);
|
||||
pending:
|
||||
/* wait until channel is opened by server */
|
||||
err = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, ssh_channel_open_termination, channel);
|
||||
err = ssh_handle_packets_termination(session,
|
||||
SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_open_termination,
|
||||
channel);
|
||||
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
err = SSH_ERROR;
|
||||
end:
|
||||
@@ -631,7 +635,7 @@ SSH_PACKET_CALLBACK(channel_rcv_close) {
|
||||
channel,
|
||||
channel->callbacks->userdata);
|
||||
}
|
||||
channel->flags &= SSH_CHANNEL_FLAG_CLOSED_REMOTE;
|
||||
channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE;
|
||||
if(channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL)
|
||||
ssh_channel_do_free(channel);
|
||||
|
||||
@@ -912,10 +916,10 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len,
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @see channel_open_forward()
|
||||
* @see channel_request_env()
|
||||
* @see channel_request_shell()
|
||||
* @see channel_request_exec()
|
||||
* @see ssh_channel_open_forward()
|
||||
* @see ssh_channel_request_env()
|
||||
* @see ssh_channel_request_shell()
|
||||
* @see ssh_channel_request_exec()
|
||||
*/
|
||||
int ssh_channel_open_session(ssh_channel channel) {
|
||||
if(channel == NULL) {
|
||||
@@ -948,7 +952,7 @@ int ssh_channel_open_session(ssh_channel channel) {
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @see channel_open_forward()
|
||||
* @see ssh_channel_open_forward()
|
||||
*/
|
||||
int ssh_channel_open_auth_agent(ssh_channel channel){
|
||||
if(channel == NULL) {
|
||||
@@ -1074,7 +1078,7 @@ void ssh_channel_free(ssh_channel channel) {
|
||||
if (session->alive && channel->state == SSH_CHANNEL_STATE_OPEN) {
|
||||
ssh_channel_close(channel);
|
||||
}
|
||||
channel->flags &= SSH_CHANNEL_FLAG_FREED_LOCAL;
|
||||
channel->flags |= SSH_CHANNEL_FLAG_FREED_LOCAL;
|
||||
|
||||
/* The idea behind the flags is the following : it is well possible
|
||||
* that a client closes a channel that stills exists on the server side.
|
||||
@@ -1116,8 +1120,24 @@ void ssh_channel_do_free(ssh_channel channel){
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
*
|
||||
* @see channel_close()
|
||||
* @see channel_free()
|
||||
* Example:
|
||||
@code
|
||||
rc = ssh_channel_send_eof(channel);
|
||||
if (rc == SSH_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
while(!ssh_channel_is_eof(channel)) {
|
||||
rc = ssh_channel_read(channel, buf, sizeof(buf), 0);
|
||||
if (rc == SSH_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ssh_channel_close(channel);
|
||||
@endcode
|
||||
*
|
||||
* @see ssh_channel_close()
|
||||
* @see ssh_channel_free()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_send_eof(ssh_channel channel){
|
||||
ssh_session session;
|
||||
@@ -1143,6 +1163,10 @@ int ssh_channel_send_eof(ssh_channel channel){
|
||||
channel->local_channel,
|
||||
channel->remote_channel);
|
||||
|
||||
rc = ssh_channel_flush(channel);
|
||||
if(rc == SSH_ERROR)
|
||||
goto error;
|
||||
|
||||
channel->local_eof = 1;
|
||||
|
||||
return rc;
|
||||
@@ -1162,8 +1186,8 @@ error:
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
*
|
||||
* @see channel_free()
|
||||
* @see channel_eof()
|
||||
* @see ssh_channel_free()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_close(ssh_channel channel){
|
||||
ssh_session session;
|
||||
@@ -1199,6 +1223,10 @@ int ssh_channel_close(ssh_channel channel){
|
||||
channel->state=SSH_CHANNEL_STATE_CLOSED;
|
||||
}
|
||||
|
||||
rc = ssh_channel_flush(channel);
|
||||
if(rc == SSH_ERROR)
|
||||
goto error;
|
||||
|
||||
return rc;
|
||||
error:
|
||||
buffer_reinit(session->out_buffer);
|
||||
@@ -1210,7 +1238,8 @@ error:
|
||||
static int ssh_channel_waitwindow_termination(void *c){
|
||||
ssh_channel channel = (ssh_channel) c;
|
||||
if (channel->remote_window > 0 ||
|
||||
channel->session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
channel->session->session_state == SSH_SESSION_STATE_ERROR ||
|
||||
channel->state == SSH_CHANNEL_STATE_CLOSED)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
@@ -1315,7 +1344,10 @@ int channel_write_common(ssh_channel channel, const void *data,
|
||||
"Wait for a growing window message...");
|
||||
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_waitwindow_termination,channel);
|
||||
if (rc == SSH_ERROR || !ssh_channel_waitwindow_termination(channel))
|
||||
if (rc == SSH_ERROR ||
|
||||
!ssh_channel_waitwindow_termination(channel) ||
|
||||
channel->session->session_state == SSH_SESSION_STATE_ERROR ||
|
||||
channel->state == SSH_CHANNEL_STATE_CLOSED)
|
||||
goto out;
|
||||
continue;
|
||||
}
|
||||
@@ -1383,7 +1415,7 @@ uint32_t ssh_channel_window_size(ssh_channel channel) {
|
||||
*
|
||||
* @return The number of bytes written, SSH_ERROR on error.
|
||||
*
|
||||
* @see channel_read()
|
||||
* @see ssh_channel_read()
|
||||
*/
|
||||
int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len) {
|
||||
return channel_write_common(channel, data, len, 0);
|
||||
@@ -1396,7 +1428,7 @@ int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len) {
|
||||
*
|
||||
* @return 0 if channel is closed, nonzero otherwise.
|
||||
*
|
||||
* @see channel_is_closed()
|
||||
* @see ssh_channel_is_closed()
|
||||
*/
|
||||
int ssh_channel_is_open(ssh_channel channel) {
|
||||
if(channel == NULL) {
|
||||
@@ -1412,7 +1444,7 @@ int ssh_channel_is_open(ssh_channel channel) {
|
||||
*
|
||||
* @return 0 if channel is opened, nonzero otherwise.
|
||||
*
|
||||
* @see channel_is_open()
|
||||
* @see ssh_channel_is_open()
|
||||
*/
|
||||
int ssh_channel_is_closed(ssh_channel channel) {
|
||||
if(channel == NULL) {
|
||||
@@ -1582,7 +1614,11 @@ static int channel_request(ssh_channel channel, const char *request,
|
||||
return SSH_OK;
|
||||
}
|
||||
pending:
|
||||
rc = ssh_handle_packets_termination(session,SSH_TIMEOUT_USER, ssh_channel_request_termination, channel);
|
||||
rc = ssh_handle_packets_termination(session,
|
||||
SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_request_termination,
|
||||
channel);
|
||||
|
||||
if(session->session_state == SSH_SESSION_STATE_ERROR || rc == SSH_ERROR) {
|
||||
channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR;
|
||||
}
|
||||
@@ -1707,7 +1743,7 @@ error:
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @see channel_request_pty_size()
|
||||
* @see ssh_channel_request_pty_size()
|
||||
*/
|
||||
int ssh_channel_request_pty(ssh_channel channel) {
|
||||
return ssh_channel_request_pty_size(channel, "xterm", 80, 24);
|
||||
@@ -1946,7 +1982,7 @@ error:
|
||||
}
|
||||
|
||||
static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
|
||||
int timeout_ms) {
|
||||
int timeout_ms, int *destination_port) {
|
||||
#ifndef _WIN32
|
||||
static const struct timespec ts = {
|
||||
.tv_sec = 0,
|
||||
@@ -1958,9 +1994,16 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
|
||||
struct ssh_iterator *iterator;
|
||||
int t;
|
||||
|
||||
for (t = timeout_ms; t >= 0; t -= 50)
|
||||
{
|
||||
ssh_handle_packets(session, 50);
|
||||
/*
|
||||
* We sleep for 50 ms in ssh_handle_packets() and later sleep for
|
||||
* 50 ms. So we need to decrement by 100 ms.
|
||||
*/
|
||||
for (t = timeout_ms; t >= 0; t -= 100) {
|
||||
if (timeout_ms == 0) {
|
||||
ssh_handle_packets(session, 0);
|
||||
} else {
|
||||
ssh_handle_packets(session, 50);
|
||||
}
|
||||
|
||||
if (session->ssh_message_list) {
|
||||
iterator = ssh_list_get_iterator(session->ssh_message_list);
|
||||
@@ -1970,6 +2013,10 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
|
||||
ssh_message_subtype(msg) == channeltype) {
|
||||
ssh_list_remove(session->ssh_message_list, iterator);
|
||||
channel = ssh_message_channel_request_open_reply_accept(msg);
|
||||
if(destination_port) {
|
||||
*destination_port=msg->channel_request_open.destination_port;
|
||||
}
|
||||
|
||||
ssh_message_free(msg);
|
||||
return channel;
|
||||
}
|
||||
@@ -2000,7 +2047,7 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
|
||||
* the server.
|
||||
*/
|
||||
ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms) {
|
||||
return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms);
|
||||
return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2053,7 +2100,7 @@ SSH_PACKET_CALLBACK(ssh_request_denied){
|
||||
static int ssh_global_request_termination(void *s){
|
||||
ssh_session session = (ssh_session) s;
|
||||
if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING ||
|
||||
session->session_state != SSH_SESSION_STATE_ERROR)
|
||||
session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
@@ -2081,47 +2128,73 @@ static int ssh_global_request_termination(void *s){
|
||||
static int global_request(ssh_session session, const char *request,
|
||||
ssh_buffer buffer, int reply) {
|
||||
ssh_string req = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
int rc;
|
||||
|
||||
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE)
|
||||
switch (session->global_req_state) {
|
||||
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||
break;
|
||||
default:
|
||||
goto pending;
|
||||
}
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
req = ssh_string_from_char(request);
|
||||
if (req == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
ssh_set_error_oom(session);
|
||||
rc = SSH_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 ||
|
||||
buffer_add_ssh_string(session->out_buffer, req) < 0 ||
|
||||
buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
rc = buffer_add_ssh_string(session->out_buffer, req);
|
||||
ssh_string_free(req);
|
||||
req=NULL;
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
rc = SSH_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
rc = SSH_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffer != NULL) {
|
||||
if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer),
|
||||
buffer_get_rest_len(buffer)) < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
rc = buffer_add_data(session->out_buffer,
|
||||
buffer_get_rest(buffer),
|
||||
buffer_get_rest_len(buffer));
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
rc = SSH_ERROR;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
return rc;
|
||||
rc = packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
|
||||
if (reply == 0) {
|
||||
session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE;
|
||||
|
||||
return SSH_OK;
|
||||
if (reply == 0) {
|
||||
session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE;
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
pending:
|
||||
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
|
||||
ssh_global_request_termination, session);
|
||||
rc = ssh_handle_packets_termination(session,
|
||||
SSH_TIMEOUT_DEFAULT,
|
||||
ssh_global_request_termination,
|
||||
session);
|
||||
|
||||
if(rc==SSH_ERROR || session->session_state == SSH_SESSION_STATE_ERROR){
|
||||
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
|
||||
}
|
||||
@@ -2139,16 +2212,16 @@ pending:
|
||||
break;
|
||||
case SSH_CHANNEL_REQ_STATE_ERROR:
|
||||
case SSH_CHANNEL_REQ_STATE_NONE:
|
||||
rc=SSH_ERROR;
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
case SSH_CHANNEL_REQ_STATE_PENDING:
|
||||
rc=SSH_AGAIN;
|
||||
break;
|
||||
return SSH_AGAIN;
|
||||
}
|
||||
session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE;
|
||||
|
||||
return rc;
|
||||
error:
|
||||
ssh_string_free(req);
|
||||
buffer_reinit(session->out_buffer);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -2228,7 +2301,23 @@ error:
|
||||
* the server
|
||||
*/
|
||||
ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) {
|
||||
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms);
|
||||
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accept an incoming TCP/IP forwarding channel and get information
|
||||
* about incomming connection
|
||||
* @param[in] session The ssh session to use.
|
||||
*
|
||||
* @param[in] timeout_ms A timeout in milliseconds.
|
||||
*
|
||||
* @param[in] destination_port A pointer to destination port or NULL.
|
||||
*
|
||||
* @return Newly created channel, or NULL if no incoming channel request from
|
||||
* the server
|
||||
*/
|
||||
ssh_channel ssh_channel_accept_forward(ssh_session session, int timeout_ms, int* destination_port) {
|
||||
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, destination_port);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2364,20 +2453,22 @@ error:
|
||||
* SSH_ERROR if an error occurred,
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
* @code
|
||||
* rc = channel_request_exec(channel, "ps aux");
|
||||
* if (rc > 0) {
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
* if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
|
||||
* return -1;
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
* Example:
|
||||
@code
|
||||
rc = channel_request_exec(channel, "ps aux");
|
||||
if (rc > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
|
||||
if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
*
|
||||
* @see channel_request_shell()
|
||||
* @see ssh_channel_request_shell()
|
||||
*/
|
||||
int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
|
||||
ssh_buffer buffer = NULL;
|
||||
@@ -2615,15 +2706,48 @@ static int ssh_channel_read_termination(void *s){
|
||||
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
|
||||
*
|
||||
* @return The number of bytes read, 0 on end of file or SSH_ERROR
|
||||
* on error. Can return 0 if nothing is available in nonblocking
|
||||
* mode.
|
||||
* on error. In nonblocking mode it Can return 0 if no data
|
||||
* is available or SSH_AGAIN.
|
||||
*
|
||||
* @warning This function may return less than count bytes of data, and won't
|
||||
* block until count bytes have been read.
|
||||
* @warning The read function using a buffer has been renamed to
|
||||
* channel_read_buffer().
|
||||
*/
|
||||
int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr) {
|
||||
int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr)
|
||||
{
|
||||
return ssh_channel_read_timeout(channel, dest, count, is_stderr, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads data from a channel.
|
||||
*
|
||||
* @param[in] channel The channel to read from.
|
||||
*
|
||||
* @param[in] dest The destination buffer which will get the data.
|
||||
*
|
||||
* @param[in] count The count of bytes to be read.
|
||||
*
|
||||
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
|
||||
*
|
||||
* @param[in] timeout_ms A timeout in milliseconds. A value of -1 means
|
||||
* infinite timeout.
|
||||
*
|
||||
* @return The number of bytes read, 0 on end of file or SSH_ERROR
|
||||
* on error. In nonblocking mode it Can return 0 if no data
|
||||
* is available or SSH_AGAIN.
|
||||
*
|
||||
* @warning This function may return less than count bytes of data, and won't
|
||||
* block until count bytes have been read.
|
||||
* @warning The read function using a buffer has been renamed to
|
||||
* channel_read_buffer().
|
||||
*/
|
||||
int ssh_channel_read_timeout(ssh_channel channel,
|
||||
void *dest,
|
||||
uint32_t count,
|
||||
int is_stderr,
|
||||
int timeout)
|
||||
{
|
||||
ssh_session session;
|
||||
ssh_buffer stdbuf;
|
||||
uint32_t len;
|
||||
@@ -2671,8 +2795,15 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
|
||||
ctx.channel = channel;
|
||||
ctx.buffer = stdbuf;
|
||||
ctx.count = 1;
|
||||
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_read_termination, &ctx);
|
||||
|
||||
if (timeout < 0) {
|
||||
timeout = SSH_TIMEOUT_DEFAULT;
|
||||
}
|
||||
|
||||
rc = ssh_handle_packets_termination(session,
|
||||
timeout,
|
||||
ssh_channel_read_termination,
|
||||
&ctx);
|
||||
if (rc == SSH_ERROR){
|
||||
return rc;
|
||||
}
|
||||
@@ -2716,7 +2847,7 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
|
||||
*
|
||||
* @warning Don't forget to check for EOF as it would return 0 here.
|
||||
*
|
||||
* @see channel_is_eof()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
|
||||
int is_stderr) {
|
||||
@@ -2768,7 +2899,7 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count
|
||||
*
|
||||
* @warning When the channel is in EOF state, the function returns SSH_EOF.
|
||||
*
|
||||
* @see channel_is_eof()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_poll(ssh_channel channel, int is_stderr){
|
||||
ssh_buffer stdbuf;
|
||||
@@ -2820,7 +2951,7 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
|
||||
*
|
||||
* @warning When the channel is in EOF state, the function returns SSH_EOF.
|
||||
*
|
||||
* @see channel_is_eof()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr){
|
||||
ssh_session session;
|
||||
@@ -2893,14 +3024,21 @@ static int ssh_channel_exit_status_termination(void *c){
|
||||
* (yet).
|
||||
* @warning This function may block until a timeout (or never)
|
||||
* if the other side is not willing to close the channel.
|
||||
*
|
||||
* If you're looking for an async handling of this register a callback for the
|
||||
* exit status.
|
||||
*
|
||||
* @see ssh_channel_exit_status_callback
|
||||
*/
|
||||
int ssh_channel_get_exit_status(ssh_channel channel) {
|
||||
int rc;
|
||||
if(channel == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
rc = ssh_handle_packets_termination(channel->session, SSH_TIMEOUT_USER,
|
||||
ssh_channel_exit_status_termination, channel);
|
||||
rc = ssh_handle_packets_termination(channel->session,
|
||||
SSH_TIMEOUT_DEFAULT,
|
||||
ssh_channel_exit_status_termination,
|
||||
channel);
|
||||
if (rc == SSH_ERROR || channel->session->session_state ==
|
||||
SSH_SESSION_STATE_ERROR)
|
||||
return SSH_ERROR;
|
||||
@@ -3123,7 +3261,7 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
*
|
||||
* @return The number of bytes written, SSH_ERROR on error.
|
||||
*
|
||||
* @see channel_read()
|
||||
* @see ssh_channel_read()
|
||||
*/
|
||||
int ssh_channel_write_stderr(ssh_channel channel, const void *data, uint32_t len) {
|
||||
return channel_write_common(channel, data, len, 1);
|
||||
@@ -3284,17 +3422,18 @@ error:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send the exit status to the remote process (as described in RFC 4254, section 6.10).
|
||||
* @brief Send the exit status to the remote process
|
||||
*
|
||||
* Sends the exit status to the remote process.
|
||||
* Sends the exit status to the remote process (as described in RFC 4254,
|
||||
* section 6.10).
|
||||
* Only SSH-v2 is supported (I'm not sure about SSH-v1).
|
||||
*
|
||||
* @param[in] channel The channel to send exit status.
|
||||
*
|
||||
* @param[in] sig The exit status to send
|
||||
* @param[in] exit_status The exit status to send
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred
|
||||
* (including attempts to send exit status via SSH-v1 session).
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
* (including attempts to send exit status via SSH-v1 session).
|
||||
*/
|
||||
int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
|
||||
ssh_buffer buffer = NULL;
|
||||
@@ -3328,9 +3467,9 @@ error:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send an exit signal to remote process (as described in RFC 4254, section 6.10).
|
||||
* @brief Send an exit signal to remote process (RFC 4254, section 6.10).
|
||||
*
|
||||
* Sends a signal 'sig' to the remote process.
|
||||
* This sends the exit status of the remote process.
|
||||
* Note, that remote system may not support signals concept.
|
||||
* In such a case this request will be silently ignored.
|
||||
* Only SSH-v2 is supported (I'm not sure about SSH-v1).
|
||||
@@ -3408,7 +3547,7 @@ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig,
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = channel_request(channel, "signal", buffer, 0);
|
||||
rc = channel_request(channel, "exit-signal", buffer, 0);
|
||||
error:
|
||||
ssh_buffer_free(buffer);
|
||||
if(tmp)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* 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
|
||||
|
||||
64
src/client.c
64
src/client.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-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
|
||||
@@ -60,12 +60,15 @@
|
||||
static void socket_callback_connected(int code, int errno_code, void *user){
|
||||
ssh_session session=(ssh_session)user;
|
||||
|
||||
if(session->session_state != SSH_SESSION_STATE_CONNECTING){
|
||||
if (session->session_state != SSH_SESSION_STATE_CONNECTING &&
|
||||
session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED)
|
||||
{
|
||||
ssh_set_error(session,SSH_FATAL, "Wrong state in socket_callback_connected : %d",
|
||||
session->session_state);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code);
|
||||
if(code == SSH_SOCKET_CONNECTED_OK)
|
||||
session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
|
||||
@@ -105,14 +108,18 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
|
||||
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'){
|
||||
buffer[i]='\0';
|
||||
str=strdup(buffer);
|
||||
/* number of bytes read */
|
||||
ret=i+1;
|
||||
session->serverbanner=str;
|
||||
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);
|
||||
@@ -148,19 +155,27 @@ int ssh_send_banner(ssh_session session, int server) {
|
||||
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
|
||||
|
||||
if (server) {
|
||||
session->serverbanner = strdup(banner);
|
||||
if(session->opts.custombanner == NULL){
|
||||
session->serverbanner = strdup(banner);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
snprintf(buffer, 128, "%s\n", banner);
|
||||
|
||||
if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) {
|
||||
goto end;
|
||||
}
|
||||
@@ -196,6 +211,11 @@ static int dh_handshake(ssh_session session) {
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
rc = ssh_client_ecdh_init(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
rc = ssh_client_curve25519_init(session);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rc = SSH_ERROR;
|
||||
@@ -495,6 +515,7 @@ int ssh_connect(ssh_session session) {
|
||||
session->socket_callbacks.exception=ssh_socket_exception_callback;
|
||||
session->socket_callbacks.userdata=session;
|
||||
if (session->opts.fd != SSH_INVALID_SOCKET) {
|
||||
session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
|
||||
ssh_socket_set_fd(session->socket, session->opts.fd);
|
||||
ret=SSH_OK;
|
||||
#ifndef _WIN32
|
||||
@@ -526,7 +547,8 @@ pending:
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PACKET,"ssh_connect: Actual timeout : %d", timeout);
|
||||
ret = ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session);
|
||||
if (ret == SSH_ERROR || !ssh_connect_termination(session)) {
|
||||
if (session->session_state != SSH_SESSION_STATE_ERROR &&
|
||||
(ret == SSH_ERROR || !ssh_connect_termination(session))) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Timeout connecting to %s", session->opts.host);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
@@ -579,6 +601,14 @@ char *ssh_get_issue_banner(ssh_session session) {
|
||||
* @param[in] session The SSH session to use.
|
||||
*
|
||||
* @return The version number if available, 0 otherwise.
|
||||
*
|
||||
* @code
|
||||
* int openssh = ssh_get_openssh_version();
|
||||
*
|
||||
* if (openssh == SSH_INT_VERSION(6, 1, 0)) {
|
||||
* printf("Version match!\m");
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
int ssh_get_openssh_version(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
@@ -634,7 +664,7 @@ error:
|
||||
session->session_state=SSH_SESSION_STATE_DISCONNECTED;
|
||||
|
||||
while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
|
||||
ssh_channel_free(ssh_iterator_value(ssh_channel,it));
|
||||
ssh_channel_do_free(ssh_iterator_value(ssh_channel,it));
|
||||
ssh_list_remove(session->channels, it);
|
||||
}
|
||||
if(session->current_crypto){
|
||||
@@ -670,8 +700,8 @@ error:
|
||||
}
|
||||
|
||||
const char *ssh_copyright(void) {
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2010 Aris Adamantiadis "
|
||||
"(aris@0xbadc0de.be) Distributed under the LGPL, please refer to COPYING "
|
||||
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";
|
||||
}
|
||||
/** @} */
|
||||
|
||||
57
src/config.c
57
src/config.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2009-2013 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
|
||||
@@ -46,7 +46,10 @@ enum ssh_config_opcode_e {
|
||||
SOC_PROTOCOL,
|
||||
SOC_STRICTHOSTKEYCHECK,
|
||||
SOC_KNOWNHOSTS,
|
||||
SOC_PROXYCOMMAND
|
||||
SOC_PROXYCOMMAND,
|
||||
SOC_GSSAPISERVERIDENTITY,
|
||||
SOC_GSSAPICLIENTIDENTITY,
|
||||
SOC_GSSAPIDELEGATECREDENTIALS,
|
||||
};
|
||||
|
||||
struct ssh_config_keyword_table_s {
|
||||
@@ -67,6 +70,9 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "stricthostkeychecking", SOC_STRICTHOSTKEYCHECK },
|
||||
{ "userknownhostsfile", SOC_KNOWNHOSTS },
|
||||
{ "proxycommand", SOC_PROXYCOMMAND },
|
||||
{ "gssapiserveridentity", SOC_GSSAPISERVERIDENTITY },
|
||||
{ "gssapiserveridentity", SOC_GSSAPICLIENTIDENTITY },
|
||||
{ "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
|
||||
{ NULL, SOC_UNSUPPORTED }
|
||||
};
|
||||
|
||||
@@ -122,7 +128,7 @@ static char *ssh_config_get_token(char **str) {
|
||||
c = ssh_config_get_cmd(str);
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (isblank(*c)) {
|
||||
if (isblank(*c) || *c == '=') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
@@ -213,16 +219,25 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
|
||||
switch (opcode) {
|
||||
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 && *p;
|
||||
p = ssh_config_get_str_tok(&s, NULL)) {
|
||||
if (match_hostname(lowerhost, p, strlen(p))) {
|
||||
*parsing = 1;
|
||||
*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)) {
|
||||
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;
|
||||
SAFE_FREE(lowerhost);
|
||||
break;
|
||||
case SOC_HOSTNAME:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
@@ -323,6 +338,24 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
|
||||
}
|
||||
break;
|
||||
case SOC_GSSAPISERVERIDENTITY:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_GSSAPI_SERVER_IDENTITY, p);
|
||||
}
|
||||
break;
|
||||
case SOC_GSSAPICLIENTIDENTITY:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY, p);
|
||||
}
|
||||
break;
|
||||
case SOC_GSSAPIDELEGATECREDENTIALS:
|
||||
i = ssh_config_get_yesno(&s, -1);
|
||||
if (i >=0 && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, &i);
|
||||
}
|
||||
break;
|
||||
case SOC_UNSUPPORTED:
|
||||
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d\n",
|
||||
keyword, count);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-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
|
||||
@@ -382,7 +382,15 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
continue;
|
||||
}
|
||||
|
||||
connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
if (rc == -1 && (errno != EINPROGRESS)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to connect: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -421,7 +429,7 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
||||
* @param[in] readfds A fd_set of file descriptors to be select'ed for
|
||||
* reading.
|
||||
*
|
||||
* @param[in] timeout A timeout for the select.
|
||||
* @param[in] timeout The timeout in milliseconds.
|
||||
*
|
||||
* @return SSH_OK on success,
|
||||
* SSH_ERROR on error,
|
||||
@@ -436,6 +444,7 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
||||
*/
|
||||
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
fd_set *readfds, struct timeval *timeout) {
|
||||
fd_set origfds;
|
||||
socket_t fd;
|
||||
int i,j;
|
||||
int rc;
|
||||
@@ -449,9 +458,11 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
ssh_event_add_session(event, channels[i]->session);
|
||||
}
|
||||
|
||||
FD_ZERO(&origfds);
|
||||
for (fd = 0; fd < maxfd ; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||
FD_SET(fd, &origfds);
|
||||
}
|
||||
}
|
||||
outchannels[0] = NULL;
|
||||
@@ -485,13 +496,17 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
/* since there's nothing, let's fire the polling */
|
||||
rc = ssh_event_dopoll(event,tm);
|
||||
if (rc == SSH_ERROR){
|
||||
ssh_event_free(event);
|
||||
return SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
tm = ssh_timeout_update(&ts, base_tm);
|
||||
firstround=0;
|
||||
} while (1);
|
||||
out:
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, &origfds)) {
|
||||
ssh_event_remove_fd(event, fd);
|
||||
}
|
||||
}
|
||||
ssh_event_free(event);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
292
src/curve25519.c
Normal file
292
src/curve25519.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* curve25519.c - Curve25519 ECDH functions for key exchange
|
||||
* curve25519-sha256@libssh.org
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013 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, version 2.1 of the License.
|
||||
*
|
||||
* 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/curve25519.h"
|
||||
#ifdef HAVE_CURVE25519
|
||||
|
||||
#ifdef WITH_NACL
|
||||
#include "nacl/crypto_scalarmult_curve25519.h"
|
||||
#endif
|
||||
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/pki.h"
|
||||
|
||||
/** @internal
|
||||
* @brief Starts curve25519-sha256@libssh.org key exchange
|
||||
*/
|
||||
int ssh_client_curve25519_init(ssh_session session){
|
||||
ssh_string client_pubkey;
|
||||
int rc;
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
|
||||
if (rc < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
client_pubkey = ssh_string_new(CURVE25519_PUBKEY_SIZE);
|
||||
if (client_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ssh_string_fill(client_pubkey, session->next_crypto->curve25519_client_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
rc = buffer_add_ssh_string(session->out_buffer,client_pubkey);
|
||||
ssh_string_free(client_pubkey);
|
||||
if (rc < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = packet_send(session);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ssh_curve25519_build_k(ssh_session session) {
|
||||
ssh_curve25519_pubkey k;
|
||||
session->next_crypto->k = bignum_new();
|
||||
|
||||
if (session->next_crypto->k == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->server)
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
else
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
|
||||
|
||||
#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
|
||||
* a SSH_MSG_NEWKEYS
|
||||
*/
|
||||
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE){
|
||||
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
|
||||
(int)ssh_string_len(q_s_string));
|
||||
ssh_string_free(q_s_string);
|
||||
goto error;
|
||||
}
|
||||
memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE);
|
||||
ssh_string_free(q_s_string);
|
||||
|
||||
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 */
|
||||
/* TODO: verify signature now instead of waiting for NEWKEYS */
|
||||
if (ssh_curve25519_build_k(session) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
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_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
|
||||
/* SSH host keys (rsa,dsa,ecdsa) */
|
||||
ssh_key privkey;
|
||||
ssh_string sig_blob = NULL;
|
||||
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;
|
||||
}
|
||||
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
|
||||
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
|
||||
(int)ssh_string_len(q_c_string));
|
||||
ssh_string_free(q_c_string);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
memcpy(session->next_crypto->curve25519_client_pubkey,
|
||||
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
|
||||
ssh_string_free(q_c_string);
|
||||
/* Build server's keypair */
|
||||
|
||||
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (rc == 0){
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* build k and session_id */
|
||||
rc = ssh_curve25519_build_k(session);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* privkey is not allocated */
|
||||
rc = ssh_get_key_params(session, &privkey);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = make_sessionid(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* add host's public key */
|
||||
rc = buffer_add_ssh_string(session->out_buffer,
|
||||
session->next_crypto->server_pubkey);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* add ecdh public key */
|
||||
q_s_string = ssh_string_new(CURVE25519_PUBKEY_SIZE);
|
||||
if (q_s_string == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ssh_string_fill(q_s_string,
|
||||
session->next_crypto->curve25519_server_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
|
||||
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);
|
||||
goto error;
|
||||
}
|
||||
/* add signature blob */
|
||||
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");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = buffer_add_ssh_string(session->out_buffer, sig_blob);
|
||||
ssh_string_free(sig_blob);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_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) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
rc = packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
return rc;
|
||||
error:
|
||||
buffer_reinit(session->out_buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* HAVE_CURVE25519 */
|
||||
272
src/curve25519_ref.c
Normal file
272
src/curve25519_ref.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
version 20081011
|
||||
Matthew Dempsky
|
||||
Public domain.
|
||||
Derived from public domain code by D. J. Bernstein.
|
||||
*/
|
||||
|
||||
#include "libssh/curve25519.h"
|
||||
static const unsigned char base[32] = {9};
|
||||
|
||||
int crypto_scalarmult_base(unsigned char *q,
|
||||
const unsigned char *n)
|
||||
{
|
||||
return crypto_scalarmult(q,n,base);
|
||||
}
|
||||
|
||||
static void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int u;
|
||||
u = 0;
|
||||
for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; }
|
||||
u += a[31] + b[31]; out[31] = u;
|
||||
}
|
||||
|
||||
static void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int u;
|
||||
u = 218;
|
||||
for (j = 0;j < 31;++j) {
|
||||
u += a[j] + 65280 - b[j];
|
||||
out[j] = u & 255;
|
||||
u >>= 8;
|
||||
}
|
||||
u += a[31] - b[31];
|
||||
out[31] = u;
|
||||
}
|
||||
|
||||
static void squeeze(unsigned int a[32])
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int u;
|
||||
u = 0;
|
||||
for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
|
||||
u += a[31]; a[31] = u & 127;
|
||||
u = 19 * (u >> 7);
|
||||
for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
|
||||
u += a[31]; a[31] = u;
|
||||
}
|
||||
|
||||
static const unsigned int minusp[32] = {
|
||||
19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128
|
||||
} ;
|
||||
|
||||
static void freeze(unsigned int a[32])
|
||||
{
|
||||
unsigned int aorig[32];
|
||||
unsigned int j;
|
||||
unsigned int negative;
|
||||
|
||||
for (j = 0;j < 32;++j) aorig[j] = a[j];
|
||||
add(a,a,minusp);
|
||||
negative = -((a[31] >> 7) & 1);
|
||||
for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]);
|
||||
}
|
||||
|
||||
static void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
unsigned int u;
|
||||
|
||||
for (i = 0;i < 32;++i) {
|
||||
u = 0;
|
||||
for (j = 0;j <= i;++j) u += a[j] * b[i - j];
|
||||
for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j];
|
||||
out[i] = u;
|
||||
}
|
||||
squeeze(out);
|
||||
}
|
||||
|
||||
static void mult121665(unsigned int out[32],const unsigned int a[32])
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int u;
|
||||
|
||||
u = 0;
|
||||
for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; }
|
||||
u += 121665 * a[31]; out[31] = u & 127;
|
||||
u = 19 * (u >> 7);
|
||||
for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; }
|
||||
u += out[j]; out[j] = u;
|
||||
}
|
||||
|
||||
static void square(unsigned int out[32],const unsigned int a[32])
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
unsigned int u;
|
||||
|
||||
for (i = 0;i < 32;++i) {
|
||||
u = 0;
|
||||
for (j = 0;j < i - j;++j) u += a[j] * a[i - j];
|
||||
for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j];
|
||||
u *= 2;
|
||||
if ((i & 1) == 0) {
|
||||
u += a[i / 2] * a[i / 2];
|
||||
u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
|
||||
}
|
||||
out[i] = u;
|
||||
}
|
||||
squeeze(out);
|
||||
}
|
||||
|
||||
static void c_select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b)
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int t;
|
||||
unsigned int bminus1;
|
||||
|
||||
bminus1 = b - 1;
|
||||
for (j = 0;j < 64;++j) {
|
||||
t = bminus1 & (r[j] ^ s[j]);
|
||||
p[j] = s[j] ^ t;
|
||||
q[j] = r[j] ^ t;
|
||||
}
|
||||
}
|
||||
|
||||
static void mainloop(unsigned int work[64],const unsigned char e[32])
|
||||
{
|
||||
unsigned int xzm1[64];
|
||||
unsigned int xzm[64];
|
||||
unsigned int xzmb[64];
|
||||
unsigned int xzm1b[64];
|
||||
unsigned int xznb[64];
|
||||
unsigned int xzn1b[64];
|
||||
unsigned int a0[64];
|
||||
unsigned int a1[64];
|
||||
unsigned int b0[64];
|
||||
unsigned int b1[64];
|
||||
unsigned int c1[64];
|
||||
unsigned int r[32];
|
||||
unsigned int s[32];
|
||||
unsigned int t[32];
|
||||
unsigned int u[32];
|
||||
unsigned int j;
|
||||
unsigned int b;
|
||||
int pos;
|
||||
|
||||
for (j = 0;j < 32;++j) xzm1[j] = work[j];
|
||||
xzm1[32] = 1;
|
||||
for (j = 33;j < 64;++j) xzm1[j] = 0;
|
||||
|
||||
xzm[0] = 1;
|
||||
for (j = 1;j < 64;++j) xzm[j] = 0;
|
||||
|
||||
for (pos = 254;pos >= 0;--pos) {
|
||||
b = e[pos / 8] >> (pos & 7);
|
||||
b &= 1;
|
||||
c_select(xzmb,xzm1b,xzm,xzm1,b);
|
||||
add(a0,xzmb,xzmb + 32);
|
||||
sub(a0 + 32,xzmb,xzmb + 32);
|
||||
add(a1,xzm1b,xzm1b + 32);
|
||||
sub(a1 + 32,xzm1b,xzm1b + 32);
|
||||
square(b0,a0);
|
||||
square(b0 + 32,a0 + 32);
|
||||
mult(b1,a1,a0 + 32);
|
||||
mult(b1 + 32,a1 + 32,a0);
|
||||
add(c1,b1,b1 + 32);
|
||||
sub(c1 + 32,b1,b1 + 32);
|
||||
square(r,c1 + 32);
|
||||
sub(s,b0,b0 + 32);
|
||||
mult121665(t,s);
|
||||
add(u,t,b0);
|
||||
mult(xznb,b0,b0 + 32);
|
||||
mult(xznb + 32,s,u);
|
||||
square(xzn1b,c1);
|
||||
mult(xzn1b + 32,r,work);
|
||||
c_select(xzm,xzm1,xznb,xzn1b,b);
|
||||
}
|
||||
|
||||
for (j = 0;j < 64;++j) work[j] = xzm[j];
|
||||
}
|
||||
|
||||
static void recip(unsigned int out[32],const unsigned int z[32])
|
||||
{
|
||||
unsigned int z2[32];
|
||||
unsigned int z9[32];
|
||||
unsigned int z11[32];
|
||||
unsigned int z2_5_0[32];
|
||||
unsigned int z2_10_0[32];
|
||||
unsigned int z2_20_0[32];
|
||||
unsigned int z2_50_0[32];
|
||||
unsigned int z2_100_0[32];
|
||||
unsigned int t0[32];
|
||||
unsigned int t1[32];
|
||||
int i;
|
||||
|
||||
/* 2 */ square(z2,z);
|
||||
/* 4 */ square(t1,z2);
|
||||
/* 8 */ square(t0,t1);
|
||||
/* 9 */ mult(z9,t0,z);
|
||||
/* 11 */ mult(z11,z9,z2);
|
||||
/* 22 */ square(t0,z11);
|
||||
/* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9);
|
||||
|
||||
/* 2^6 - 2^1 */ square(t0,z2_5_0);
|
||||
/* 2^7 - 2^2 */ square(t1,t0);
|
||||
/* 2^8 - 2^3 */ square(t0,t1);
|
||||
/* 2^9 - 2^4 */ square(t1,t0);
|
||||
/* 2^10 - 2^5 */ square(t0,t1);
|
||||
/* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0);
|
||||
|
||||
/* 2^11 - 2^1 */ square(t0,z2_10_0);
|
||||
/* 2^12 - 2^2 */ square(t1,t0);
|
||||
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); }
|
||||
/* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0);
|
||||
|
||||
/* 2^21 - 2^1 */ square(t0,z2_20_0);
|
||||
/* 2^22 - 2^2 */ square(t1,t0);
|
||||
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); }
|
||||
/* 2^40 - 2^0 */ mult(t0,t1,z2_20_0);
|
||||
|
||||
/* 2^41 - 2^1 */ square(t1,t0);
|
||||
/* 2^42 - 2^2 */ square(t0,t1);
|
||||
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); }
|
||||
/* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0);
|
||||
|
||||
/* 2^51 - 2^1 */ square(t0,z2_50_0);
|
||||
/* 2^52 - 2^2 */ square(t1,t0);
|
||||
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
|
||||
/* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0);
|
||||
|
||||
/* 2^101 - 2^1 */ square(t1,z2_100_0);
|
||||
/* 2^102 - 2^2 */ square(t0,t1);
|
||||
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); }
|
||||
/* 2^200 - 2^0 */ mult(t1,t0,z2_100_0);
|
||||
|
||||
/* 2^201 - 2^1 */ square(t0,t1);
|
||||
/* 2^202 - 2^2 */ square(t1,t0);
|
||||
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
|
||||
/* 2^250 - 2^0 */ mult(t0,t1,z2_50_0);
|
||||
|
||||
/* 2^251 - 2^1 */ square(t1,t0);
|
||||
/* 2^252 - 2^2 */ square(t0,t1);
|
||||
/* 2^253 - 2^3 */ square(t1,t0);
|
||||
/* 2^254 - 2^4 */ square(t0,t1);
|
||||
/* 2^255 - 2^5 */ square(t1,t0);
|
||||
/* 2^255 - 21 */ mult(out,t1,z11);
|
||||
}
|
||||
|
||||
int crypto_scalarmult(unsigned char *q,
|
||||
const unsigned char *n,
|
||||
const unsigned char *p)
|
||||
{
|
||||
unsigned int work[96];
|
||||
unsigned char e[32];
|
||||
unsigned int i;
|
||||
for (i = 0;i < 32;++i) e[i] = n[i];
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
for (i = 0;i < 32;++i) work[i] = p[i];
|
||||
mainloop(work,e);
|
||||
recip(work + 32,work + 32);
|
||||
mult(work + 64,work,work + 32);
|
||||
freeze(work + 64);
|
||||
for (i = 0;i < 32;++i) q[i] = work[64 + i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
280
src/dh.c
280
src/dh.c
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2003-2013 by Aris Adamantiadis
|
||||
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012 by Dmitriy Kuznetsov <dk@yandex.ru>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
@@ -170,7 +170,7 @@ int ssh_crypto_init(void) {
|
||||
return -1;
|
||||
}
|
||||
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14);
|
||||
if (p_group1 == NULL) {
|
||||
if (p_group14 == NULL) {
|
||||
bignum_free(g);
|
||||
bignum_free(p_group1);
|
||||
g = NULL;
|
||||
@@ -239,63 +239,6 @@ void ssh_print_bignum(const char *which, bignum num) {
|
||||
SAFE_FREE(hex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a buffer into a colon separated hex string.
|
||||
* The caller has to free the memory.
|
||||
*
|
||||
* @param what What should be converted to a hex string.
|
||||
*
|
||||
* @param len Length of the buffer to convert.
|
||||
*
|
||||
* @return The hex string or NULL on error.
|
||||
*
|
||||
* @see ssh_string_free_char()
|
||||
*/
|
||||
char *ssh_get_hexa(const unsigned char *what, size_t len) {
|
||||
const char h[] = "0123456789abcdef";
|
||||
char *hexa;
|
||||
size_t i;
|
||||
size_t hlen = len * 3;
|
||||
|
||||
if (len > (UINT_MAX - 1) / 3) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hexa = malloc(hlen + 1);
|
||||
if (hexa == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
hexa[i * 3] = h[(what[i] >> 4) & 0xF];
|
||||
hexa[i * 3 + 1] = h[what[i] & 0xF];
|
||||
hexa[i * 3 + 2] = ':';
|
||||
}
|
||||
hexa[hlen - 1] = '\0';
|
||||
|
||||
return hexa;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print a buffer as colon separated hex string.
|
||||
*
|
||||
* @param descr Description printed in front of the hex string.
|
||||
*
|
||||
* @param what What should be converted to a hex string.
|
||||
*
|
||||
* @param len Length of the buffer to convert.
|
||||
*/
|
||||
void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
|
||||
char *hexa = ssh_get_hexa(what, len);
|
||||
|
||||
if (hexa == NULL) {
|
||||
return;
|
||||
}
|
||||
printf("%s: %s\n", descr, hexa);
|
||||
|
||||
free(hexa);
|
||||
}
|
||||
|
||||
int dh_generate_x(ssh_session session) {
|
||||
session->next_crypto->x = bignum_new();
|
||||
if (session->next_crypto->x == NULL) {
|
||||
@@ -464,6 +407,15 @@ bignum make_string_bn(ssh_string string){
|
||||
return bn;
|
||||
}
|
||||
|
||||
void make_string_bn_inplace(ssh_string string, bignum bnout) {
|
||||
unsigned int len = ssh_string_len(string);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#error "unsupported"
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_bin2bn(string->data, len, bnout);
|
||||
#endif
|
||||
}
|
||||
|
||||
ssh_string dh_get_e(ssh_session session) {
|
||||
return make_bignum_string(session->next_crypto->e);
|
||||
}
|
||||
@@ -770,6 +722,18 @@ int make_sessionid(ssh_session session) {
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
} else if(session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG){
|
||||
rc = buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
|
||||
rc += buffer_add_data(buf, session->next_crypto->curve25519_client_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
rc += buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
|
||||
rc += buffer_add_data(buf, session->next_crypto->curve25519_server_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
num = make_bignum_string(session->next_crypto->k);
|
||||
@@ -800,6 +764,7 @@ int make_sessionid(ssh_session session) {
|
||||
session->next_crypto->secret_hash);
|
||||
break;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
|
||||
session->next_crypto->mac_type = SSH_MAC_SHA256;
|
||||
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
|
||||
@@ -913,6 +878,7 @@ int generate_session_keys(ssh_session session) {
|
||||
ssh_string k_string = NULL;
|
||||
ssh_mac_ctx ctx = NULL;
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
unsigned char *tmp;
|
||||
int rc = -1;
|
||||
|
||||
k_string = make_bignum_string(crypto->k);
|
||||
@@ -968,9 +934,12 @@ int generate_session_keys(ssh_session session) {
|
||||
|
||||
/* some ciphers need more than DIGEST_LEN bytes of input key */
|
||||
if (crypto->out_cipher->keysize > crypto->digest_len * 8) {
|
||||
crypto->encryptkey = realloc(crypto->encryptkey, crypto->digest_len * 2);
|
||||
if(crypto->encryptkey == NULL)
|
||||
goto error;
|
||||
tmp = realloc(crypto->encryptkey, crypto->digest_len * 2);
|
||||
if (tmp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
crypto->encryptkey = tmp;
|
||||
|
||||
ctx = ssh_mac_ctx_init(crypto->mac_type);
|
||||
if (ctx == NULL) {
|
||||
goto error;
|
||||
@@ -983,7 +952,12 @@ int generate_session_keys(ssh_session session) {
|
||||
}
|
||||
|
||||
if (crypto->in_cipher->keysize > crypto->digest_len * 8) {
|
||||
crypto->decryptkey = realloc(crypto->decryptkey, crypto->digest_len *2);
|
||||
tmp = realloc(crypto->decryptkey, crypto->digest_len *2);
|
||||
if (tmp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
crypto->decryptkey = tmp;
|
||||
|
||||
if(crypto->decryptkey == NULL)
|
||||
goto error;
|
||||
ctx = ssh_mac_ctx_init(crypto->mac_type);
|
||||
@@ -1034,25 +1008,7 @@ error:
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Allocates a buffer with the MD5 hash of the server public key.
|
||||
*
|
||||
* This function allows you to get a MD5 hash of the public key. You can then
|
||||
* print this hash in a human-readable form to the user so that he is able to
|
||||
* verify it. Use ssh_get_hexa() or ssh_print_hexa() to display it.
|
||||
*
|
||||
* @param[in] session The SSH session to use.
|
||||
*
|
||||
* @param[in] hash The buffer to allocate.
|
||||
*
|
||||
* @return The bytes allocated or < 0 on error.
|
||||
*
|
||||
* @warning It is very important that you verify at some moment that the hash
|
||||
* matches a known server. If you don't do it, cryptography wont help
|
||||
* you at making things secure
|
||||
*
|
||||
* @see ssh_is_server_known()
|
||||
* @see ssh_get_hexa()
|
||||
* @see ssh_print_hexa()
|
||||
* @deprecated Use ssh_get_publickey_hash()
|
||||
*/
|
||||
int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
|
||||
ssh_string pubkey;
|
||||
@@ -1129,6 +1085,164 @@ int ssh_get_publickey(ssh_session session, ssh_key *key)
|
||||
key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocates a buffer with the hash of the public key.
|
||||
*
|
||||
* This function allows you to get a hash of the public key. You can then
|
||||
* print this hash in a human-readable form to the user so that he is able to
|
||||
* verify it. Use ssh_get_hexa() or ssh_print_hexa() to display it.
|
||||
*
|
||||
* @param[in] key The public key to create the hash for.
|
||||
*
|
||||
* @param[in] type The type of the hash you want.
|
||||
*
|
||||
* @param[in] hash A pointer to store the allocated buffer. It can be
|
||||
* freed using ssh_clean_pubkey_hash().
|
||||
*
|
||||
* @param[in] hlen The length of the hash.
|
||||
*
|
||||
* @return 0 on success, -1 if an error occured.
|
||||
*
|
||||
* @warning It is very important that you verify at some moment that the hash
|
||||
* matches a known server. If you don't do it, cryptography wont help
|
||||
* you at making things secure.
|
||||
* OpenSSH uses SHA1 to print public key digests.
|
||||
*
|
||||
* @see ssh_is_server_known()
|
||||
* @see ssh_get_hexa()
|
||||
* @see ssh_print_hexa()
|
||||
* @see ssh_clean_pubkey_hash()
|
||||
*/
|
||||
int ssh_get_publickey_hash(const ssh_key key,
|
||||
enum ssh_publickey_hash_type type,
|
||||
unsigned char **hash,
|
||||
size_t *hlen)
|
||||
{
|
||||
ssh_string blob;
|
||||
unsigned char *h;
|
||||
int rc;
|
||||
|
||||
rc = ssh_pki_export_pubkey_blob(key, &blob);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SSH_PUBLICKEY_HASH_SHA1:
|
||||
{
|
||||
SHACTX ctx;
|
||||
|
||||
h = malloc(SHA_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
sha1_final(h, ctx);
|
||||
|
||||
*hlen = SHA_DIGEST_LEN;
|
||||
}
|
||||
break;
|
||||
case SSH_PUBLICKEY_HASH_MD5:
|
||||
{
|
||||
MD5CTX ctx;
|
||||
|
||||
h = malloc(MD5_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx = md5_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
md5_final(h, ctx);
|
||||
|
||||
*hlen = MD5_DIGEST_LEN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*hash = h;
|
||||
rc = 0;
|
||||
out:
|
||||
ssh_string_free(blob);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a buffer into a colon separated hex string.
|
||||
* The caller has to free the memory.
|
||||
*
|
||||
* @param what What should be converted to a hex string.
|
||||
*
|
||||
* @param len Length of the buffer to convert.
|
||||
*
|
||||
* @return The hex string or NULL on error.
|
||||
*
|
||||
* @see ssh_string_free_char()
|
||||
*/
|
||||
char *ssh_get_hexa(const unsigned char *what, size_t len) {
|
||||
const char h[] = "0123456789abcdef";
|
||||
char *hexa;
|
||||
size_t i;
|
||||
size_t hlen = len * 3;
|
||||
|
||||
if (len > (UINT_MAX - 1) / 3) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hexa = malloc(hlen + 1);
|
||||
if (hexa == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
hexa[i * 3] = h[(what[i] >> 4) & 0xF];
|
||||
hexa[i * 3 + 1] = h[what[i] & 0xF];
|
||||
hexa[i * 3 + 2] = ':';
|
||||
}
|
||||
hexa[hlen - 1] = '\0';
|
||||
|
||||
return hexa;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print a buffer as colon separated hex string.
|
||||
*
|
||||
* @param descr Description printed in front of the hex string.
|
||||
*
|
||||
* @param what What should be converted to a hex string.
|
||||
*
|
||||
* @param len Length of the buffer to convert.
|
||||
*/
|
||||
void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
|
||||
char *hexa = ssh_get_hexa(what, len);
|
||||
|
||||
if (hexa == NULL) {
|
||||
return;
|
||||
}
|
||||
printf("%s: %s\n", descr, hexa);
|
||||
|
||||
free(hexa);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
23
src/ecdh.c
23
src/ecdh.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2011 by Aris Adamantiadis
|
||||
* 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
|
||||
@@ -100,6 +100,7 @@ static int ecdh_build_k(ssh_session session) {
|
||||
EC_POINT *pubkey;
|
||||
void *buffer;
|
||||
int len = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||
int rc;
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
@@ -124,9 +125,23 @@ static int ecdh_build_k(ssh_session session) {
|
||||
EC_POINT_oct2point(group,pubkey,ssh_string_data(session->next_crypto->ecdh_server_pubkey),
|
||||
ssh_string_len(session->next_crypto->ecdh_server_pubkey),ctx);
|
||||
buffer = malloc(len);
|
||||
ECDH_compute_key(buffer,len,pubkey,session->next_crypto->ecdh_privkey,NULL);
|
||||
EC_POINT_free(pubkey);
|
||||
BN_bin2bn(buffer,len,session->next_crypto->k);
|
||||
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;
|
||||
|
||||
@@ -104,7 +104,7 @@ void _ssh_set_error_invalid(void *error, const char *function)
|
||||
/**
|
||||
* @brief Retrieve the error text message from the last error.
|
||||
*
|
||||
* @param error The SSH session pointer.
|
||||
* @param error An ssh_session or ssh_bind.
|
||||
*
|
||||
* @return A static string describing the error.
|
||||
*/
|
||||
@@ -117,7 +117,7 @@ const char *ssh_get_error(void *error) {
|
||||
/**
|
||||
* @brief Retrieve the error code from the last error.
|
||||
*
|
||||
* @param error The SSH session pointer.
|
||||
* @param error An ssh_session or ssh_bind.
|
||||
*
|
||||
* \return SSH_NO_ERROR No error occurred\n
|
||||
* SSH_REQUEST_DENIED The last request was denied but situation is
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2011 by Andreas Schneider <mail@cryptomilk.org>
|
||||
* Copyright (c) 2011-2013 by Andreas Schneider <mail@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
|
||||
|
||||
273
src/gssapi.c
273
src/gssapi.c
@@ -49,7 +49,7 @@ struct ssh_gssapi_struct{
|
||||
enum ssh_gssapi_state_e state; /* current state */
|
||||
struct gss_OID_desc_struct mech; /* mechanism being elected for auth */
|
||||
gss_cred_id_t server_creds; /* credentials of server */
|
||||
gss_cred_id_t client_creds; /* creds of the client */
|
||||
gss_cred_id_t client_creds; /* creds delegated by the client */
|
||||
gss_ctx_id_t ctx; /* the authentication context */
|
||||
gss_name_t client_name; /* Identity of the client */
|
||||
char *user; /* username of client */
|
||||
@@ -57,7 +57,9 @@ struct ssh_gssapi_struct{
|
||||
char *service; /* name of the service */
|
||||
struct {
|
||||
gss_name_t server_name; /* identity of server */
|
||||
OM_uint32 flags; /* flags used for init context */
|
||||
gss_OID oid; /* mech being used for authentication */
|
||||
gss_cred_id_t creds; /* creds used to initialize context */
|
||||
gss_cred_id_t client_deleg_creds; /* delegated creds (const, not freeable) */
|
||||
} client;
|
||||
};
|
||||
@@ -89,12 +91,13 @@ static void ssh_gssapi_free(ssh_session session){
|
||||
OM_uint32 min;
|
||||
if (session->gssapi == NULL)
|
||||
return;
|
||||
if (session->gssapi->mech.elements)
|
||||
SAFE_FREE(session->gssapi->mech.elements);
|
||||
if (session->gssapi->user)
|
||||
SAFE_FREE(session->gssapi->user);
|
||||
if (session->gssapi->server_creds)
|
||||
gss_release_cred(&min,&session->gssapi->server_creds);
|
||||
SAFE_FREE(session->gssapi->user);
|
||||
SAFE_FREE(session->gssapi->mech.elements);
|
||||
gss_release_cred(&min,&session->gssapi->server_creds);
|
||||
if (session->gssapi->client.creds !=
|
||||
session->gssapi->client.client_deleg_creds) {
|
||||
gss_release_cred(&min, &session->gssapi->client.creds);
|
||||
}
|
||||
SAFE_FREE(session->gssapi);
|
||||
}
|
||||
|
||||
@@ -208,8 +211,8 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
|
||||
maj_stat = gss_import_name(&min_stat, &name_buf,
|
||||
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(0, "importing name", maj_stat);
|
||||
SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "importing name", maj_stat);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -220,13 +223,13 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
|
||||
gss_release_oid_set(&min_stat, &both_supported);
|
||||
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(0, "error acquiring credentials %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(0, "acquiring creds", maj_stat);
|
||||
SSH_LOG(SSH_LOG_WARNING, "error acquiring credentials %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "acquiring creds", maj_stat);
|
||||
ssh_auth_reply_default(session,0);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(0, "acquiring credentials %d, %d", maj_stat, min_stat);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "acquiring credentials %d, %d", maj_stat, min_stat);
|
||||
|
||||
/* finding which OID from client we selected */
|
||||
for (i=0 ; i< n_oid ; ++i){
|
||||
@@ -263,7 +266,7 @@ static char *ssh_gssapi_name_to_char(gss_name_t name){
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
char *ptr;
|
||||
maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
|
||||
ssh_gssapi_log_error(0, "converting name", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "converting name", maj_stat);
|
||||
ptr=malloc(buffer.length + 1);
|
||||
memcpy(ptr, buffer.value, buffer.length);
|
||||
ptr[buffer.length] = '\0';
|
||||
@@ -335,14 +338,14 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
||||
maj_stat = gss_accept_sec_context(&min_stat, &session->gssapi->ctx, session->gssapi->server_creds,
|
||||
&input_token, input_bindings, &client_name, NULL /*mech_oid*/, &output_token, &ret_flags,
|
||||
NULL /*time*/, &session->gssapi->client_creds);
|
||||
ssh_gssapi_log_error(0, "accepting token", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "accepting token", maj_stat);
|
||||
ssh_string_free(token);
|
||||
if (client_name != GSS_C_NO_NAME){
|
||||
session->gssapi->client_name = client_name;
|
||||
session->gssapi->canonic_user = ssh_gssapi_name_to_char(client_name);
|
||||
}
|
||||
if (GSS_ERROR(maj_stat)){
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "Gssapi error", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "Gssapi error", maj_stat);
|
||||
ssh_auth_reply_default(session,0);
|
||||
ssh_gssapi_free(session);
|
||||
session->gssapi=NULL;
|
||||
@@ -484,8 +487,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic)
|
||||
mic_token_buf.value = ssh_string_data(mic_token);
|
||||
|
||||
maj_stat = gss_verify_mic(&min_stat, session->gssapi->ctx, &mic_buf, &mic_token_buf, NULL);
|
||||
ssh_gssapi_log_error(0, "verifying MIC", maj_stat);
|
||||
ssh_gssapi_log_error(0, "verifying MIC (min stat)", min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "verifying MIC", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "verifying MIC (min stat)", min_stat);
|
||||
if (maj_stat == GSS_S_DEFECTIVE_TOKEN || GSS_ERROR(maj_stat)) {
|
||||
goto error;
|
||||
}
|
||||
@@ -536,8 +539,12 @@ ssh_gssapi_creds ssh_gssapi_get_creds(ssh_session session){
|
||||
return (ssh_gssapi_creds)session->gssapi->client_creds;
|
||||
}
|
||||
|
||||
#endif /* SERVER */
|
||||
|
||||
/**
|
||||
* @brief Set the forwadable ticket to be given to the server for authentication.
|
||||
* Unlike ssh_gssapi_get_creds() this is called on the client side of an ssh
|
||||
* connection.
|
||||
*
|
||||
* @param[in] creds gssapi credentials handle.
|
||||
*/
|
||||
@@ -556,8 +563,6 @@ void ssh_gssapi_set_creds(ssh_session session, const ssh_gssapi_creds creds)
|
||||
session->gssapi->client.client_deleg_creds = (gss_cred_id_t)creds;
|
||||
}
|
||||
|
||||
#endif /* SERVER */
|
||||
|
||||
static int ssh_gssapi_send_auth_mic(ssh_session session, ssh_string *oid_set, int n_oid){
|
||||
ssh_string str;
|
||||
int rc;
|
||||
@@ -616,88 +621,75 @@ fail:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/** @brief returns the OIDs of the mechs that work with both
|
||||
* hostname and username
|
||||
/** @brief returns the OIDs of the mechs that have usable credentials
|
||||
*/
|
||||
static int ssh_gssapi_match(ssh_session session, char *hostname, char *username, gss_OID_set *valid_oids, int deleg){
|
||||
gss_buffer_desc host_namebuf, user_namebuf;
|
||||
gss_name_t host_name, user_name;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
gss_OID_set supported;
|
||||
static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids)
|
||||
{
|
||||
OM_uint32 maj_stat, min_stat, lifetime;
|
||||
gss_OID_set actual_mechs;
|
||||
gss_buffer_desc namebuf;
|
||||
gss_name_t client_id = GSS_C_NO_NAME;
|
||||
gss_OID oid;
|
||||
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
|
||||
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL;
|
||||
unsigned int i;
|
||||
char *ptr;
|
||||
char hostname_buf[256];
|
||||
int ret;
|
||||
|
||||
if (session->gssapi->client.client_deleg_creds == NULL) {
|
||||
if (session->opts.gss_client_identity != NULL) {
|
||||
namebuf.value = (void *)session->opts.gss_client_identity;
|
||||
namebuf.length = strlen(session->opts.gss_client_identity);
|
||||
|
||||
gss_create_empty_oid_set(&min_stat, valid_oids);
|
||||
maj_stat = gss_indicate_mechs(&min_stat, &supported);
|
||||
for (i=0; i < supported->count; ++i){
|
||||
ptr=ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "GSSAPI oid supported %d : %s\n",i, ptr);
|
||||
SAFE_FREE(ptr);
|
||||
}
|
||||
|
||||
user_namebuf.value = username;
|
||||
user_namebuf.length = strlen(username) + 1;
|
||||
maj_stat = gss_import_name(&min_stat, &user_namebuf,
|
||||
(gss_OID) GSS_C_NT_USER_NAME, &user_name);
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_DEBUG, "importing name", maj_stat);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(hostname_buf, sizeof(hostname_buf),"host@%s", hostname);
|
||||
host_namebuf.value = hostname_buf;
|
||||
host_namebuf.length = strlen(hostname_buf) + 1;
|
||||
maj_stat = gss_import_name(&min_stat, &host_namebuf,
|
||||
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &host_name);
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(0, "importing name", maj_stat);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssh_gssapi_init(session);
|
||||
session->gssapi->client_name = user_name;
|
||||
session->gssapi->client.server_name = host_name;
|
||||
session->gssapi->user = strdup(username);
|
||||
for (i=0; i<supported->count; ++i){
|
||||
oid = &supported->elements[i];
|
||||
maj_stat = gss_init_sec_context(&min_stat,
|
||||
session->gssapi->client.client_deleg_creds, &ctx, host_name, oid,
|
||||
GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0),
|
||||
0, NULL, &input_token, NULL, &output_token, NULL, NULL);
|
||||
if (!GSS_ERROR(maj_stat)){
|
||||
gss_OID_set tmp;
|
||||
if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL){
|
||||
/* we know the oid is ok since init_sec_context worked */
|
||||
gss_add_oid_set_member(&min_stat, oid, valid_oids);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server (with forwarding)", i);
|
||||
} else {
|
||||
gss_create_empty_oid_set(&min_stat, &tmp);
|
||||
gss_add_oid_set_member(&min_stat, oid, &tmp);
|
||||
maj_stat = gss_acquire_cred(&min_stat, user_name, 0,
|
||||
tmp, GSS_C_INITIATE,
|
||||
&client_creds, NULL, NULL);
|
||||
gss_release_oid_set(&min_stat, &tmp);
|
||||
if (!GSS_ERROR(maj_stat)){
|
||||
gss_release_cred(&min_stat, &client_creds);
|
||||
gss_add_oid_set_member(&min_stat,oid,valid_oids);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server", i);
|
||||
}
|
||||
maj_stat = gss_import_name(&min_stat, &namebuf,
|
||||
GSS_C_NT_USER_NAME, &client_id);
|
||||
if (GSS_ERROR(maj_stat)) {
|
||||
ret = SSH_ERROR;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
gss_delete_sec_context(&min_stat,&ctx, &output_token);
|
||||
ctx = GSS_C_NO_CONTEXT;
|
||||
|
||||
maj_stat = gss_acquire_cred(&min_stat, client_id, GSS_C_INDEFINITE,
|
||||
GSS_C_NO_OID_SET, GSS_C_INITIATE,
|
||||
&session->gssapi->client.creds,
|
||||
&actual_mechs, NULL);
|
||||
if (GSS_ERROR(maj_stat)) {
|
||||
ret = SSH_ERROR;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
session->gssapi->client.creds =
|
||||
session->gssapi->client.client_deleg_creds;
|
||||
|
||||
maj_stat = gss_inquire_cred(&min_stat, session->gssapi->client.creds,
|
||||
&client_id, NULL, NULL, &actual_mechs);
|
||||
if (GSS_ERROR(maj_stat)) {
|
||||
ret = SSH_ERROR;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
gss_create_empty_oid_set(&min_stat, valid_oids);
|
||||
|
||||
/* double check each single cred */
|
||||
for (i = 0; i < actual_mechs->count; i++) {
|
||||
/* check lifetime is not 0 or skip */
|
||||
lifetime = 0;
|
||||
oid = &actual_mechs->elements[i];
|
||||
maj_stat = gss_inquire_cred_by_mech(&min_stat,
|
||||
session->gssapi->client.creds,
|
||||
oid, NULL, &lifetime, NULL, NULL);
|
||||
if (maj_stat == GSS_S_COMPLETE && lifetime > 0) {
|
||||
gss_add_oid_set_member(&min_stat, oid, valid_oids);
|
||||
ptr = ssh_get_hexa(oid->elements, oid->length);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "GSSAPI valid oid %d : %s\n", i, ptr);
|
||||
SAFE_FREE(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
ret = SSH_OK;
|
||||
|
||||
end:
|
||||
gss_release_name(&min_stat, &client_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -713,21 +705,55 @@ int ssh_gssapi_auth_mic(ssh_session session){
|
||||
ssh_string *oids;
|
||||
int rc;
|
||||
int n_oids = 0;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
char name_buf[256];
|
||||
gss_buffer_desc hostname;
|
||||
const char *gss_host = session->opts.host;
|
||||
|
||||
if (ssh_gssapi_init(session) == SSH_ERROR)
|
||||
rc = ssh_gssapi_init(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
if (session->opts.gss_server_identity != NULL) {
|
||||
gss_host = session->opts.gss_server_identity;
|
||||
}
|
||||
/* import target host name */
|
||||
snprintf(name_buf, sizeof(name_buf), "host@%s", gss_host);
|
||||
|
||||
hostname.value = name_buf;
|
||||
hostname.length = strlen(name_buf) + 1;
|
||||
maj_stat = gss_import_name(&min_stat, &hostname,
|
||||
(gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
|
||||
&session->gssapi->client.server_name);
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "importing name", maj_stat);
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
/* copy username */
|
||||
session->gssapi->user = strdup(session->opts.username);
|
||||
if (session->gssapi->user == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi to host %s with user %s",
|
||||
session->opts.host, session->opts.username);
|
||||
rc = ssh_gssapi_match(session,session->opts.host, session->opts.username, &selected, 0);
|
||||
if (rc == SSH_ERROR)
|
||||
session->opts.host, session->gssapi->user);
|
||||
rc = ssh_gssapi_match(session, &selected);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
n_oids = selected->count;
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Sending %d oids", n_oids);
|
||||
|
||||
oids = calloc(n_oids, sizeof(ssh_string));
|
||||
if (oids == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
for (i=0; i<n_oids; ++i){
|
||||
oids[i] = ssh_string_new(selected->elements[i].length + 2);
|
||||
@@ -769,15 +795,11 @@ static gss_OID ssh_gssapi_oid_from_string(ssh_string oid_s){
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
|
||||
ssh_string oid_s;
|
||||
gss_OID oid;
|
||||
gss_uint32 maj_stat, min_stat;
|
||||
int deleg = 0;
|
||||
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_OID_set tmp;
|
||||
char *hexa;
|
||||
ssh_string token;
|
||||
gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
@@ -791,31 +813,27 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
|
||||
ssh_set_error(session, SSH_FATAL, "Missing OID");
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
oid = ssh_gssapi_oid_from_string(oid_s);
|
||||
session->gssapi->client.oid = ssh_gssapi_oid_from_string(oid_s);
|
||||
ssh_string_free(oid_s);
|
||||
if (!oid) {
|
||||
if (!session->gssapi->client.oid) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid OID");
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL)
|
||||
creds = session->gssapi->client.client_deleg_creds;
|
||||
if (creds == GSS_C_NO_CREDENTIAL){
|
||||
gss_create_empty_oid_set(&min_stat, &tmp);
|
||||
gss_add_oid_set_member(&min_stat, oid, &tmp);
|
||||
maj_stat = gss_acquire_cred(&min_stat, session->gssapi->client_name, 0,
|
||||
tmp, GSS_C_INITIATE,
|
||||
&session->gssapi->client_creds, NULL, NULL);
|
||||
gss_release_oid_set(&min_stat, &tmp);
|
||||
if (GSS_ERROR(maj_stat)){
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING,"Error acquiring credentials",maj_stat);
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
session->gssapi->client.flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
|
||||
if (session->opts.gss_delegate_creds) {
|
||||
session->gssapi->client.flags |= GSS_C_DELEG_FLAG;
|
||||
}
|
||||
|
||||
/* prepare the first TOKEN response */
|
||||
maj_stat = gss_init_sec_context(&min_stat,
|
||||
creds, &session->gssapi->ctx, session->gssapi->client.server_name, oid,
|
||||
GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0),
|
||||
0, NULL, &input_token, NULL, &output_token, NULL, NULL);
|
||||
session->gssapi->client.creds,
|
||||
&session->gssapi->ctx,
|
||||
session->gssapi->client.server_name,
|
||||
session->gssapi->client.oid,
|
||||
session->gssapi->client.flags,
|
||||
0, NULL, &input_token, NULL,
|
||||
&output_token, NULL, NULL);
|
||||
if(GSS_ERROR(maj_stat)){
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING, "Initializing gssapi context", maj_stat);
|
||||
return SSH_PACKET_USED;
|
||||
@@ -832,7 +850,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
|
||||
ssh_string_free(token);
|
||||
session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN;
|
||||
}
|
||||
session->gssapi->client.oid = oid;
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
@@ -856,7 +873,7 @@ static int ssh_gssapi_send_mic(ssh_session session){
|
||||
maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT, &mic_buf, &mic_token_buf);
|
||||
if (GSS_ERROR(maj_stat)){
|
||||
ssh_buffer_free(mic_buffer);
|
||||
ssh_gssapi_log_error(0, "generating MIC", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "generating MIC", maj_stat);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -889,8 +906,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
|
||||
char *hexa;
|
||||
OM_uint32 maj_stat, min_stat;
|
||||
gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
|
||||
int deleg = 0;
|
||||
(void)user;
|
||||
(void)type;
|
||||
|
||||
@@ -910,16 +925,16 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
|
||||
SAFE_FREE(hexa);
|
||||
input_token.length = ssh_string_len(token);
|
||||
input_token.value = ssh_string_data(token);
|
||||
if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL)
|
||||
creds = session->gssapi->client.client_deleg_creds;
|
||||
else
|
||||
creds = session->gssapi->client_creds;
|
||||
maj_stat = gss_init_sec_context(&min_stat,
|
||||
creds, &session->gssapi->ctx, session->gssapi->client.server_name, session->gssapi->client.oid,
|
||||
GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0),
|
||||
0, NULL, &input_token, NULL, &output_token, NULL, NULL);
|
||||
session->gssapi->client.creds,
|
||||
&session->gssapi->ctx,
|
||||
session->gssapi->client.server_name,
|
||||
session->gssapi->client.oid,
|
||||
session->gssapi->client.flags,
|
||||
0, NULL, &input_token, NULL,
|
||||
&output_token, NULL, NULL);
|
||||
|
||||
ssh_gssapi_log_error(0, "accepting token", maj_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "accepting token", maj_stat);
|
||||
ssh_string_free(token);
|
||||
if (GSS_ERROR(maj_stat)){
|
||||
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "Gssapi error", maj_stat);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* 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
|
||||
|
||||
82
src/kex.c
82
src/kex.c
@@ -34,6 +34,8 @@
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/string.h"
|
||||
#include "libssh/curve25519.h"
|
||||
#include "libssh/knownhosts.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
# define BLOWFISH "blowfish-cbc,"
|
||||
@@ -63,14 +65,21 @@
|
||||
#define ZLIB "none"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
#define KEY_EXCHANGE "ecdh-sha2-nistp256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
|
||||
#define HOSTKEYS "ecdsa-sha2-nistp256,ssh-rsa,ssh-dss"
|
||||
#ifdef HAVE_CURVE25519
|
||||
#define CURVE25519 "curve25519-sha256@libssh.org,"
|
||||
#else
|
||||
#define KEY_EXCHANGE "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
|
||||
#define HOSTKEYS "ssh-rsa,ssh-dss"
|
||||
#define CURVE25519 ""
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
#define ECDH "ecdh-sha2-nistp256,"
|
||||
#define HOSTKEYS "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss"
|
||||
#else
|
||||
#define HOSTKEYS "ssh-rsa,ssh-dss"
|
||||
#define ECDH ""
|
||||
#endif
|
||||
|
||||
#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
|
||||
#define KEX_METHODS_SIZE 10
|
||||
|
||||
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
|
||||
@@ -306,7 +315,7 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
|
||||
for (i = 0; i < KEX_METHODS_SIZE; i++) {
|
||||
str = buffer_get_ssh_string(packet);
|
||||
if (str == NULL) {
|
||||
break;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffer_add_ssh_string(session->in_hashbuf, str) < 0) {
|
||||
@@ -341,6 +350,11 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
|
||||
error:
|
||||
ssh_string_free(str);
|
||||
for (i = 0; i < SSH_KEX_METHODS; i++) {
|
||||
if (server_kex) {
|
||||
session->next_crypto->client_kex.methods[i] = NULL;
|
||||
} else { /* client */
|
||||
session->next_crypto->server_kex.methods[i] = NULL;
|
||||
}
|
||||
SAFE_FREE(strings[i]);
|
||||
}
|
||||
|
||||
@@ -365,6 +379,53 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief selects the hostkey mechanisms to be chosen for the key exchange,
|
||||
* as some hostkey mechanisms may be present in known_hosts file and preferred
|
||||
* @returns a cstring containing a comma-separated list of hostkey methods.
|
||||
* NULL if no method matches
|
||||
*/
|
||||
static char *ssh_client_select_hostkeys(ssh_session session){
|
||||
char methods_buffer[128]={0};
|
||||
static const char *preferred_hostkeys[]={"ecdsa-sha2-nistp521","ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp256", "ssh-rsa", "ssh-dss", "ssh-rsa1", NULL};
|
||||
char **methods;
|
||||
int i,j;
|
||||
int needcoma=0;
|
||||
|
||||
methods = ssh_knownhosts_algorithms(session);
|
||||
if (methods == NULL || methods[0] == NULL){
|
||||
SAFE_FREE(methods);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0;preferred_hostkeys[i] != NULL; ++i){
|
||||
for (j=0; methods[j] != NULL; ++j){
|
||||
if(strcmp(preferred_hostkeys[i], methods[j]) == 0){
|
||||
if (verify_existing_algo(SSH_HOSTKEYS, methods[j])){
|
||||
if(needcoma)
|
||||
strncat(methods_buffer,",",sizeof(methods_buffer)-strlen(methods_buffer)-1);
|
||||
strncat(methods_buffer, methods[j], sizeof(methods_buffer)-strlen(methods_buffer)-1);
|
||||
needcoma = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i=0;methods[i]!= NULL; ++i){
|
||||
SAFE_FREE(methods[i]);
|
||||
}
|
||||
SAFE_FREE(methods);
|
||||
|
||||
if(strlen(methods_buffer) > 0){
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Changing host key method to \"%s\"", methods_buffer);
|
||||
return strdup(methods_buffer);
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "No supported kex method for existing key in known_hosts file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief sets the key exchange parameters to be sent to the server,
|
||||
* in function of the options and available methods.
|
||||
@@ -377,6 +438,13 @@ int set_client_kex(ssh_session session){
|
||||
ssh_get_random(client->cookie, 16, 0);
|
||||
|
||||
memset(client->methods, 0, KEX_METHODS_SIZE * sizeof(char **));
|
||||
/* first check if we have specific host key methods */
|
||||
if(session->opts.wanted_methods[SSH_HOSTKEYS] == NULL){
|
||||
/* Only if no override */
|
||||
session->opts.wanted_methods[SSH_HOSTKEYS] =
|
||||
ssh_client_select_hostkeys(session);
|
||||
}
|
||||
|
||||
for (i = 0; i < KEX_METHODS_SIZE; i++) {
|
||||
wanted = session->opts.wanted_methods[i];
|
||||
if (wanted == NULL)
|
||||
@@ -412,6 +480,8 @@ int ssh_kex_select_methods (ssh_session session){
|
||||
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
|
||||
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
|
||||
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
|
||||
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
|
||||
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* 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
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/options.h"
|
||||
|
||||
#include "libssh/knownhosts.h"
|
||||
/*todo: remove this include */
|
||||
#include "libssh/string.h"
|
||||
|
||||
@@ -647,6 +647,102 @@ int ssh_write_knownhost(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KNOWNHOSTS_MAXTYPES 10
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Check which kind of host keys should be preferred for connection
|
||||
* by reading the known_hosts file.
|
||||
*
|
||||
* @param[in] session The SSH session to use.
|
||||
*
|
||||
* @returns array of supported key types
|
||||
* NULL on error
|
||||
*/
|
||||
char **ssh_knownhosts_algorithms(ssh_session session) {
|
||||
FILE *file = NULL;
|
||||
char **tokens;
|
||||
char *host;
|
||||
char *hostport;
|
||||
const char *type;
|
||||
int match;
|
||||
char **array;
|
||||
int i=0, j;
|
||||
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Can't find a known_hosts file");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.host == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
host = ssh_lowercase(session->opts.host);
|
||||
hostport = ssh_hostport(host, session->opts.port);
|
||||
array = malloc(sizeof(char *) * KNOWNHOSTS_MAXTYPES);
|
||||
|
||||
if (host == NULL || hostport == NULL || array == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
SAFE_FREE(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
tokens = ssh_get_knownhost_line(&file,
|
||||
session->opts.knownhosts, &type);
|
||||
|
||||
/* End of file, return the current state */
|
||||
if (tokens == NULL) {
|
||||
break;
|
||||
}
|
||||
match = match_hashed_host(host, tokens[0]);
|
||||
if (match == 0){
|
||||
match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hostname(host, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hashed_host(hostport, tokens[0]);
|
||||
}
|
||||
if (match) {
|
||||
/* We got a match. Now check the key type */
|
||||
SSH_LOG(SSH_LOG_DEBUG, "server %s:%d has %s in known_hosts",
|
||||
host, session->opts.port, type);
|
||||
/* don't copy more than once */
|
||||
for(j=0;j<i && match;++j){
|
||||
if(strcmp(array[j], type)==0)
|
||||
match=0;
|
||||
}
|
||||
if (match){
|
||||
array[i] = strdup(type);
|
||||
i++;
|
||||
if(i>= KNOWNHOSTS_MAXTYPES-1){
|
||||
tokens_free(tokens);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens_free(tokens);
|
||||
} while (1);
|
||||
|
||||
array[i]=NULL;
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
if (file != NULL) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* Return the current state at end of file */
|
||||
return array;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
@@ -19,10 +19,14 @@
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
@@ -38,6 +42,8 @@
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#ifdef HAVE_OPENSSL_AES_H
|
||||
#define HAS_AES
|
||||
#include <openssl/aes.h>
|
||||
@@ -74,6 +80,14 @@ static int alloc_key(struct ssh_cipher_struct *cipher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssh_reseed(void){
|
||||
#ifndef _WIN32
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
RAND_add(&tv, sizeof(tv), 0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
SHACTX sha1_init(void) {
|
||||
SHACTX c = malloc(sizeof(*c));
|
||||
if (c == NULL) {
|
||||
@@ -123,6 +137,30 @@ void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned
|
||||
EVP_DigestUpdate(&md, digest, len);
|
||||
EVP_DigestFinal(&md, hash, hlen);
|
||||
}
|
||||
|
||||
EVPCTX evp_init(int nid)
|
||||
{
|
||||
const EVP_MD *evp_md = nid_to_evpmd(nid);
|
||||
|
||||
EVPCTX ctx = malloc(sizeof(EVP_MD_CTX));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_DigestInit(ctx, evp_md);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void evp_update(EVPCTX ctx, const void *data, unsigned long len)
|
||||
{
|
||||
EVP_DigestUpdate(ctx, data, len);
|
||||
}
|
||||
|
||||
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
|
||||
{
|
||||
EVP_DigestFinal(ctx, md, mdlen);
|
||||
}
|
||||
#endif
|
||||
|
||||
SHA256CTX sha256_init(void){
|
||||
@@ -169,7 +207,11 @@ void md5_final(unsigned char *md, MD5CTX c) {
|
||||
}
|
||||
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||
ssh_mac_ctx ctx=malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->mac_type=type;
|
||||
switch(type){
|
||||
case SSH_MAC_SHA1:
|
||||
|
||||
@@ -45,6 +45,9 @@ static int alloc_key(struct ssh_cipher_struct *cipher) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ssh_reseed(void){
|
||||
}
|
||||
|
||||
SHACTX sha1_init(void) {
|
||||
SHACTX ctx = NULL;
|
||||
gcry_md_open(&ctx, GCRY_MD_SHA1, 0);
|
||||
@@ -88,7 +91,11 @@ void md5_final(unsigned char *md, MD5CTX c) {
|
||||
}
|
||||
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||
ssh_mac_ctx ctx=malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->mac_type=type;
|
||||
switch(type){
|
||||
case SSH_MAC_SHA1:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2008-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
|
||||
@@ -65,7 +65,7 @@ static int current_timestring(int hires, char *buf, size_t len)
|
||||
|
||||
if (hires) {
|
||||
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
|
||||
snprintf(buf, len, "%s.%06ld", tbuf, tv.tv_usec);
|
||||
snprintf(buf, len, "%s.%06ld", tbuf, (long)tv.tv_usec);
|
||||
} else {
|
||||
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
|
||||
snprintf(buf, len, "%s", tbuf);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-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
|
||||
@@ -120,13 +120,32 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
|
||||
msg->auth_request.username, msg->auth_request.pubkey,
|
||||
msg->auth_request.signature_state,
|
||||
session->server_callbacks->userdata);
|
||||
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){
|
||||
if (msg->auth_request.signature_state != SSH_PUBLICKEY_STATE_NONE) {
|
||||
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) {
|
||||
ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
|
||||
} else {
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
}
|
||||
} else {
|
||||
if (rc == SSH_AUTH_SUCCESS) {
|
||||
ssh_message_auth_reply_pk_ok_simple(msg);
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
} else if (msg->auth_request.method == SSH_AUTH_METHOD_NONE &&
|
||||
ssh_callbacks_exists(session->server_callbacks, auth_none_function)) {
|
||||
rc = session->server_callbacks->auth_none_function(session,
|
||||
msg->auth_request.username, session->server_callbacks->userdata);
|
||||
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){
|
||||
ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
break;
|
||||
case SSH_REQUEST_CHANNEL_OPEN:
|
||||
@@ -189,8 +208,8 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
|
||||
ssh_callbacks_exists(channel->callbacks, channel_pty_window_change_function)) {
|
||||
rc = channel->callbacks->channel_pty_window_change_function(session,
|
||||
channel,
|
||||
msg->channel_request.height, msg->channel_request.width,
|
||||
msg->channel_request.pxheight, msg->channel_request.pxwidth,
|
||||
msg->channel_request.width, msg->channel_request.height,
|
||||
msg->channel_request.pxwidth, msg->channel_request.pxheight,
|
||||
channel->callbacks->userdata);
|
||||
} else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_EXEC &&
|
||||
ssh_callbacks_exists(channel->callbacks, channel_exec_request_function)) {
|
||||
@@ -290,10 +309,8 @@ static int ssh_execute_server_callbacks(ssh_session session, ssh_message msg){
|
||||
|
||||
if (session->server_callbacks != NULL){
|
||||
rc = ssh_execute_server_request(session, msg);
|
||||
}
|
||||
|
||||
/* This one is in fact a client callback... */
|
||||
if (session->common.callbacks != NULL) {
|
||||
} else if (session->common.callbacks != NULL) {
|
||||
/* This one is in fact a client callback... */
|
||||
rc = ssh_execute_client_request(session, msg);
|
||||
}
|
||||
|
||||
@@ -491,8 +508,7 @@ void ssh_message_free(ssh_message msg){
|
||||
case SSH_REQUEST_AUTH:
|
||||
SAFE_FREE(msg->auth_request.username);
|
||||
if (msg->auth_request.password) {
|
||||
memset(msg->auth_request.password, 0,
|
||||
strlen(msg->auth_request.password));
|
||||
BURN_STRING(msg->auth_request.password);
|
||||
SAFE_FREE(msg->auth_request.password);
|
||||
}
|
||||
ssh_key_free(msg->auth_request.pubkey);
|
||||
@@ -1355,6 +1371,7 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel,
|
||||
msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight);
|
||||
msg->channel_request.modes = buffer_get_ssh_string(packet);
|
||||
if (msg->channel_request.modes == NULL) {
|
||||
msg->channel_request.TERM = NULL;
|
||||
SAFE_FREE(term_c);
|
||||
goto error;
|
||||
}
|
||||
@@ -1453,6 +1470,7 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel,
|
||||
if (strcmp(request, "x11-req") == 0) {
|
||||
ssh_string auth_protocol = NULL;
|
||||
ssh_string auth_cookie = NULL;
|
||||
uint32_t screen_number;
|
||||
|
||||
buffer_get_u8(packet, &msg->channel_request.x11_single_connection);
|
||||
|
||||
@@ -1480,7 +1498,8 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel,
|
||||
ssh_string_free(auth_protocol);
|
||||
ssh_string_free(auth_cookie);
|
||||
|
||||
buffer_get_u32(packet, &msg->channel_request.x11_screen_number);
|
||||
buffer_get_u32(packet, &screen_number);
|
||||
msg->channel_request.x11_screen_number = ntohl(screen_number);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2008-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
|
||||
@@ -697,7 +697,6 @@ char *ssh_path_expand_tilde(const char *d) {
|
||||
}
|
||||
|
||||
char *ssh_path_expand_escape(ssh_session session, const char *s) {
|
||||
#define MAX_BUF_SIZE 4096
|
||||
char host[NI_MAXHOST];
|
||||
char buf[MAX_BUF_SIZE];
|
||||
char *r, *x = NULL;
|
||||
|
||||
217
src/options.c
217
src/options.c
@@ -4,7 +4,7 @@
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2009-2013 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
|
||||
@@ -367,6 +367,18 @@ int ssh_options_set_algo(ssh_session session, int algo,
|
||||
* Set the command to be executed in order to connect to
|
||||
* server (const char *).
|
||||
*
|
||||
* - SSH_OPTIONS_GSSAPI_SERVER_IDENTITY
|
||||
* Set it to specify the GSSAPI server identity that libssh
|
||||
* should expect when connecting to the server (const char *).
|
||||
*
|
||||
* - SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY
|
||||
* Set it to specify the GSSAPI client identity that libssh
|
||||
* should expect when connecting to the server (const char *).
|
||||
*
|
||||
* - SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS
|
||||
* Set it to specify that GSSAPI should delegate credentials
|
||||
* to the server (int, 0 = false).
|
||||
*
|
||||
* @param value The value to set. This is a generic pointer and the
|
||||
* datatype which is used should be set according to the
|
||||
* type set.
|
||||
@@ -500,7 +512,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
}
|
||||
session->opts.username = q;
|
||||
} else if (v[0] == '\0') {
|
||||
ssh_set_error_oom(session);
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
} else { /* username provided */
|
||||
session->opts.username = strdup(value);
|
||||
@@ -519,7 +531,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
return -1;
|
||||
}
|
||||
} else if (v[0] == '\0') {
|
||||
ssh_set_error_oom(session);
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
} else {
|
||||
session->opts.sshdir = ssh_path_expand_tilde(v);
|
||||
@@ -661,6 +673,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
}
|
||||
|
||||
session->common.log_verbosity = i & 0xffff;
|
||||
ssh_set_log_level(i & 0xffff);
|
||||
}
|
||||
break;
|
||||
case SSH_OPTIONS_CIPHERS_C_S:
|
||||
@@ -792,6 +805,45 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_OPTIONS_GSSAPI_SERVER_IDENTITY:
|
||||
v = value;
|
||||
if (v == NULL || v[0] == '\0') {
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
} else {
|
||||
SAFE_FREE(session->opts.gss_server_identity);
|
||||
session->opts.gss_server_identity = strdup(v);
|
||||
if (session->opts.gss_server_identity == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY:
|
||||
v = value;
|
||||
if (v == NULL || v[0] == '\0') {
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
} else {
|
||||
SAFE_FREE(session->opts.gss_client_identity);
|
||||
session->opts.gss_client_identity = strdup(v);
|
||||
if (session->opts.gss_client_identity == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS:
|
||||
if (value == NULL) {
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
} else {
|
||||
int x = *(int *)value;
|
||||
|
||||
session->opts.gss_delegate_creds = (x & 0xff);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
|
||||
return -1;
|
||||
@@ -856,6 +908,11 @@ int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
|
||||
* It may include "%s" which will be replaced by the
|
||||
* user home directory.
|
||||
*
|
||||
* - SSH_OPTIONS_PROXYCOMMAND:
|
||||
* Get the proxycommand necessary to log into the
|
||||
* remote host. When not explicitly set, it will be read
|
||||
* from the ~/.ssh/config file.
|
||||
*
|
||||
* @param value The value to get into. As a char**, space will be
|
||||
* allocated by the function for the value, it is
|
||||
* your responsibility to free the memory using
|
||||
@@ -894,6 +951,10 @@ int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
|
||||
src = ssh_iterator_value(char *, it);
|
||||
break;
|
||||
}
|
||||
case SSH_OPTIONS_PROXYCOMMAND: {
|
||||
src = session->opts.ProxyCommand;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
|
||||
return SSH_ERROR;
|
||||
@@ -1242,65 +1303,89 @@ static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssh_bind_set_key(ssh_bind sshbind, char **key_loc,
|
||||
const void *value) {
|
||||
if (value == NULL) {
|
||||
ssh_set_error_invalid(sshbind);
|
||||
return -1;
|
||||
} else {
|
||||
SAFE_FREE(*key_loc);
|
||||
*key_loc = strdup(value);
|
||||
if (*key_loc == NULL) {
|
||||
ssh_set_error_oom(sshbind);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function can set all possible ssh bind options.
|
||||
* @brief Set options for an SSH server bind.
|
||||
*
|
||||
* @param session An allocated ssh option structure.
|
||||
* @param sshbind The ssh server bind to configure.
|
||||
*
|
||||
* @param type The option type to set. This could be one of the
|
||||
* @param type The option type to set. This should be one of the
|
||||
* following:
|
||||
*
|
||||
* SSH_BIND_OPTIONS_LOG_VERBOSITY:
|
||||
* Set the session logging verbosity (integer).
|
||||
*
|
||||
* The verbosity of the messages. Every log smaller or
|
||||
* equal to verbosity will be shown.
|
||||
* SSH_LOG_NOLOG: No logging
|
||||
* SSH_LOG_RARE: Rare conditions or warnings
|
||||
* SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* SSH_LOG_PACKET: Packet id and size
|
||||
* SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
*
|
||||
* SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
|
||||
* Set the session logging verbosity (integer).
|
||||
*
|
||||
* The verbosity of the messages. Every log smaller or
|
||||
* equal to verbosity will be shown.
|
||||
* SSH_LOG_NOLOG: No logging
|
||||
* SSH_LOG_RARE: Rare conditions or warnings
|
||||
* SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* SSH_LOG_PACKET: Packet id and size
|
||||
* SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
*
|
||||
* SSH_BIND_OPTIONS_BINDADDR:
|
||||
* Set the bind address.
|
||||
*
|
||||
* SSH_BIND_OPTIONS_BINDPORT:
|
||||
* Set the bind port, default is 22.
|
||||
*
|
||||
* SSH_BIND_OPTIONS_HOSTKEY:
|
||||
* - SSH_BIND_OPTIONS_HOSTKEY:
|
||||
* Set the server public key type: ssh-rsa or ssh-dss
|
||||
* (string).
|
||||
* (const char *).
|
||||
*
|
||||
* SSH_BIND_OPTIONS_DSAKEY:
|
||||
* Set the path to the dsa ssh host key (string).
|
||||
* - SSH_BIND_OPTIONS_BINDADDR:
|
||||
* Set the IP address to bind (const char *).
|
||||
*
|
||||
* SSH_BIND_OPTIONS_RSAKEY:
|
||||
* Set the path to the ssh host rsa key (string).
|
||||
* - SSH_BIND_OPTIONS_BINDPORT:
|
||||
* Set the port to bind (unsigned int *).
|
||||
*
|
||||
* SSH_BIND_OPTIONS_BANNER:
|
||||
* Set the server banner sent to clients (string).
|
||||
* - SSH_BIND_OPTIONS_BINDPORT_STR:
|
||||
* Set the port to bind (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_LOG_VERBOSITY:
|
||||
* Set the session logging verbosity (int *).
|
||||
* The logging verbosity should have one of the
|
||||
* following values, which are listed in order
|
||||
* of increasing verbosity. Every log message
|
||||
* with verbosity less than or equal to the
|
||||
* logging verbosity will be shown.
|
||||
* - SSH_LOG_NOLOG: No logging
|
||||
* - SSH_LOG_RARE: Rare conditions or warnings
|
||||
* - SSH_LOG_ENTRY: API-accessible entrypoints
|
||||
* - SSH_LOG_PACKET: Packet id and size
|
||||
* - SSH_LOG_FUNCTIONS: Function entering and leaving
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
|
||||
* Set the session logging verbosity via a
|
||||
* string that will be converted to a numerical
|
||||
* value (e.g. "3") and interpreted according
|
||||
* to the values of
|
||||
* SSH_BIND_OPTIONS_LOG_VERBOSITY above (const
|
||||
* char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_DSAKEY:
|
||||
* Set the path to the ssh host dsa key, SSHv2
|
||||
* only (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_RSAKEY:
|
||||
* Set the path to the ssh host rsa key, SSHv2
|
||||
* only (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_ECDSAKEY:
|
||||
* Set the path to the ssh host ecdsa key,
|
||||
* SSHv2 only (const char *).
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_BANNER:
|
||||
* Set the server banner sent to clients (const char *).
|
||||
*
|
||||
* @param value The value to set. This is a generic pointer and the
|
||||
* datatype which is used should be set according to the
|
||||
* type set.
|
||||
* datatype which should be used is described at the
|
||||
* corresponding value of type above.
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
* @return 0 on success, < 0 on error, invalid option, or parameter.
|
||||
*/
|
||||
int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
|
||||
const void *value) {
|
||||
char *p, *q;
|
||||
int i;
|
||||
int i, rc;
|
||||
|
||||
if (sshbind == NULL) {
|
||||
return -1;
|
||||
@@ -1367,7 +1452,7 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
|
||||
break;
|
||||
case SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
|
||||
if (value == NULL) {
|
||||
sshbind->common.log_verbosity = 0;
|
||||
ssh_set_log_level(0);
|
||||
} else {
|
||||
q = strdup(value);
|
||||
if (q == NULL) {
|
||||
@@ -1380,35 +1465,27 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
|
||||
}
|
||||
SAFE_FREE(q);
|
||||
|
||||
sshbind->common.log_verbosity = i & 0xffff;
|
||||
ssh_set_log_level(i & 0xffff);
|
||||
}
|
||||
break;
|
||||
case SSH_BIND_OPTIONS_DSAKEY:
|
||||
if (value == NULL) {
|
||||
ssh_set_error_invalid(sshbind);
|
||||
return -1;
|
||||
} else {
|
||||
SAFE_FREE(sshbind->dsakey);
|
||||
sshbind->dsakey = strdup(value);
|
||||
if (sshbind->dsakey == NULL) {
|
||||
ssh_set_error_oom(sshbind);
|
||||
return -1;
|
||||
rc = ssh_bind_set_key(sshbind, &sshbind->dsakey, value);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case SSH_BIND_OPTIONS_RSAKEY:
|
||||
if (value == NULL) {
|
||||
ssh_set_error_invalid(sshbind);
|
||||
return -1;
|
||||
} else {
|
||||
SAFE_FREE(sshbind->rsakey);
|
||||
sshbind->rsakey = strdup(value);
|
||||
if (sshbind->rsakey == NULL) {
|
||||
ssh_set_error_oom(sshbind);
|
||||
return -1;
|
||||
rc = ssh_bind_set_key(sshbind, &sshbind->rsakey, value);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case SSH_BIND_OPTIONS_ECDSAKEY:
|
||||
rc = ssh_bind_set_key(sshbind, &sshbind->ecdsakey, value);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SSH_BIND_OPTIONS_BANNER:
|
||||
if (value == NULL) {
|
||||
ssh_set_error_invalid(sshbind);
|
||||
|
||||
356
src/packet.c
356
src/packet.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-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
|
||||
@@ -141,174 +141,217 @@ static ssh_packet_callback default_packet_handlers[]= {
|
||||
* @len length of data received. It might not be enough for a complete packet
|
||||
* @returns number of bytes read and processed.
|
||||
*/
|
||||
int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user){
|
||||
ssh_session session=(ssh_session) user;
|
||||
unsigned int blocksize = (session->current_crypto ?
|
||||
session->current_crypto->in_cipher->blocksize : 8);
|
||||
int current_macsize = session->current_crypto ? MACSIZE : 0;
|
||||
unsigned char mac[30] = {0};
|
||||
char buffer[16] = {0};
|
||||
const void *packet = NULL;
|
||||
int to_be_read;
|
||||
int rc;
|
||||
uint32_t len, compsize, payloadsize;
|
||||
uint8_t padding;
|
||||
size_t processed=0; /* number of byte processed from the callback */
|
||||
int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
{
|
||||
ssh_session session= (ssh_session) user;
|
||||
unsigned int blocksize = (session->current_crypto ?
|
||||
session->current_crypto->in_cipher->blocksize : 8);
|
||||
int current_macsize = session->current_crypto ? MACSIZE : 0;
|
||||
unsigned char mac[30] = {0};
|
||||
char buffer[16] = {0};
|
||||
const uint8_t *packet;
|
||||
int to_be_read;
|
||||
int rc;
|
||||
uint32_t len, compsize, payloadsize;
|
||||
uint8_t padding;
|
||||
size_t processed = 0; /* number of byte processed from the callback */
|
||||
|
||||
if (data == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
goto error;
|
||||
switch(session->packet_state) {
|
||||
case PACKET_STATE_INIT:
|
||||
if(receivedlen < blocksize){
|
||||
/* We didn't receive enough data to read at least one block size, give up */
|
||||
return 0;
|
||||
}
|
||||
memset(&session->in_packet, 0, sizeof(PACKET));
|
||||
|
||||
if (session->in_buffer) {
|
||||
if (buffer_reinit(session->in_buffer) < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
session->in_buffer = ssh_buffer_new();
|
||||
if (session->in_buffer == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(buffer,data,blocksize);
|
||||
processed += blocksize;
|
||||
len = packet_decrypt_len(session, buffer);
|
||||
|
||||
if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) {
|
||||
if (data == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if(len > MAX_PACKET_LEN) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"read_packet(): Packet len too high(%u %.4x)", len, len);
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
to_be_read = len - blocksize + sizeof(uint32_t);
|
||||
if (to_be_read < 0) {
|
||||
/* remote sshd sends invalid sizes? */
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"given numbers of bytes left to be read < 0 (%d)!", to_be_read);
|
||||
goto error;
|
||||
}
|
||||
switch(session->packet_state) {
|
||||
case PACKET_STATE_INIT:
|
||||
if (receivedlen < blocksize) {
|
||||
/*
|
||||
* We didn't receive enough data to read at least one
|
||||
* block size, give up
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* saves the status of the current operations */
|
||||
session->in_packet.len = len;
|
||||
session->packet_state = PACKET_STATE_SIZEREAD;
|
||||
/* FALL TROUGH */
|
||||
case PACKET_STATE_SIZEREAD:
|
||||
len = session->in_packet.len;
|
||||
to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
|
||||
/* if to_be_read is zero, the whole packet was blocksize bytes. */
|
||||
if (to_be_read != 0) {
|
||||
if(receivedlen - processed < (unsigned int)to_be_read){
|
||||
/* give up, not enough data in buffer */
|
||||
SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len);
|
||||
return processed;
|
||||
}
|
||||
memset(&session->in_packet, 0, sizeof(PACKET));
|
||||
|
||||
packet = ((unsigned char *)data) + processed;
|
||||
// ssh_socket_read(session->socket,packet,to_be_read-current_macsize);
|
||||
if (session->in_buffer) {
|
||||
rc = buffer_reinit(session->in_buffer);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
session->in_buffer = ssh_buffer_new();
|
||||
if (session->in_buffer == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer_add_data(session->in_buffer, packet,
|
||||
to_be_read - current_macsize) < 0) {
|
||||
goto error;
|
||||
}
|
||||
processed += to_be_read - current_macsize;
|
||||
}
|
||||
memcpy(buffer, data, blocksize);
|
||||
processed += blocksize;
|
||||
len = packet_decrypt_len(session, buffer);
|
||||
|
||||
if (session->current_crypto) {
|
||||
/*
|
||||
* decrypt the rest of the packet (blocksize bytes already
|
||||
* have been decrypted)
|
||||
*/
|
||||
if (packet_decrypt(session,
|
||||
((uint8_t*)buffer_get_rest(session->in_buffer) + blocksize),
|
||||
buffer_get_rest_len(session->in_buffer) - blocksize) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Decrypt error");
|
||||
goto error;
|
||||
}
|
||||
/* copy the last part from the incoming buffer */
|
||||
memcpy(mac,(unsigned char *)packet + to_be_read - current_macsize, MACSIZE);
|
||||
rc = buffer_add_data(session->in_buffer, buffer, blocksize);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "HMAC error");
|
||||
goto error;
|
||||
}
|
||||
processed += current_macsize;
|
||||
}
|
||||
if (len > MAX_PACKET_LEN) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"read_packet(): Packet len too high(%u %.4x)",
|
||||
len, len);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* skip the size field which has been processed before */
|
||||
buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
|
||||
to_be_read = len - blocksize + sizeof(uint32_t);
|
||||
if (to_be_read < 0) {
|
||||
/* remote sshd sends invalid sizes? */
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Given numbers of bytes left to be read < 0 (%d)!",
|
||||
to_be_read);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (buffer_get_u8(session->in_buffer, &padding) == 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Packet too short to read padding");
|
||||
goto error;
|
||||
}
|
||||
/* Saves the status of the current operations */
|
||||
session->in_packet.len = len;
|
||||
session->packet_state = PACKET_STATE_SIZEREAD;
|
||||
/* FALL TROUGH */
|
||||
case PACKET_STATE_SIZEREAD:
|
||||
len = session->in_packet.len;
|
||||
to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
|
||||
/* if to_be_read is zero, the whole packet was blocksize bytes. */
|
||||
if (to_be_read != 0) {
|
||||
if (receivedlen - processed < (unsigned int)to_be_read) {
|
||||
/* give up, not enough data in buffer */
|
||||
SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len);
|
||||
return processed;
|
||||
}
|
||||
|
||||
if (padding > buffer_get_rest_len(session->in_buffer)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Invalid padding: %d (%d left)",
|
||||
padding,
|
||||
buffer_get_rest_len(session->in_buffer));
|
||||
goto error;
|
||||
}
|
||||
buffer_pass_bytes_end(session->in_buffer, padding);
|
||||
compsize = buffer_get_rest_len(session->in_buffer);
|
||||
packet = ((uint8_t*)data) + processed;
|
||||
#if 0
|
||||
ssh_socket_read(session->socket,
|
||||
packet,
|
||||
to_be_read - current_macsize);
|
||||
#endif
|
||||
|
||||
rc = buffer_add_data(session->in_buffer,
|
||||
packet,
|
||||
to_be_read - current_macsize);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
processed += to_be_read - current_macsize;
|
||||
}
|
||||
|
||||
if (session->current_crypto) {
|
||||
/*
|
||||
* Decrypt the rest of the packet (blocksize bytes already
|
||||
* have been decrypted)
|
||||
*/
|
||||
uint32_t buffer_len = buffer_get_rest_len(session->in_buffer);
|
||||
|
||||
/* The following check avoids decrypting zero bytes */
|
||||
if (buffer_len > blocksize) {
|
||||
uint8_t *payload = ((uint8_t*)buffer_get_rest(session->in_buffer) + blocksize);
|
||||
uint32_t plen = buffer_len - blocksize;
|
||||
|
||||
rc = packet_decrypt(session, payload, plen);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Decrypt error");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the last part from the incoming buffer */
|
||||
packet = ((uint8_t *)data) + processed;
|
||||
memcpy(mac, packet, MACSIZE);
|
||||
|
||||
rc = packet_hmac_verify(session, session->in_buffer, mac);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "HMAC error");
|
||||
goto error;
|
||||
}
|
||||
processed += current_macsize;
|
||||
}
|
||||
|
||||
/* skip the size field which has been processed before */
|
||||
buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
|
||||
|
||||
rc = buffer_get_u8(session->in_buffer, &padding);
|
||||
if (rc == 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Packet too short to read padding");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (padding > buffer_get_rest_len(session->in_buffer)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid padding: %d (%d left)",
|
||||
padding,
|
||||
buffer_get_rest_len(session->in_buffer));
|
||||
goto error;
|
||||
}
|
||||
buffer_pass_bytes_end(session->in_buffer, padding);
|
||||
compsize = buffer_get_rest_len(session->in_buffer);
|
||||
|
||||
#ifdef WITH_ZLIB
|
||||
if (session->current_crypto
|
||||
&& session->current_crypto->do_compress_in
|
||||
&& buffer_get_rest_len(session->in_buffer)) {
|
||||
if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (session->current_crypto
|
||||
&& session->current_crypto->do_compress_in
|
||||
&& buffer_get_rest_len(session->in_buffer) > 0) {
|
||||
rc = decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_ZLIB */
|
||||
payloadsize=buffer_get_rest_len(session->in_buffer);
|
||||
session->recv_seq++;
|
||||
/* We don't want to rewrite a new packet while still executing the packet callbacks */
|
||||
session->packet_state = PACKET_STATE_PROCESSING;
|
||||
ssh_packet_parse_type(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
|
||||
session->in_packet.type, len, padding, compsize, payloadsize);
|
||||
/* execute callbacks */
|
||||
ssh_packet_process(session, session->in_packet.type);
|
||||
session->packet_state = PACKET_STATE_INIT;
|
||||
if(processed < receivedlen){
|
||||
/* Handle a potential packet left in socket buffer */
|
||||
SSH_LOG(SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer",
|
||||
receivedlen-processed);
|
||||
rc = ssh_packet_socket_callback(((unsigned char *)data) + processed,
|
||||
receivedlen - processed,user);
|
||||
processed += rc;
|
||||
}
|
||||
payloadsize = buffer_get_rest_len(session->in_buffer);
|
||||
session->recv_seq++;
|
||||
|
||||
return processed;
|
||||
case PACKET_STATE_PROCESSING:
|
||||
SSH_LOG(SSH_LOG_RARE, "Nested packet processing. Delaying.");
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* We don't want to rewrite a new packet while still executing the
|
||||
* packet callbacks
|
||||
*/
|
||||
session->packet_state = PACKET_STATE_PROCESSING;
|
||||
ssh_packet_parse_type(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
|
||||
session->in_packet.type, len, padding, compsize, payloadsize);
|
||||
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Invalid state into packet_read2(): %d",
|
||||
session->packet_state);
|
||||
/* Execute callbacks */
|
||||
ssh_packet_process(session, session->in_packet.type);
|
||||
session->packet_state = PACKET_STATE_INIT;
|
||||
if (processed < receivedlen) {
|
||||
/* Handle a potential packet left in socket buffer */
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Processing %" PRIdS " bytes left in socket buffer",
|
||||
receivedlen-processed);
|
||||
|
||||
packet = ((uint8_t*)data) + processed;
|
||||
|
||||
rc = ssh_packet_socket_callback(packet, receivedlen - processed,user);
|
||||
processed += rc;
|
||||
}
|
||||
|
||||
return processed;
|
||||
case PACKET_STATE_PROCESSING:
|
||||
SSH_LOG(SSH_LOG_RARE, "Nested packet processing. Delaying.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid state into packet_read2(): %d",
|
||||
session->packet_state);
|
||||
|
||||
error:
|
||||
session->session_state= SSH_SESSION_STATE_ERROR;
|
||||
session->session_state= SSH_SESSION_STATE_ERROR;
|
||||
|
||||
return processed;
|
||||
return processed;
|
||||
}
|
||||
|
||||
void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){
|
||||
@@ -461,11 +504,13 @@ static int packet_send2(ssh_session session) {
|
||||
session->current_crypto->out_cipher->blocksize : 8);
|
||||
uint32_t currentlen = buffer_get_rest_len(session->out_buffer);
|
||||
unsigned char *hmac = NULL;
|
||||
char padstring[32] = {0};
|
||||
char padstring[32] = { 0 };
|
||||
int rc = SSH_ERROR;
|
||||
uint32_t finallen,payloadsize,compsize;
|
||||
uint8_t padding;
|
||||
|
||||
uint8_t header[sizeof(padding) + sizeof(finallen)] = { 0 };
|
||||
|
||||
payloadsize = currentlen;
|
||||
#ifdef WITH_ZLIB
|
||||
if (session->current_crypto
|
||||
@@ -485,19 +530,18 @@ static int packet_send2(ssh_session session) {
|
||||
|
||||
if (session->current_crypto) {
|
||||
ssh_get_random(padstring, padding, 0);
|
||||
} else {
|
||||
memset(padstring,0,padding);
|
||||
}
|
||||
|
||||
finallen = htonl(currentlen + padding + 1);
|
||||
|
||||
if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) {
|
||||
memcpy(&header[0], &finallen, sizeof(finallen));
|
||||
header[sizeof(finallen)] = padding;
|
||||
rc = buffer_prepend_data(session->out_buffer, &header, sizeof(header));
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (buffer_add_data(session->out_buffer, padstring, padding) < 0) {
|
||||
rc = buffer_add_data(session->out_buffer, padstring, padding);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
#ifdef WITH_PCAP
|
||||
|
||||
@@ -106,7 +106,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user
|
||||
size_t processed=0;
|
||||
uint32_t padding;
|
||||
uint32_t crc;
|
||||
uint32_t len;
|
||||
uint32_t len, buffer_len;
|
||||
ssh_session session=(ssh_session)user;
|
||||
|
||||
switch (session->packet_state){
|
||||
@@ -168,11 +168,16 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user
|
||||
* We decrypt everything, missing the lenght part (which was
|
||||
* previously read, unencrypted, and is not part of the buffer
|
||||
*/
|
||||
if (packet_decrypt(session,
|
||||
ssh_buffer_get_begin(session->in_buffer),
|
||||
ssh_buffer_get_len(session->in_buffer)) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
|
||||
goto error;
|
||||
buffer_len = ssh_buffer_get_len(session->in_buffer);
|
||||
if (buffer_len > 0) {
|
||||
int rc;
|
||||
rc = packet_decrypt(session,
|
||||
ssh_buffer_get_begin(session->in_buffer),
|
||||
buffer_len);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
@@ -300,6 +305,8 @@ int packet_send1(ssh_session session) {
|
||||
ssh_buffer_get_len(session->out_buffer));
|
||||
#endif
|
||||
|
||||
/* session->out_buffer should have more than sizeof(uint32_t) bytes
|
||||
in it as required for packet_encrypt */
|
||||
packet_encrypt(session, (unsigned char *)ssh_buffer_get_begin(session->out_buffer) + sizeof(uint32_t),
|
||||
ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t));
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -42,29 +43,35 @@
|
||||
* @brief Handle a SSH_DISCONNECT packet.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback){
|
||||
uint32_t code;
|
||||
char *error=NULL;
|
||||
ssh_string error_s;
|
||||
(void)user;
|
||||
(void)type;
|
||||
buffer_get_u32(packet, &code);
|
||||
int rc;
|
||||
uint32_t code = 0;
|
||||
char *error = NULL;
|
||||
ssh_string error_s;
|
||||
(void)user;
|
||||
(void)type;
|
||||
|
||||
rc = buffer_get_u32(packet, &code);
|
||||
if (rc != 0) {
|
||||
code = ntohl(code);
|
||||
}
|
||||
|
||||
error_s = buffer_get_ssh_string(packet);
|
||||
if (error_s != NULL) {
|
||||
error = ssh_string_to_char(error_s);
|
||||
ssh_string_free(error_s);
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",code,
|
||||
error != NULL ? error : "no error");
|
||||
SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",
|
||||
code, error != NULL ? error : "no error");
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Received SSH_MSG_DISCONNECT: %d:%s",code,
|
||||
error != NULL ? error : "no error");
|
||||
"Received SSH_MSG_DISCONNECT: %d:%s",
|
||||
code, error != NULL ? error : "no error");
|
||||
SAFE_FREE(error);
|
||||
|
||||
ssh_socket_close(session->socket);
|
||||
session->alive = 0;
|
||||
session->session_state= SSH_SESSION_STATE_ERROR;
|
||||
/* TODO: handle a graceful disconnect */
|
||||
return SSH_PACKET_USED;
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
/* TODO: handle a graceful disconnect */
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,6 +109,11 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
rc = ssh_client_ecdh_reply(session, packet);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
rc = ssh_client_curve25519_reply(session, packet);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_dh_reply");
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -59,6 +60,9 @@ uint32_t packet_decrypt_len(ssh_session session, char *crypted){
|
||||
int packet_decrypt(ssh_session session, void *data,uint32_t len) {
|
||||
struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher;
|
||||
char *out = NULL;
|
||||
|
||||
assert(len);
|
||||
|
||||
if(len % session->current_crypto->in_cipher->blocksize != 0){
|
||||
ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
|
||||
return SSH_ERROR;
|
||||
@@ -89,6 +93,8 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) {
|
||||
unsigned int finallen;
|
||||
uint32_t seq;
|
||||
|
||||
assert(len);
|
||||
|
||||
if (!session->current_crypto) {
|
||||
return NULL; /* nothing to do here */
|
||||
}
|
||||
|
||||
229
src/pki.c
229
src/pki.c
@@ -3,7 +3,7 @@
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2010 by Aris Adamantiadis
|
||||
* Copyright (c) 2011-2012 Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2011-2013 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
|
||||
@@ -98,6 +98,25 @@ enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey) {
|
||||
return SSH_KEYTYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns the ECDSA key name ("ecdsa-sha2-nistp256" for example)
|
||||
*
|
||||
* @param[in] key the ssh_key whose ECDSA name to get
|
||||
*
|
||||
* @returns the ECDSA key name ("ecdsa-sha2-nistp256" for example)
|
||||
*
|
||||
* @returns "unknown" if the ECDSA key name is not known
|
||||
*/
|
||||
const char *ssh_pki_key_ecdsa_name(const ssh_key key)
|
||||
{
|
||||
#ifdef HAVE_OPENSSL_ECC /* FIXME Better ECC check needed */
|
||||
return pki_key_ecdsa_nid_to_name(key->ecdsa_nid);
|
||||
#else
|
||||
(void) key; /* unused */
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief creates a new empty SSH key
|
||||
* @returns an empty ssh_key handle, or NULL on error.
|
||||
@@ -331,6 +350,10 @@ void ssh_signature_free(ssh_signature sig)
|
||||
#endif
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ECC)
|
||||
ECDSA_SIG_free(sig->ecdsa_sig);
|
||||
#endif
|
||||
break;
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
@@ -349,8 +372,8 @@ void ssh_signature_free(ssh_signature sig)
|
||||
*
|
||||
* @param[in] auth_data Private data passed to the auth function.
|
||||
*
|
||||
* @param[out] pkey A pointer where the key can be stored. You need
|
||||
* to free the memory.
|
||||
* @param[out] pkey A pointer where the allocated key can be stored. You
|
||||
* need to free the memory.
|
||||
*
|
||||
* @return SSH_ERROR in case of error, SSH_OK otherwise.
|
||||
*
|
||||
@@ -397,8 +420,8 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
|
||||
*
|
||||
* @param[in] auth_data Private data passed to the auth function.
|
||||
*
|
||||
* @param[out] pkey A pointer to store the ssh_key. You need to free the
|
||||
* key.
|
||||
* @param[out] pkey A pointer to store the allocated ssh_key. You need to
|
||||
* free the key.
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
|
||||
* denied, SSH_ERROR otherwise.
|
||||
@@ -476,6 +499,65 @@ int ssh_pki_import_privkey_file(const char *filename,
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Export a private key to a pam file on disk.
|
||||
*
|
||||
* @param[in] privkey The private key to export.
|
||||
*
|
||||
* @param[in] passphrase The passphrase to use to encrypt the key with or
|
||||
* NULL. An empty string means no passphrase.
|
||||
*
|
||||
* @param[in] auth_fn An auth function you may want to use or NULL.
|
||||
*
|
||||
* @param[in] auth_data Private data passed to the auth function.
|
||||
*
|
||||
* @param[in] filename The path where to store the pem file.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*/
|
||||
int ssh_pki_export_privkey_file(const ssh_key privkey,
|
||||
const char *passphrase,
|
||||
ssh_auth_callback auth_fn,
|
||||
void *auth_data,
|
||||
const char *filename)
|
||||
{
|
||||
ssh_string blob;
|
||||
FILE *fp;
|
||||
int rc;
|
||||
|
||||
if (privkey == NULL || !ssh_key_is_private(privkey)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
fp = fopen(filename, "wb");
|
||||
if (fp == NULL) {
|
||||
SSH_LOG(SSH_LOG_FUNCTIONS, "Error opening %s: %s",
|
||||
filename, strerror(errno));
|
||||
return SSH_EOF;
|
||||
}
|
||||
|
||||
|
||||
blob = pki_private_key_to_pem(privkey,
|
||||
passphrase,
|
||||
auth_fn,
|
||||
auth_data);
|
||||
if (blob == NULL) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = fwrite(ssh_string_data(blob), ssh_string_len(blob), 1, fp);
|
||||
ssh_string_free(blob);
|
||||
if (rc != 1 || ferror(fp)) {
|
||||
fclose(fp);
|
||||
unlink(filename);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/* temporary function to migrate seemlessly to ssh_key */
|
||||
ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key) {
|
||||
ssh_public_key pub;
|
||||
@@ -661,6 +743,9 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Update key type */
|
||||
key->type_c = ssh_pki_key_ecdsa_name(key);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -684,8 +769,8 @@ fail:
|
||||
*
|
||||
* @param[in] type The type of the key to format.
|
||||
*
|
||||
* @param[out] pkey A pointer where the key can be stored. You need
|
||||
* to free the memory.
|
||||
* @param[out] pkey A pointer where the allocated key can be stored. You
|
||||
* need to free the memory.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*
|
||||
@@ -728,8 +813,8 @@ int ssh_pki_import_pubkey_base64(const char *b64_key,
|
||||
* @param[in] key_blob The key blob to import as specified in RFC 4253 section
|
||||
* 6.6 "Public Key Algorithms".
|
||||
*
|
||||
* @param[out] pkey A pointer where the key can be stored. You need
|
||||
* to free the memory.
|
||||
* @param[out] pkey A pointer where the allocated key can be stored. You
|
||||
* need to free the memory.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*
|
||||
@@ -789,8 +874,8 @@ fail:
|
||||
*
|
||||
* @param[in] filename The path to the public key.
|
||||
*
|
||||
* @param[out] pkey A pointer to store the public key. You need to free the
|
||||
* memory.
|
||||
* @param[out] pkey A pointer to store the allocated public key. You need to
|
||||
* free the memory.
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
|
||||
* denied, SSH_ERROR otherwise.
|
||||
@@ -875,17 +960,20 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
|
||||
|
||||
/**
|
||||
* @brief Generates a keypair.
|
||||
*
|
||||
* @param[in] type Type of key to create
|
||||
*
|
||||
* @param[in] parameter Parameter to the creation of key:
|
||||
* rsa : length of the key in bits (e.g. 1024, 2048, 4096)
|
||||
* dsa : length of the key in bits (e.g. 1024, 2048, 3072)
|
||||
* ecdsa : bits of the key (e.g. 256, 384, 512)
|
||||
* @param[out] pkey A pointer to store the private key. You need to free the
|
||||
* memory.
|
||||
* @param[out] pkey A pointer to store the allocated private key. You need
|
||||
* to free the memory.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*
|
||||
* @warning Generating a key pair may take some time.
|
||||
*/
|
||||
|
||||
int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
|
||||
ssh_key *pkey){
|
||||
int rc;
|
||||
@@ -914,8 +1002,12 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_ECC
|
||||
rc = pki_key_generate_ecdsa(key, parameter);
|
||||
if(rc == SSH_ERROR)
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Update key type */
|
||||
key->type_c = ssh_pki_key_ecdsa_name(key);
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
@@ -1000,7 +1092,8 @@ int ssh_pki_export_pubkey_blob(const ssh_key key,
|
||||
*
|
||||
* @param[in] key The key to hash
|
||||
*
|
||||
* @param[out] b64_key A pointer to store the base64 hased key.
|
||||
* @param[out] b64_key A pointer to store the allocated base64 hashed key. You
|
||||
* need to free the buffer.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error.
|
||||
*
|
||||
@@ -1114,7 +1207,7 @@ int ssh_pki_export_signature_blob(const ssh_signature sig,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
str = ssh_string_from_char(ssh_key_type_to_char(sig->type));
|
||||
str = ssh_string_from_char(sig->type_c);
|
||||
if (str == NULL) {
|
||||
ssh_buffer_free(buf);
|
||||
return SSH_ERROR;
|
||||
@@ -1232,6 +1325,11 @@ int ssh_pki_signature_verify_blob(ssh_session session,
|
||||
|
||||
evp(key->ecdsa_nid, digest, dlen, ehash, &elen);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Hash to be verified with ecdsa",
|
||||
ehash, elen);
|
||||
#endif
|
||||
|
||||
rc = pki_signature_verify(session,
|
||||
sig,
|
||||
key,
|
||||
@@ -1267,11 +1365,9 @@ ssh_string ssh_pki_do_sign(ssh_session session,
|
||||
struct ssh_crypto_struct *crypto =
|
||||
session->current_crypto ? session->current_crypto :
|
||||
session->next_crypto;
|
||||
unsigned char hash[SHA_DIGEST_LEN] = {0};
|
||||
ssh_signature sig;
|
||||
ssh_string sig_blob;
|
||||
ssh_string session_id;
|
||||
SHACTX ctx;
|
||||
int rc;
|
||||
|
||||
if (privkey == NULL || !ssh_key_is_private(privkey)) {
|
||||
@@ -1283,24 +1379,50 @@ ssh_string ssh_pki_do_sign(ssh_session session,
|
||||
return NULL;
|
||||
}
|
||||
ssh_string_fill(session_id, crypto->session_id, crypto->digest_len);
|
||||
/* TODO: change when supporting ECDSA keys */
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
ssh_string_free(session_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sha1_update(ctx, session_id, ssh_string_len(session_id) + 4);
|
||||
ssh_string_free(session_id);
|
||||
if (privkey->type == SSH_KEYTYPE_ECDSA) {
|
||||
#ifdef HAVE_ECC
|
||||
unsigned char ehash[EVP_DIGEST_LEN] = {0};
|
||||
uint32_t elen;
|
||||
EVPCTX ctx;
|
||||
|
||||
sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
|
||||
sha1_final(hash, ctx);
|
||||
ctx = evp_init(privkey->ecdsa_nid);
|
||||
if (ctx == NULL) {
|
||||
ssh_string_free(session_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evp_update(ctx, session_id, ssh_string_len(session_id) + 4);
|
||||
evp_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
|
||||
evp_final(ctx, ehash, &elen);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("Hash being signed", ehash, elen);
|
||||
#endif
|
||||
|
||||
sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN);
|
||||
sig = pki_do_sign(privkey, ehash, elen);
|
||||
#endif
|
||||
} else {
|
||||
unsigned char hash[SHA_DIGEST_LEN] = {0};
|
||||
SHACTX ctx;
|
||||
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
ssh_string_free(session_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sha1_update(ctx, session_id, ssh_string_len(session_id) + 4);
|
||||
sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
|
||||
sha1_final(hash, ctx);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
|
||||
#endif
|
||||
|
||||
sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN);
|
||||
}
|
||||
ssh_string_free(session_id);
|
||||
if (sig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -1371,10 +1493,8 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
|
||||
const ssh_key privkey)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto;
|
||||
unsigned char hash[SHA_DIGEST_LEN] = {0};
|
||||
ssh_signature sig;
|
||||
ssh_string sig_blob;
|
||||
SHACTX ctx;
|
||||
int rc;
|
||||
|
||||
if (session == NULL || privkey == NULL || !ssh_key_is_private(privkey)) {
|
||||
@@ -1383,24 +1503,47 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
|
||||
crypto = session->next_crypto ? session->next_crypto :
|
||||
session->current_crypto;
|
||||
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (crypto->secret_hash == NULL){
|
||||
ssh_set_error(session,SSH_FATAL,"Missing secret_hash");
|
||||
return NULL;
|
||||
}
|
||||
sha1_update(ctx, crypto->secret_hash, crypto->digest_len);
|
||||
sha1_final(hash, ctx);
|
||||
|
||||
if (privkey->type == SSH_KEYTYPE_ECDSA) {
|
||||
#ifdef HAVE_ECC
|
||||
unsigned char ehash[EVP_DIGEST_LEN] = {0};
|
||||
uint32_t elen;
|
||||
|
||||
evp(privkey->ecdsa_nid, crypto->secret_hash, crypto->digest_len,
|
||||
ehash, &elen);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("Hash being signed", ehash, elen);
|
||||
#endif
|
||||
|
||||
sig = pki_do_sign_sessionid(privkey, hash, SHA_DIGEST_LEN);
|
||||
if (sig == NULL) {
|
||||
return NULL;
|
||||
sig = pki_do_sign_sessionid(privkey, ehash, elen);
|
||||
if (sig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
unsigned char hash[SHA_DIGEST_LEN] = {0};
|
||||
SHACTX ctx;
|
||||
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
sha1_update(ctx, crypto->secret_hash, crypto->digest_len);
|
||||
sha1_final(hash, ctx);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
|
||||
#endif
|
||||
|
||||
sig = pki_do_sign_sessionid(privkey, hash, SHA_DIGEST_LEN);
|
||||
if (sig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ssh_pki_export_signature_blob(sig, &sig_blob);
|
||||
|
||||
371
src/pki_crypto.c
371
src/pki_crypto.c
@@ -4,7 +4,7 @@
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2009-2012 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2009-2013 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
|
||||
@@ -25,6 +25,8 @@
|
||||
#ifndef _PKI_CRYPTO_H
|
||||
#define _PKI_CRYPTO_H
|
||||
|
||||
#include "libssh/priv.h"
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/err.h>
|
||||
@@ -37,8 +39,6 @@
|
||||
#include <openssl/ecdsa.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
@@ -89,7 +89,7 @@ static int pki_key_ecdsa_to_nid(EC_KEY *k)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *pki_key_ecdsa_nid_to_name(int nid)
|
||||
const char *pki_key_ecdsa_nid_to_name(int nid)
|
||||
{
|
||||
switch (nid) {
|
||||
case NID_X9_62_prime256v1:
|
||||
@@ -200,9 +200,11 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* EC_KEY_set_public_key duplicates p */
|
||||
ok = EC_KEY_set_public_key(key->ecdsa, p);
|
||||
EC_POINT_free(p);
|
||||
if (!ok) {
|
||||
EC_POINT_free(p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -343,13 +345,13 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
new->ecdsa_nid = key->ecdsa_nid;
|
||||
|
||||
/* privkey -> pubkey */
|
||||
if (demote && ssh_key_is_private(key)) {
|
||||
const EC_POINT *p;
|
||||
int ok;
|
||||
|
||||
new->ecdsa_nid = key->ecdsa_nid;
|
||||
|
||||
new->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
|
||||
if (new->ecdsa == NULL) {
|
||||
goto fail;
|
||||
@@ -381,10 +383,20 @@ fail:
|
||||
}
|
||||
|
||||
int pki_key_generate_rsa(ssh_key key, int parameter){
|
||||
key->rsa = RSA_generate_key(parameter, 65537, NULL, NULL);
|
||||
if(key->rsa == NULL)
|
||||
return SSH_ERROR;
|
||||
return SSH_OK;
|
||||
BIGNUM *e;
|
||||
int rc;
|
||||
|
||||
e = BN_new();
|
||||
key->rsa = RSA_new();
|
||||
|
||||
BN_set_word(e, 65537);
|
||||
rc = RSA_generate_key_ex(key->rsa, parameter, e, NULL);
|
||||
|
||||
BN_free(e);
|
||||
|
||||
if (rc == -1 || key->rsa == NULL)
|
||||
return SSH_ERROR;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int pki_key_generate_dss(ssh_key key, int parameter){
|
||||
@@ -528,6 +540,124 @@ int pki_key_compare(const ssh_key k1,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssh_string pki_private_key_to_pem(const ssh_key key,
|
||||
const char *passphrase,
|
||||
ssh_auth_callback auth_fn,
|
||||
void *auth_data)
|
||||
{
|
||||
ssh_string blob;
|
||||
BUF_MEM *buf;
|
||||
BIO *mem;
|
||||
int rc;
|
||||
|
||||
/* needed for openssl initialization */
|
||||
if (ssh_init() < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mem = BIO_new(BIO_s_mem());
|
||||
if (mem == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (key->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
if (passphrase == NULL) {
|
||||
struct pem_get_password_struct pgp = { auth_fn, auth_data };
|
||||
|
||||
rc = PEM_write_bio_DSAPrivateKey(mem,
|
||||
key->dsa,
|
||||
NULL, /* cipher */
|
||||
NULL, /* kstr */
|
||||
0, /* klen */
|
||||
pem_get_password,
|
||||
&pgp);
|
||||
} else {
|
||||
rc = PEM_write_bio_DSAPrivateKey(mem,
|
||||
key->dsa,
|
||||
NULL, /* cipher */
|
||||
NULL, /* kstr */
|
||||
0, /* klen */
|
||||
NULL, /* auth_fn */
|
||||
(void*) passphrase);
|
||||
}
|
||||
if (rc != 1) {
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
if (passphrase == NULL) {
|
||||
struct pem_get_password_struct pgp = { auth_fn, auth_data };
|
||||
|
||||
rc = PEM_write_bio_RSAPrivateKey(mem,
|
||||
key->rsa,
|
||||
NULL, /* cipher */
|
||||
NULL, /* kstr */
|
||||
0, /* klen */
|
||||
pem_get_password,
|
||||
&pgp);
|
||||
} else {
|
||||
rc = PEM_write_bio_RSAPrivateKey(mem,
|
||||
key->rsa,
|
||||
NULL, /* cipher */
|
||||
NULL, /* kstr */
|
||||
0, /* klen */
|
||||
NULL, /* auth_fn */
|
||||
(void*) passphrase);
|
||||
}
|
||||
if (rc != 1) {
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_ECC
|
||||
if (passphrase == NULL) {
|
||||
struct pem_get_password_struct pgp = { auth_fn, auth_data };
|
||||
|
||||
rc = PEM_write_bio_ECPrivateKey(mem,
|
||||
key->ecdsa,
|
||||
NULL, /* cipher */
|
||||
NULL, /* kstr */
|
||||
0, /* klen */
|
||||
pem_get_password,
|
||||
&pgp);
|
||||
} else {
|
||||
rc = PEM_write_bio_ECPrivateKey(mem,
|
||||
key->ecdsa,
|
||||
NULL, /* cipher */
|
||||
NULL, /* kstr */
|
||||
0, /* klen */
|
||||
NULL, /* auth_fn */
|
||||
(void*) passphrase);
|
||||
}
|
||||
if (rc != 1) {
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
BIO_free(mem);
|
||||
ssh_pki_log("Unkown or invalid private key type %d", key->type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BIO_get_mem_ptr(mem, &buf);
|
||||
|
||||
blob = ssh_string_new(buf->length);
|
||||
if (blob == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ssh_string_fill(blob, buf->data, buf->length);
|
||||
BIO_free(mem);
|
||||
|
||||
return blob;
|
||||
err:
|
||||
BIO_free(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
const char *passphrase,
|
||||
ssh_auth_callback auth_fn,
|
||||
@@ -976,41 +1106,65 @@ static ssh_string _RSA_do_sign(const unsigned char *digest,
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
|
||||
{
|
||||
char buffer[40] = { 0 };
|
||||
ssh_string sig_blob = NULL;
|
||||
|
||||
ssh_string r;
|
||||
int r_len, r_offset_in, r_offset_out;
|
||||
|
||||
ssh_string s;
|
||||
int s_len, s_offset_in, s_offset_out;
|
||||
|
||||
r = make_bignum_string(sig->dsa_sig->r);
|
||||
if (r == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = make_bignum_string(sig->dsa_sig->s);
|
||||
if (s == NULL) {
|
||||
ssh_string_free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_len = ssh_string_len(r);
|
||||
r_offset_in = (r_len > 20) ? (r_len - 20) : 0;
|
||||
r_offset_out = (r_len < 20) ? (20 - r_len) : 0;
|
||||
|
||||
s_len = ssh_string_len(s);
|
||||
s_offset_in = (s_len > 20) ? (s_len - 20) : 0;
|
||||
s_offset_out = (s_len < 20) ? (20 - s_len) : 0;
|
||||
|
||||
memcpy(buffer + r_offset_out,
|
||||
((char *)ssh_string_data(r)) + r_offset_in,
|
||||
r_len - r_offset_in);
|
||||
memcpy(buffer + 20 + s_offset_out,
|
||||
((char *)ssh_string_data(s)) + s_offset_in,
|
||||
s_len - s_offset_in);
|
||||
|
||||
ssh_string_free(r);
|
||||
ssh_string_free(s);
|
||||
|
||||
sig_blob = ssh_string_new(40);
|
||||
if (sig_blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_string_fill(sig_blob, buffer, 40);
|
||||
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
{
|
||||
char buffer[40] = {0};
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_string r;
|
||||
ssh_string s;
|
||||
ssh_string sig_blob = NULL;
|
||||
|
||||
switch(sig->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
r = make_bignum_string(sig->dsa_sig->r);
|
||||
if (r == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
s = make_bignum_string(sig->dsa_sig->s);
|
||||
if (s == NULL) {
|
||||
ssh_string_free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buffer,
|
||||
((char *)ssh_string_data(r)) + ssh_string_len(r) - 20,
|
||||
20);
|
||||
memcpy(buffer + 20,
|
||||
((char *)ssh_string_data(s)) + ssh_string_len(s) - 20,
|
||||
20);
|
||||
|
||||
ssh_string_free(r);
|
||||
ssh_string_free(s);
|
||||
|
||||
sig_blob = ssh_string_new(40);
|
||||
if (sig_blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_string_fill(sig_blob, buffer, 40);
|
||||
sig_blob = pki_dsa_signature_to_blob(sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
@@ -1018,42 +1172,119 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
{
|
||||
ssh_buffer b;
|
||||
int rc;
|
||||
|
||||
b = ssh_buffer_new();
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = make_bignum_string(sig->ecdsa_sig->r);
|
||||
if (r == NULL) {
|
||||
ssh_buffer_free(b);
|
||||
return NULL;
|
||||
}
|
||||
rc = buffer_add_ssh_string(b, r);
|
||||
ssh_string_free(r);
|
||||
if (rc < 0) {
|
||||
ssh_buffer_free(b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = make_bignum_string(sig->ecdsa_sig->s);
|
||||
if (s == NULL) {
|
||||
ssh_string_free(r);
|
||||
ssh_buffer_free(b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buffer,
|
||||
((char *)ssh_string_data(r)) + ssh_string_len(r) - 20,
|
||||
20);
|
||||
memcpy(buffer + 20,
|
||||
((char *)ssh_string_data(s)) + ssh_string_len(s) - 20,
|
||||
20);
|
||||
|
||||
ssh_string_free(r);
|
||||
rc = buffer_add_ssh_string(b, s);
|
||||
ssh_string_free(s);
|
||||
|
||||
sig_blob = ssh_string_new(40);
|
||||
if (sig_blob == NULL) {
|
||||
if (rc < 0) {
|
||||
ssh_buffer_free(b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_string_fill(sig_blob, buffer, 40);
|
||||
sig_blob = ssh_string_new(buffer_get_rest_len(b));
|
||||
if (sig_blob == NULL) {
|
||||
ssh_buffer_free(b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_string_fill(sig_blob, buffer_get_rest(b), buffer_get_rest_len(b));
|
||||
ssh_buffer_free(b);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
ssh_pki_log("Unknown signature key type: %d", sig->type);
|
||||
ssh_pki_log("Unknown signature key type: %s", sig->type_c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sig_blob;
|
||||
}
|
||||
|
||||
static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey,
|
||||
const ssh_string sig_blob,
|
||||
ssh_signature sig)
|
||||
{
|
||||
uint32_t pad_len = 0;
|
||||
char *blob_orig;
|
||||
char *blob_padded_data;
|
||||
ssh_string sig_blob_padded;
|
||||
|
||||
size_t rsalen = 0;
|
||||
size_t len = ssh_string_len(sig_blob);
|
||||
|
||||
if (pubkey->rsa == NULL) {
|
||||
ssh_pki_log("Pubkey RSA field NULL");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rsalen = RSA_size(pubkey->rsa);
|
||||
if (len > rsalen) {
|
||||
ssh_pki_log("Signature is too big: %lu > %lu",
|
||||
(unsigned long)len, (unsigned long)rsalen);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_pki_log("RSA signature len: %lu", (unsigned long)len);
|
||||
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
|
||||
#endif
|
||||
|
||||
if (len == rsalen) {
|
||||
sig->rsa_sig = ssh_string_copy(sig_blob);
|
||||
} else {
|
||||
/* pad the blob to the expected rsalen size */
|
||||
ssh_pki_log("RSA signature len %lu < %lu",
|
||||
(unsigned long)len, (unsigned long)rsalen);
|
||||
|
||||
pad_len = rsalen - len;
|
||||
|
||||
sig_blob_padded = ssh_string_new(rsalen);
|
||||
if (sig_blob_padded == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
blob_padded_data = (char *) ssh_string_data(sig_blob_padded);
|
||||
blob_orig = (char *) ssh_string_data(sig_blob);
|
||||
|
||||
/* front-pad the buffer with zeroes */
|
||||
BURN_BUFFER(blob_padded_data, pad_len);
|
||||
/* fill the rest with the actual signature blob */
|
||||
memcpy(blob_padded_data + pad_len, blob_orig, len);
|
||||
|
||||
sig->rsa_sig = sig_blob_padded;
|
||||
}
|
||||
|
||||
return sig;
|
||||
|
||||
errout:
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
const ssh_string sig_blob,
|
||||
enum ssh_keytypes_e type)
|
||||
@@ -1062,7 +1293,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
ssh_string r;
|
||||
ssh_string s;
|
||||
size_t len;
|
||||
size_t rsalen;
|
||||
|
||||
sig = ssh_signature_new();
|
||||
if (sig == NULL) {
|
||||
@@ -1070,6 +1300,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
}
|
||||
|
||||
sig->type = type;
|
||||
sig->type_c = ssh_key_type_to_char(type);
|
||||
|
||||
len = ssh_string_len(sig_blob);
|
||||
|
||||
@@ -1125,29 +1356,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
break;
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
rsalen = RSA_size(pubkey->rsa);
|
||||
|
||||
if (len > rsalen) {
|
||||
ssh_pki_log("Signature is to big size: %lu",
|
||||
(unsigned long)len);
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len < rsalen) {
|
||||
ssh_pki_log("RSA signature len %lu < %lu",
|
||||
(unsigned long)len, (unsigned long)rsalen);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_pki_log("RSA signature len: %lu", (unsigned long)len);
|
||||
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
|
||||
#endif
|
||||
sig->rsa_sig = ssh_string_copy(sig_blob);
|
||||
if (sig->rsa_sig == NULL) {
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
sig = pki_signature_from_rsa_blob(pubkey, sig_blob, sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
@@ -1188,7 +1397,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
|
||||
#endif
|
||||
|
||||
sig->ecdsa_sig->r = make_string_bn(r);
|
||||
make_string_bn_inplace(r, sig->ecdsa_sig->r);
|
||||
ssh_string_burn(r);
|
||||
ssh_string_free(r);
|
||||
if (sig->ecdsa_sig->r == NULL) {
|
||||
@@ -1209,7 +1418,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
|
||||
#endif
|
||||
|
||||
sig->ecdsa_sig->s = make_string_bn(s);
|
||||
make_string_bn_inplace(s, sig->ecdsa_sig->s);
|
||||
ssh_string_burn(s);
|
||||
ssh_string_free(s);
|
||||
if (sig->ecdsa_sig->s == NULL) {
|
||||
@@ -1309,6 +1518,7 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
}
|
||||
|
||||
sig->type = privkey->type;
|
||||
sig->type_c = privkey->type_c;
|
||||
|
||||
switch(privkey->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
@@ -1368,6 +1578,7 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
|
||||
return NULL;
|
||||
}
|
||||
sig->type = key->type;
|
||||
sig->type_c = key->type_c;
|
||||
|
||||
switch(key->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
|
||||
@@ -591,6 +591,19 @@ int pki_key_ecdsa_nid_from_name(const char *name)
|
||||
}
|
||||
#endif
|
||||
|
||||
ssh_string pki_private_key_to_pem(const ssh_key key,
|
||||
const char *passphrase,
|
||||
ssh_auth_callback auth_fn,
|
||||
void *auth_data)
|
||||
{
|
||||
(void) key;
|
||||
(void) passphrase;
|
||||
(void) auth_fn;
|
||||
(void) auth_data;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
const char *passphrase,
|
||||
ssh_auth_callback auth_fn,
|
||||
@@ -1577,7 +1590,7 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
return NULL;
|
||||
}
|
||||
sig->type = privkey->type;
|
||||
|
||||
sig->type_c = privkey->type_c;
|
||||
switch (privkey->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
/* That is to mark the number as positive */
|
||||
@@ -1644,6 +1657,7 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
|
||||
return NULL;
|
||||
}
|
||||
sig->type = key->type;
|
||||
sig->type_c = key->type_c;
|
||||
|
||||
switch(key->type) {
|
||||
case SSH_KEYTYPE_DSS:
|
||||
|
||||
62
src/poll.c
62
src/poll.c
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009-2010 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
||||
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2003-2013 by Aris Adamantiadis
|
||||
* Copyright (c) 2009 Aleksandar Kanchev
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
@@ -64,6 +64,7 @@
|
||||
|
||||
struct ssh_poll_handle_struct {
|
||||
ssh_poll_ctx ctx;
|
||||
ssh_session session;
|
||||
union {
|
||||
socket_t fd;
|
||||
size_t idx;
|
||||
@@ -450,7 +451,11 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
|
||||
if (ctx->polls_allocated > 0) {
|
||||
while (ctx->polls_used > 0){
|
||||
ssh_poll_handle p = ctx->pollptrs[0];
|
||||
ssh_poll_ctx_remove(ctx, p);
|
||||
/*
|
||||
* The free function calls ssh_poll_ctx_remove() and decrements
|
||||
* ctx->polls_used
|
||||
*/
|
||||
ssh_poll_free(p);
|
||||
}
|
||||
|
||||
SAFE_FREE(ctx->pollptrs);
|
||||
@@ -468,14 +473,18 @@ static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size) {
|
||||
if (pollptrs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->pollptrs = pollptrs;
|
||||
|
||||
pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
|
||||
if (pollfds == NULL) {
|
||||
ctx->pollptrs = realloc(pollptrs, sizeof(ssh_poll_handle) * ctx->polls_allocated);
|
||||
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * ctx->polls_allocated);
|
||||
if (pollptrs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->pollptrs = pollptrs;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->pollptrs = pollptrs;
|
||||
ctx->pollfds = pollfds;
|
||||
ctx->polls_allocated = new_size;
|
||||
|
||||
@@ -782,6 +791,10 @@ int ssh_event_add_session(ssh_event event, ssh_session session) {
|
||||
p = session->default_poll_ctx->pollptrs[i];
|
||||
ssh_poll_ctx_remove(session->default_poll_ctx, p);
|
||||
ssh_poll_ctx_add(event->ctx, p);
|
||||
/* associate the pollhandler with a session so we can put it back
|
||||
* at ssh_event_free()
|
||||
*/
|
||||
p->session = session;
|
||||
}
|
||||
#ifdef WITH_SERVER
|
||||
iterator = ssh_list_get_iterator(event->sessions);
|
||||
@@ -844,12 +857,22 @@ int ssh_event_remove_fd(ssh_event event, socket_t fd) {
|
||||
for (i = 0; i < used; i++) {
|
||||
if(fd == event->ctx->pollfds[i].fd) {
|
||||
ssh_poll_handle p = event->ctx->pollptrs[i];
|
||||
struct ssh_event_fd_wrapper *pw = p->cb_data;
|
||||
if (p->session != NULL){
|
||||
/* we cannot free that handle, it's owned by its session */
|
||||
continue;
|
||||
}
|
||||
if (p->cb == ssh_event_fd_wrapper_callback) {
|
||||
struct ssh_event_fd_wrapper *pw = p->cb_data;
|
||||
SAFE_FREE(pw);
|
||||
}
|
||||
|
||||
ssh_poll_ctx_remove(event->ctx, p);
|
||||
free(pw);
|
||||
/*
|
||||
* The free function calls ssh_poll_ctx_remove() and decrements
|
||||
* event->ctx->polls_used.
|
||||
*/
|
||||
ssh_poll_free(p);
|
||||
rc = SSH_OK;
|
||||
|
||||
/* restart the loop */
|
||||
used = event->ctx->polls_used;
|
||||
i = 0;
|
||||
@@ -872,7 +895,6 @@ int ssh_event_remove_session(ssh_event event, ssh_session session) {
|
||||
ssh_poll_handle p;
|
||||
register size_t i, used;
|
||||
int rc = SSH_ERROR;
|
||||
socket_t session_fd;
|
||||
#ifdef WITH_SERVER
|
||||
struct ssh_iterator *iterator;
|
||||
#endif
|
||||
@@ -881,14 +903,15 @@ int ssh_event_remove_session(ssh_event event, ssh_session session) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
session_fd = ssh_get_fd(session);
|
||||
used = event->ctx->polls_used;
|
||||
for(i = 0; i < used; i++) {
|
||||
if(session_fd == event->ctx->pollfds[i].fd) {
|
||||
p = event->ctx->pollptrs[i];
|
||||
p = event->ctx->pollptrs[i];
|
||||
if(p->session == session){
|
||||
ssh_poll_ctx_remove(event->ctx, p);
|
||||
p->session = NULL;
|
||||
ssh_poll_ctx_add(session->default_poll_ctx, p);
|
||||
rc = SSH_OK;
|
||||
used = 0;
|
||||
}
|
||||
}
|
||||
#ifdef WITH_SERVER
|
||||
@@ -915,10 +938,23 @@ int ssh_event_remove_session(ssh_event event, ssh_session session) {
|
||||
*
|
||||
*/
|
||||
void ssh_event_free(ssh_event event) {
|
||||
if(event == NULL) {
|
||||
int used, i;
|
||||
ssh_poll_handle p;
|
||||
if(event == NULL) {
|
||||
return;
|
||||
}
|
||||
if(event->ctx != NULL) {
|
||||
used = event->ctx->polls_used;
|
||||
for(i = 0; i < used; i++) {
|
||||
p = event->ctx->pollptrs[i];
|
||||
if(p->session != NULL){
|
||||
ssh_poll_ctx_remove(event->ctx, p);
|
||||
ssh_poll_ctx_add(p->session->default_poll_ctx, p);
|
||||
p->session = NULL;
|
||||
used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ssh_poll_ctx_free(event->ctx);
|
||||
}
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
38
src/scp.c
38
src/scp.c
@@ -83,7 +83,17 @@ ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){
|
||||
return scp;
|
||||
}
|
||||
|
||||
int ssh_scp_init(ssh_scp scp){
|
||||
/**
|
||||
* @brief Initialize the scp channel.
|
||||
*
|
||||
* @param[in] scp The scp context to initialize.
|
||||
*
|
||||
* @return SSH_OK on success or an SSH error code.
|
||||
*
|
||||
* @see ssh_scp_new()
|
||||
*/
|
||||
int ssh_scp_init(ssh_scp scp)
|
||||
{
|
||||
int r;
|
||||
char execbuffer[1024];
|
||||
uint8_t code;
|
||||
@@ -139,7 +149,17 @@ int ssh_scp_init(ssh_scp scp){
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_scp_close(ssh_scp scp){
|
||||
/**
|
||||
* @brief Close the scp channel.
|
||||
*
|
||||
* @param[in] scp The scp context to close.
|
||||
*
|
||||
* @return SSH_OK on success or an SSH error code.
|
||||
*
|
||||
* @see ssh_scp_init()
|
||||
*/
|
||||
int ssh_scp_close(ssh_scp scp)
|
||||
{
|
||||
char buffer[128];
|
||||
int err;
|
||||
if(scp==NULL)
|
||||
@@ -169,7 +189,15 @@ int ssh_scp_close(ssh_scp scp){
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
void ssh_scp_free(ssh_scp scp){
|
||||
/**
|
||||
* @brief Free a scp context.
|
||||
*
|
||||
* @param[in] scp The context to free.
|
||||
*
|
||||
* @see ssh_scp_new()
|
||||
*/
|
||||
void ssh_scp_free(ssh_scp scp)
|
||||
{
|
||||
if(scp==NULL)
|
||||
return;
|
||||
if(scp->state != SSH_SCP_NEW)
|
||||
@@ -517,7 +545,7 @@ int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){
|
||||
* @see ssh_scp_request_get_warning()
|
||||
*/
|
||||
int ssh_scp_pull_request(ssh_scp scp){
|
||||
char buffer[4096] = {0};
|
||||
char buffer[MAX_BUF_SIZE] = {0};
|
||||
char *mode=NULL;
|
||||
char *p,*tmp;
|
||||
uint64_t size;
|
||||
@@ -614,7 +642,7 @@ int ssh_scp_pull_request(ssh_scp scp){
|
||||
* the message failed, or sending it in a bad state.
|
||||
*/
|
||||
int ssh_scp_deny_request(ssh_scp scp, const char *reason){
|
||||
char buffer[4096];
|
||||
char buffer[MAX_BUF_SIZE];
|
||||
int err;
|
||||
if(scp==NULL)
|
||||
return SSH_ERROR;
|
||||
|
||||
52
src/server.c
52
src/server.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2004-2005 by Aris Adamantiadis
|
||||
* Copyright (c) 2004-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
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/messages.h"
|
||||
#include "libssh/options.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
#define set_status(session, status) do {\
|
||||
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
|
||||
@@ -182,6 +183,11 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
rc = ssh_server_ecdh_init(session, packet);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
rc = ssh_server_curve25519_init(session, packet);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_kexdh_init");
|
||||
@@ -211,6 +217,7 @@ int ssh_get_key_params(ssh_session session, ssh_key *privkey){
|
||||
*privkey = session->srv.ecdsa_key;
|
||||
break;
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
*privkey = NULL;
|
||||
}
|
||||
|
||||
@@ -988,7 +995,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name,
|
||||
msg->session->kbdint = NULL;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
msg->session->kbdint->echo = malloc(num_prompts * sizeof(char));
|
||||
msg->session->kbdint->echo = malloc(num_prompts * sizeof(unsigned char));
|
||||
if (msg->session->kbdint->echo == NULL) {
|
||||
ssh_set_error_oom(msg->session);
|
||||
ssh_kbdint_free(msg->session->kbdint);
|
||||
@@ -1215,6 +1222,47 @@ int ssh_execute_message_callbacks(ssh_session session){
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_send_keepalive(ssh_session session)
|
||||
{
|
||||
struct ssh_string_struct *req;
|
||||
int rc;
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST);
|
||||
if (rc < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
req = ssh_string_from_char("keepalive@openssh.com");
|
||||
if (req == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = buffer_add_ssh_string(session->out_buffer, req);
|
||||
ssh_string_free(req);
|
||||
if (rc < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = buffer_add_u8(session->out_buffer, 1);
|
||||
if (rc < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (packet_send(session) == SSH_ERROR) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ssh_handle_packets(session, 0);
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Sent a keepalive");
|
||||
return SSH_OK;
|
||||
|
||||
err:
|
||||
ssh_set_error_oom(session);
|
||||
buffer_reinit(session->out_buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/* vim: set ts=4 sw=4 et cindent: */
|
||||
|
||||
127
src/session.c
127
src/session.c
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2005-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2005-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
|
||||
@@ -115,6 +115,17 @@ ssh_session ssh_new(void) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
id = strdup("%d/id_ecdsa");
|
||||
if (id == NULL) {
|
||||
goto err;
|
||||
}
|
||||
rc = ssh_list_append(session->opts.identity, id);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
id = strdup("%d/id_rsa");
|
||||
if (id == NULL) {
|
||||
goto err;
|
||||
@@ -215,7 +226,11 @@ void ssh_free(ssh_session session) {
|
||||
#endif /* _WIN32 */
|
||||
|
||||
ssh_key_free(session->srv.dsa_key);
|
||||
session->srv.dsa_key = NULL;
|
||||
ssh_key_free(session->srv.rsa_key);
|
||||
session->srv.rsa_key = NULL;
|
||||
ssh_key_free(session->srv.ecdsa_key);
|
||||
session->srv.ecdsa_key = NULL;
|
||||
|
||||
if (session->ssh_message_list) {
|
||||
ssh_message msg;
|
||||
@@ -244,16 +259,20 @@ void ssh_free(ssh_session session) {
|
||||
ssh_list_free(session->opts.identity);
|
||||
}
|
||||
|
||||
SAFE_FREE(session->auth_auto_state);
|
||||
SAFE_FREE(session->serverbanner);
|
||||
SAFE_FREE(session->clientbanner);
|
||||
SAFE_FREE(session->banner);
|
||||
|
||||
SAFE_FREE(session->opts.bindaddr);
|
||||
SAFE_FREE(session->opts.custombanner);
|
||||
SAFE_FREE(session->opts.username);
|
||||
SAFE_FREE(session->opts.host);
|
||||
SAFE_FREE(session->opts.sshdir);
|
||||
SAFE_FREE(session->opts.knownhosts);
|
||||
SAFE_FREE(session->opts.ProxyCommand);
|
||||
SAFE_FREE(session->opts.gss_server_identity);
|
||||
SAFE_FREE(session->opts.gss_client_identity);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (session->opts.wanted_methods[i]) {
|
||||
@@ -261,14 +280,32 @@ void ssh_free(ssh_session session) {
|
||||
}
|
||||
}
|
||||
|
||||
/* burn connection, it could hang sensitive datas */
|
||||
ZERO_STRUCTP(session);
|
||||
/* burn connection, it could contain sensitive data */
|
||||
BURN_BUFFER(session, sizeof(struct ssh_session_struct));
|
||||
SAFE_FREE(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the server banner
|
||||
* @brief get the client banner
|
||||
*
|
||||
* @param[in] session The SSH session
|
||||
*
|
||||
* @return Returns the client banner string or NULL.
|
||||
*/
|
||||
const char* ssh_get_clientbanner(ssh_session session) {
|
||||
if (session == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return session->clientbanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the server banner
|
||||
*
|
||||
* @param[in] session The SSH session
|
||||
*
|
||||
* @return Returns the server banner string or NULL.
|
||||
*/
|
||||
const char* ssh_get_serverbanner(ssh_session session) {
|
||||
if(!session) {
|
||||
@@ -277,6 +314,38 @@ const char* ssh_get_serverbanner(ssh_session session) {
|
||||
return session->serverbanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the name of the input for the given session.
|
||||
*
|
||||
* @param[in] session The SSH session.
|
||||
*
|
||||
* @return Returns cipher name or NULL.
|
||||
*/
|
||||
const char* ssh_get_cipher_in(ssh_session session) {
|
||||
if ((session != NULL) &&
|
||||
(session->current_crypto != NULL) &&
|
||||
(session->current_crypto->in_cipher != NULL)) {
|
||||
return session->current_crypto->in_cipher->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the name of the output cipher for the given session.
|
||||
*
|
||||
* @param[in] session The SSH session.
|
||||
*
|
||||
* @return Returns cipher name or NULL.
|
||||
*/
|
||||
const char* ssh_get_cipher_out(ssh_session session) {
|
||||
if ((session != NULL) &&
|
||||
(session->current_crypto != NULL) &&
|
||||
(session->current_crypto->out_cipher != NULL)) {
|
||||
return session->current_crypto->out_cipher->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnect impolitely from a remote host by closing the socket.
|
||||
*
|
||||
@@ -300,8 +369,6 @@ void ssh_silent_disconnect(ssh_session session) {
|
||||
* @param[in] session The ssh session to change.
|
||||
*
|
||||
* @param[in] blocking Zero for nonblocking mode.
|
||||
*
|
||||
* \bug nonblocking code is in development and won't work as expected
|
||||
*/
|
||||
void ssh_set_blocking(ssh_session session, int blocking) {
|
||||
if (session == NULL) {
|
||||
@@ -464,9 +531,7 @@ int ssh_handle_packets(ssh_session session, int timeout) {
|
||||
|
||||
spoll_in = ssh_socket_get_poll_handle_in(session->socket);
|
||||
spoll_out = ssh_socket_get_poll_handle_out(session->socket);
|
||||
if (session->server) {
|
||||
ssh_poll_add_events(spoll_in, POLLIN);
|
||||
}
|
||||
ssh_poll_add_events(spoll_in, POLLIN);
|
||||
ctx = ssh_poll_get_ctx(spoll_in);
|
||||
|
||||
if (!ctx) {
|
||||
@@ -539,7 +604,11 @@ int ssh_handle_packets_termination(ssh_session session,
|
||||
}
|
||||
}
|
||||
|
||||
ssh_timestamp_init(&ts);
|
||||
/* avoid unnecessary syscall for the SSH_TIMEOUT_NONBLOCKING case */
|
||||
if (timeout != SSH_TIMEOUT_NONBLOCKING) {
|
||||
ssh_timestamp_init(&ts);
|
||||
}
|
||||
|
||||
tm = timeout;
|
||||
while(!fct(user)) {
|
||||
ret = ssh_handle_packets(session, tm);
|
||||
@@ -577,7 +646,7 @@ int ssh_get_status(ssh_session session) {
|
||||
|
||||
socketstate = ssh_socket_get_status(session->socket);
|
||||
|
||||
if (session->closed) {
|
||||
if (session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
|
||||
r |= SSH_CLOSED;
|
||||
}
|
||||
if (socketstate & SSH_READ_PENDING) {
|
||||
@@ -586,7 +655,8 @@ int ssh_get_status(ssh_session session) {
|
||||
if (socketstate & SSH_WRITE_PENDING) {
|
||||
r |= SSH_WRITE_PENDING;
|
||||
}
|
||||
if ((session->closed && (socketstate & SSH_CLOSED_ERROR)) ||
|
||||
if ((session->session_state == SSH_SESSION_STATE_DISCONNECTED &&
|
||||
(socketstate & SSH_CLOSED_ERROR)) ||
|
||||
session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
r |= SSH_CLOSED_ERROR;
|
||||
}
|
||||
@@ -594,6 +664,25 @@ int ssh_get_status(ssh_session session) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get poll flags for an external mainloop
|
||||
*
|
||||
* @param session The ssh session to use.
|
||||
*
|
||||
* @returns A bitmask including SSH_READ_PENDING or SSH_WRITE_PENDING.
|
||||
* For SSH_READ_PENDING, your invocation of poll() should include
|
||||
* POLLIN. For SSH_WRITE_PENDING, your invocation of poll() should
|
||||
* include POLLOUT.
|
||||
*/
|
||||
int ssh_get_poll_flags(ssh_session session)
|
||||
{
|
||||
if (session == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ssh_socket_get_poll_flags (session->socket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the disconnect message from the server.
|
||||
*
|
||||
@@ -610,12 +699,9 @@ const char *ssh_get_disconnect_message(ssh_session session) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!session->closed) {
|
||||
if (session->session_state != SSH_SESSION_STATE_DISCONNECTED) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Connection not closed yet");
|
||||
} else if(session->closed_by_except) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Connection closed by socket error");
|
||||
} else if(!session->discon_msg) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Connection correctly closed but no disconnect message");
|
||||
@@ -650,8 +736,13 @@ void ssh_socket_exception_callback(int code, int errno_code, void *user){
|
||||
ssh_session session=(ssh_session)user;
|
||||
|
||||
SSH_LOG(SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code);
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
ssh_set_error(session,SSH_FATAL,"Socket error: %s",strerror(errno_code));
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
if (errno_code == 0 && code == SSH_SOCKET_EXCEPTION_EOF) {
|
||||
ssh_set_error(session, SSH_FATAL, "Socket error: disconnected");
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL, "Socket error: %s", strerror(errno_code));
|
||||
}
|
||||
|
||||
session->ssh_connection_callback(session);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2005-2008 by Aris Adamantiadis
|
||||
* Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
|
||||
* Copyright (c) 2008-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
|
||||
@@ -308,7 +308,7 @@ int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){
|
||||
}
|
||||
|
||||
sftp_packet sftp_packet_read(sftp_session sftp) {
|
||||
unsigned char buffer[4096];
|
||||
unsigned char buffer[MAX_BUF_SIZE];
|
||||
sftp_packet packet = NULL;
|
||||
uint32_t size;
|
||||
int r;
|
||||
|
||||
59
src/socket.c
59
src/socket.c
@@ -218,7 +218,7 @@ void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){
|
||||
*/
|
||||
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int revents, void *v_s){
|
||||
ssh_socket s=(ssh_socket )v_s;
|
||||
char buffer[4096];
|
||||
char buffer[MAX_BUF_SIZE];
|
||||
int r;
|
||||
int err=0;
|
||||
socklen_t errlen=sizeof(err);
|
||||
@@ -245,7 +245,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
|
||||
/* force a read to get an explanation */
|
||||
revents |= POLLIN;
|
||||
}
|
||||
if(revents & POLLIN){
|
||||
if((revents & POLLIN) && s->state == SSH_SOCKET_CONNECTED){
|
||||
s->read_wontblock=1;
|
||||
r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
|
||||
if(r<0){
|
||||
@@ -291,7 +291,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
|
||||
buffer_get_rest_len(s->in_buffer),
|
||||
s->callbacks->userdata);
|
||||
buffer_pass_bytes(s->in_buffer,r);
|
||||
} while (r > 0);
|
||||
} while ((r > 0) && (s->state == SSH_SOCKET_CONNECTED));
|
||||
/* p may have been freed, so don't use it
|
||||
* anymore in this function */
|
||||
p = NULL;
|
||||
@@ -307,11 +307,13 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
|
||||
if(s->state == SSH_SOCKET_CONNECTING){
|
||||
SSH_LOG(SSH_LOG_PACKET,"Received POLLOUT in connecting state");
|
||||
s->state = SSH_SOCKET_CONNECTED;
|
||||
ssh_poll_set_events(p,POLLOUT | POLLIN);
|
||||
r = ssh_socket_set_blocking(ssh_socket_get_fd_in(s));
|
||||
if (r < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (p != NULL) {
|
||||
ssh_poll_set_events(p,POLLOUT | POLLIN);
|
||||
}
|
||||
r = ssh_socket_set_blocking(ssh_socket_get_fd_in(s));
|
||||
if (r < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(s->callbacks && s->callbacks->connected)
|
||||
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
|
||||
return 0;
|
||||
@@ -438,6 +440,8 @@ void ssh_socket_close(ssh_socket s){
|
||||
ssh_poll_free(s->poll_out);
|
||||
s->poll_out=NULL;
|
||||
}
|
||||
|
||||
s->state = SSH_SOCKET_CLOSED;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,9 +453,19 @@ void ssh_socket_close(ssh_socket s){
|
||||
* file descriptors
|
||||
*/
|
||||
void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
|
||||
s->fd_in = s->fd_out = fd;
|
||||
if(s->poll_in)
|
||||
ssh_poll_set_fd(s->poll_in,fd);
|
||||
s->fd_in = s->fd_out = fd;
|
||||
|
||||
if (s->poll_in) {
|
||||
ssh_poll_set_fd(s->poll_in,fd);
|
||||
} else {
|
||||
s->state = SSH_SOCKET_CONNECTING;
|
||||
|
||||
/* POLLOUT is the event to wait for in a nonblocking connect */
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s), POLLOUT);
|
||||
#ifdef _WIN32
|
||||
ssh_poll_add_events(ssh_socket_get_poll_handle_in(s), POLLWRNORM);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -695,11 +709,11 @@ int ssh_socket_buffered_write_bytes(ssh_socket s){
|
||||
int ssh_socket_get_status(ssh_socket s) {
|
||||
int r = 0;
|
||||
|
||||
if (s->read_wontblock) {
|
||||
r |= SSH_READ_PENDING;
|
||||
if (buffer_get_len(s->in_buffer) > 0) {
|
||||
r |= SSH_READ_PENDING;
|
||||
}
|
||||
|
||||
if (s->write_wontblock) {
|
||||
if (buffer_get_len(s->out_buffer) > 0) {
|
||||
r |= SSH_WRITE_PENDING;
|
||||
}
|
||||
|
||||
@@ -710,6 +724,17 @@ int ssh_socket_get_status(ssh_socket s) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int ssh_socket_get_poll_flags(ssh_socket s) {
|
||||
int r = 0;
|
||||
if (s->poll_in != NULL && (ssh_poll_get_events (s->poll_in) & POLLIN) > 0) {
|
||||
r |= SSH_READ_PENDING;
|
||||
}
|
||||
if (s->poll_out != NULL && (ssh_poll_get_events (s->poll_out) & POLLOUT) > 0) {
|
||||
r |= SSH_WRITE_PENDING;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int ssh_socket_set_nonblocking(socket_t fd) {
|
||||
u_long nonblocking = 1;
|
||||
@@ -759,12 +784,6 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin
|
||||
if(fd == SSH_INVALID_SOCKET)
|
||||
return SSH_ERROR;
|
||||
ssh_socket_set_fd(s,fd);
|
||||
s->state=SSH_SOCKET_CONNECTING;
|
||||
/* POLLOUT is the event to wait for in a nonblocking connect */
|
||||
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLOUT);
|
||||
#ifdef _WIN32
|
||||
ssh_poll_add_events(ssh_socket_get_poll_handle_in(s),POLLWRNORM);
|
||||
#endif
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -235,10 +235,11 @@ struct ssh_string_struct *ssh_string_copy(struct ssh_string_struct *s) {
|
||||
* @param[in] s The string to burn.
|
||||
*/
|
||||
void ssh_string_burn(struct ssh_string_struct *s) {
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
memset(s->data, 'X', ssh_string_len(s));
|
||||
if (s == NULL || s->size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
BURN_BUFFER(s->data, ssh_string_len(s));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,8 +59,28 @@ struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void) {
|
||||
static struct ssh_threads_callbacks_struct *user_callbacks =&ssh_threads_noop;
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#if (GCRYPT_VERSION_NUMBER >= 0x010600)
|
||||
/* libgcrypt >= 1.6 does not support custom callbacks */
|
||||
GCRY_THREAD_OPTION_PTHREAD_IMPL;
|
||||
|
||||
/* Libgcrypt specific way of handling thread callbacks */
|
||||
static int libgcrypt_thread_init(void){
|
||||
if(user_callbacks == NULL)
|
||||
return SSH_ERROR;
|
||||
if(user_callbacks == &ssh_threads_noop)
|
||||
return SSH_OK;
|
||||
if (strcmp(user_callbacks->type, "threads_pthread") == 0){
|
||||
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
||||
return SSH_OK;
|
||||
} else {
|
||||
/* not supported */
|
||||
SSH_LOG(SSH_LOG_WARN, "Custom thread handlers not supported with libgcrypt >=1.6, using pthreads");
|
||||
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
|
||||
return SSH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
/* Libgcrypt < 1.6 specific way of handling thread callbacks */
|
||||
|
||||
static struct gcry_thread_cbs gcrypt_threads_callbacks;
|
||||
|
||||
@@ -79,7 +99,8 @@ static int libgcrypt_thread_init(void){
|
||||
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks);
|
||||
return SSH_OK;
|
||||
}
|
||||
#else
|
||||
#endif /* GCRYPT_VERSION_NUMBER */
|
||||
#else /* HAVE_LIBGCRYPT */
|
||||
|
||||
/* Libcrypto specific stuff */
|
||||
|
||||
|
||||
@@ -53,73 +53,75 @@ include_directories(
|
||||
${LIBSSH_THREADS_PRIVATE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_library(${LIBSSH_THREADS_SHARED_LIBRARY} SHARED ${libssh_threads_SRCS})
|
||||
if (libssh_threads_SRCS)
|
||||
add_library(${LIBSSH_THREADS_SHARED_LIBRARY} SHARED ${libssh_threads_SRCS})
|
||||
|
||||
target_link_libraries(${LIBSSH_THREADS_SHARED_LIBRARY} ${LIBSSH_THREADS_LINK_LIBRARIES})
|
||||
target_link_libraries(${LIBSSH_THREADS_SHARED_LIBRARY} ${LIBSSH_THREADS_LINK_LIBRARIES})
|
||||
|
||||
set_target_properties(
|
||||
${LIBSSH_THREADS_SHARED_LIBRARY}
|
||||
PROPERTIES
|
||||
VERSION
|
||||
${LIBRARY_VERSION}
|
||||
SOVERSION
|
||||
${LIBRARY_SOVERSION}
|
||||
OUTPUT_NAME
|
||||
ssh_threads
|
||||
DEFINE_SYMBOL
|
||||
LIBSSH_EXPORTS
|
||||
)
|
||||
|
||||
if (WITH_VISIBILITY_HIDDEN)
|
||||
set_target_properties(${LIBSSH_THREADS_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
|
||||
endif (WITH_VISIBILITY_HIDDEN)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
${LIBSSH_THREADS_SHARED_LIBRARY}
|
||||
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
COMPONENT libraries
|
||||
)
|
||||
|
||||
if (WITH_STATIC_LIB)
|
||||
add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS})
|
||||
|
||||
if (MSVC)
|
||||
set(OUTPUT_SUFFIX static)
|
||||
else (MSVC)
|
||||
set(OUTPUT_SUFFIX )
|
||||
endif (MSVC)
|
||||
|
||||
set_target_properties(
|
||||
${LIBSSH_THREADS_STATIC_LIBRARY}
|
||||
PROPERTIES
|
||||
VERSION
|
||||
${LIBRARY_VERSION}
|
||||
SOVERSION
|
||||
${LIBRARY_SOVERSION}
|
||||
OUTPUT_NAME
|
||||
ssh_threads
|
||||
ARCHIVE_OUTPUT_DIRECTORY
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
set_target_properties(
|
||||
${LIBSSH_THREADS_STATIC_LIBRARY}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS
|
||||
"-DLIBSSH_STATIC"
|
||||
)
|
||||
endif (WIN32)
|
||||
${LIBSSH_THREADS_SHARED_LIBRARY}
|
||||
PROPERTIES
|
||||
VERSION
|
||||
${LIBRARY_VERSION}
|
||||
SOVERSION
|
||||
${LIBRARY_SOVERSION}
|
||||
OUTPUT_NAME
|
||||
ssh_threads
|
||||
DEFINE_SYMBOL
|
||||
LIBSSH_EXPORTS
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
${LIBSSH_THREADS_STATIC_LIBRARY}
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
|
||||
COMPONENT
|
||||
libraries
|
||||
)
|
||||
endif (WITH_STATIC_LIB)
|
||||
if (WITH_VISIBILITY_HIDDEN)
|
||||
set_target_properties(${LIBSSH_THREADS_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
|
||||
endif (WITH_VISIBILITY_HIDDEN)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
${LIBSSH_THREADS_SHARED_LIBRARY}
|
||||
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
COMPONENT libraries
|
||||
)
|
||||
|
||||
if (WITH_STATIC_LIB)
|
||||
add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS})
|
||||
|
||||
if (MSVC)
|
||||
set(OUTPUT_SUFFIX static)
|
||||
else (MSVC)
|
||||
set(OUTPUT_SUFFIX )
|
||||
endif (MSVC)
|
||||
|
||||
set_target_properties(
|
||||
${LIBSSH_THREADS_STATIC_LIBRARY}
|
||||
PROPERTIES
|
||||
VERSION
|
||||
${LIBRARY_VERSION}
|
||||
SOVERSION
|
||||
${LIBRARY_SOVERSION}
|
||||
OUTPUT_NAME
|
||||
ssh_threads
|
||||
ARCHIVE_OUTPUT_DIRECTORY
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
set_target_properties(
|
||||
${LIBSSH_THREADS_STATIC_LIBRARY}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS
|
||||
"-DLIBSSH_STATIC"
|
||||
)
|
||||
endif (WIN32)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
${LIBSSH_THREADS_STATIC_LIBRARY}
|
||||
DESTINATION
|
||||
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
|
||||
COMPONENT
|
||||
libraries
|
||||
)
|
||||
endif (WITH_STATIC_LIB)
|
||||
endif (libssh_threads_SRCS)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003 by Aris Adamantiadis
|
||||
* Copyright (c) 2003-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
|
||||
@@ -130,10 +130,13 @@ void crypto_free(struct ssh_crypto_struct *crypto){
|
||||
(deflateEnd(crypto->compress_out_ctx) != 0)) {
|
||||
inflateEnd(crypto->compress_out_ctx);
|
||||
}
|
||||
SAFE_FREE(crypto->compress_out_ctx);
|
||||
|
||||
if (crypto->compress_in_ctx &&
|
||||
(deflateEnd(crypto->compress_in_ctx) != 0)) {
|
||||
inflateEnd(crypto->compress_in_ctx);
|
||||
}
|
||||
SAFE_FREE(crypto->compress_in_ctx);
|
||||
#endif /* WITH_ZLIB */
|
||||
if(crypto->encryptIV)
|
||||
SAFE_FREE(crypto->encryptIV);
|
||||
@@ -158,7 +161,7 @@ void crypto_free(struct ssh_crypto_struct *crypto){
|
||||
SAFE_FREE(crypto->kex_methods[i]);
|
||||
}
|
||||
|
||||
memset(crypto,0,sizeof(*crypto));
|
||||
BURN_BUFFER(crypto, sizeof(struct ssh_crypto_struct));
|
||||
|
||||
SAFE_FREE(crypto);
|
||||
}
|
||||
@@ -317,8 +320,13 @@ int crypt_set_algorithms_server(ssh_session session){
|
||||
session->next_crypto->do_compress_in=1;
|
||||
}
|
||||
if(strcmp(method,"zlib@openssh.com") == 0){
|
||||
ssh_set_error(session,SSH_FATAL,"zlib@openssh.com not supported");
|
||||
return SSH_ERROR;
|
||||
SSH_LOG(SSH_LOG_PACKET,"enabling C->S delayed compression");
|
||||
|
||||
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) {
|
||||
session->next_crypto->do_compress_in = 1;
|
||||
} else {
|
||||
session->next_crypto->delayed_compress_in = 1;
|
||||
}
|
||||
}
|
||||
|
||||
method = session->next_crypto->kex_methods[SSH_COMP_S_C];
|
||||
@@ -327,8 +335,13 @@ int crypt_set_algorithms_server(ssh_session session){
|
||||
session->next_crypto->do_compress_out=1;
|
||||
}
|
||||
if(strcmp(method,"zlib@openssh.com") == 0){
|
||||
ssh_set_error(session,SSH_FATAL,"zlib@openssh.com not supported");
|
||||
return SSH_ERROR;
|
||||
SSH_LOG(SSH_LOG_PACKET,"enabling S->C delayed compression\n");
|
||||
|
||||
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) {
|
||||
session->next_crypto->do_compress_out = 1;
|
||||
} else {
|
||||
session->next_crypto->delayed_compress_out = 1;
|
||||
}
|
||||
}
|
||||
|
||||
method = session->next_crypto->kex_methods[SSH_HOSTKEYS];
|
||||
|
||||
@@ -6,7 +6,10 @@ add_cmocka_test(torture_connect torture_connect.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_knownhosts torture_knownhosts.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_proxycommand torture_proxycommand.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_session torture_session.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_forward torture_forward.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_request_env torture_request_env.c ${TORTURE_LIBRARY})
|
||||
if (WITH_SFTP)
|
||||
add_cmocka_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY})
|
||||
add_cmocka_test(torture_sftp_read torture_sftp_read.c ${TORTURE_LIBRARY})
|
||||
endif (WITH_SFTP)
|
||||
|
||||
@@ -64,9 +64,10 @@ static void torture_auth_autopubkey(void **state) {
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
|
||||
rc = ssh_userauth_autopubkey(session, NULL);
|
||||
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
||||
assert_true(rc == SSH_AUTH_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -87,16 +88,21 @@ static void torture_auth_autopubkey_nonblocking(void **state) {
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_userauth_none(session,NULL);
|
||||
ssh_set_blocking(session,0);
|
||||
do {
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
|
||||
/* This request should return a SSH_REQUEST_DENIED error */
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
|
||||
ssh_set_blocking(session, 0);
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
|
||||
do {
|
||||
rc = ssh_userauth_autopubkey(session, NULL);
|
||||
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
assert_true(rc == SSH_AUTH_SUCCESS);
|
||||
}
|
||||
@@ -130,7 +136,8 @@ static void torture_auth_kbdint(void **state) {
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_INTERACTIVE);
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_INTERACTIVE);
|
||||
|
||||
rc = ssh_userauth_kbdint(session, NULL, NULL);
|
||||
assert_true(rc == SSH_AUTH_INFO);
|
||||
@@ -172,13 +179,18 @@ static void torture_auth_kbdint_nonblocking(void **state) {
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_userauth_none(session,NULL);
|
||||
ssh_set_blocking(session,0);
|
||||
do {
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
|
||||
/* This request should return a SSH_REQUEST_DENIED error */
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_INTERACTIVE);
|
||||
ssh_set_blocking(session,0);
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_INTERACTIVE);
|
||||
|
||||
do {
|
||||
rc = ssh_userauth_kbdint(session, NULL, NULL);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
@@ -231,7 +243,8 @@ static void torture_auth_password(void **state) {
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PASSWORD);
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_PASSWORD);
|
||||
|
||||
rc = ssh_userauth_password(session, NULL, password);
|
||||
assert_true(rc == SSH_AUTH_SUCCESS);
|
||||
@@ -260,17 +273,19 @@ static void torture_auth_password_nonblocking(void **state) {
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
ssh_set_blocking(session,0);
|
||||
|
||||
ssh_set_blocking(session,0);
|
||||
do {
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
} while (rc==SSH_AUTH_AGAIN);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
|
||||
/* This request should return a SSH_REQUEST_DENIED error */
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PASSWORD);
|
||||
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_PASSWORD);
|
||||
|
||||
do {
|
||||
rc = ssh_userauth_password(session, NULL, password);
|
||||
@@ -304,7 +319,8 @@ static void torture_auth_agent(void **state) {
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
|
||||
rc = ssh_userauth_agent(session, NULL);
|
||||
assert_true(rc == SSH_AUTH_SUCCESS);
|
||||
@@ -335,14 +351,74 @@ static void torture_auth_agent_nonblocking(void **state) {
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
ssh_set_blocking(session, 0);
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
|
||||
ssh_set_blocking(session,0);
|
||||
|
||||
do {
|
||||
rc = ssh_userauth_agent(session, NULL);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
assert_true(rc == SSH_AUTH_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
static void torture_auth_none(void **state) {
|
||||
ssh_session session = *state;
|
||||
char *user = getenv("TORTURE_USER");
|
||||
int rc;
|
||||
|
||||
if (user == NULL) {
|
||||
print_message("*** Please set the environment variable TORTURE_USER"
|
||||
" to enable this test!!\n");
|
||||
return;
|
||||
}
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_USER, user);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_userauth_none(session,NULL);
|
||||
|
||||
assert_true(rc == SSH_AUTH_DENIED);
|
||||
/* This request should return a SSH_REQUEST_DENIED error */
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
}
|
||||
|
||||
static void torture_auth_none_nonblocking(void **state) {
|
||||
ssh_session session = *state;
|
||||
char *user = getenv("TORTURE_USER");
|
||||
int rc;
|
||||
|
||||
if (user == NULL) {
|
||||
print_message("*** Please set the environment variable TORTURE_USER"
|
||||
" to enable this test!!\n");
|
||||
return;
|
||||
}
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_USER, user);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
/* This request should return a SSH_REQUEST_DENIED error */
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
|
||||
ssh_set_blocking(session,0);
|
||||
|
||||
do {
|
||||
rc = ssh_userauth_none(session,NULL);
|
||||
} while (rc == SSH_AUTH_AGAIN);
|
||||
assert_true(rc == SSH_AUTH_DENIED);
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
const UnitTest tests[] = {
|
||||
@@ -354,6 +430,8 @@ int torture_run_tests(void) {
|
||||
unit_test_setup_teardown(torture_auth_autopubkey_nonblocking, setup, teardown),
|
||||
unit_test_setup_teardown(torture_auth_agent, setup, teardown),
|
||||
unit_test_setup_teardown(torture_auth_agent_nonblocking, setup, teardown),
|
||||
unit_test_setup_teardown(torture_auth_none, setup, teardown),
|
||||
unit_test_setup_teardown(torture_auth_none_nonblocking, setup, teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "torture.h"
|
||||
#include <libssh/libssh.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define HOST "localhost"
|
||||
/* Should work until Apnic decides to assign it :) */
|
||||
@@ -54,12 +55,11 @@ static void torture_connect_nonblocking(void **state) {
|
||||
ssh_set_blocking(session,0);
|
||||
|
||||
do {
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc != SSH_ERROR);
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc != SSH_ERROR);
|
||||
} while(rc == SSH_AGAIN);
|
||||
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
assert_true(rc == SSH_OK);
|
||||
}
|
||||
|
||||
static void torture_connect_timeout(void **state) {
|
||||
@@ -84,9 +84,9 @@ static void torture_connect_timeout(void **state) {
|
||||
sec = after.tv_sec - before.tv_sec;
|
||||
usec = after.tv_usec - before.tv_usec;
|
||||
/* Borrow a second for the missing usecs, but don't bother calculating */
|
||||
if(usec < 0)
|
||||
if (usec < 0)
|
||||
sec--;
|
||||
assert_in_range(sec,1,3);
|
||||
assert_in_range(sec, 1, 3);
|
||||
}
|
||||
|
||||
static void torture_connect_double(void **state) {
|
||||
@@ -102,10 +102,9 @@ static void torture_connect_double(void **state) {
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
}
|
||||
|
||||
static void torture_connect_failure(void **state){
|
||||
static void torture_connect_failure(void **state) {
|
||||
/*
|
||||
* The intent of this test is to check that a fresh
|
||||
* ssh_new/ssh_disconnect/ssh_free sequence doesn't crash/leak
|
||||
@@ -114,6 +113,30 @@ static void torture_connect_failure(void **state){
|
||||
ssh_session session = *state;
|
||||
ssh_disconnect(session);
|
||||
}
|
||||
|
||||
static void torture_connect_socket(void **state) {
|
||||
ssh_session session = *state;
|
||||
|
||||
int rc;
|
||||
int sock_fd = 0;
|
||||
struct sockaddr_in server_addr;
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
assert_true(sock_fd > 0);
|
||||
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(22);
|
||||
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
rc = connect(sock_fd, &server_addr, sizeof(server_addr));
|
||||
assert_true(rc == 0);
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_FD, &sock_fd);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
const UnitTest tests[] = {
|
||||
@@ -121,6 +144,7 @@ int torture_run_tests(void) {
|
||||
unit_test_setup_teardown(torture_connect_double, setup, teardown),
|
||||
unit_test_setup_teardown(torture_connect_failure, setup, teardown),
|
||||
unit_test_setup_teardown(torture_connect_timeout, setup, teardown),
|
||||
unit_test_setup_teardown(torture_connect_socket, setup, teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
94
tests/client/torture_forward.c
Normal file
94
tests/client/torture_forward.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013 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.
|
||||
*/
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#include "torture.h"
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
static void setup(void **state)
|
||||
{
|
||||
ssh_session session;
|
||||
const char *host;
|
||||
const char *user;
|
||||
const char *password;
|
||||
|
||||
host = getenv("TORTURE_HOST");
|
||||
if (host == NULL) {
|
||||
host = "localhost";
|
||||
}
|
||||
|
||||
user = getenv("TORTURE_USER");
|
||||
password = getenv("TORTURE_PASSWORD");
|
||||
|
||||
session = torture_ssh_session(host, user, password);
|
||||
|
||||
assert_non_null(session);
|
||||
*state = session;
|
||||
}
|
||||
|
||||
static void teardown(void **state)
|
||||
{
|
||||
ssh_session session = (ssh_session) *state;
|
||||
|
||||
assert_non_null(session);
|
||||
|
||||
if (ssh_is_connected(session)) {
|
||||
ssh_disconnect(session);
|
||||
}
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void torture_ssh_forward(void **state)
|
||||
{
|
||||
ssh_session session = (ssh_session) *state;
|
||||
#if 0
|
||||
ssh_channel c;
|
||||
#endif
|
||||
int bound_port;
|
||||
int rc;
|
||||
|
||||
rc = ssh_forward_listen(session, "127.0.0.1", 8080, &bound_port);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
#if 0
|
||||
c = ssh_forward_accept(session, 60000);
|
||||
assert_non_null(c);
|
||||
|
||||
ssh_channel_send_eof(c);
|
||||
ssh_channel_close(c);
|
||||
#endif
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_ssh_forward, setup, teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
rc = run_tests(tests);
|
||||
|
||||
ssh_finalize();
|
||||
return rc;
|
||||
}
|
||||
@@ -23,8 +23,26 @@
|
||||
|
||||
#include "torture.h"
|
||||
#include "session.c"
|
||||
#include "known_hosts.c"
|
||||
|
||||
#define KNOWNHOSTFILES "libssh_torture_knownhosts"
|
||||
#define BADRSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQChm5" \
|
||||
"a6Av65O8cKtx5YXOnui3wJnYE6A6J/I4kZSAibbn14Jcl+34VJQwv96f25AxNmo" \
|
||||
"NwoiZV93IzdypQmiuieh6s6wB9WhYjU9K/6CkIpNhpCxswA90b3ePjS7LnR9B9J" \
|
||||
"slPSbG1H0KC1c5lb7G3utXteXtM+4YvCvpN5VdC4CpghT+p0cwN2Na8Md5vRItz" \
|
||||
"YgIytryNn7LLiwYfoSxvWigFrTTZsrVtCOYyNgklmffpGdzuC43wdANvTewfI9G" \
|
||||
"o71r8EXmEc228CrYPmb8Scv3mpXFK/BosohSGkPlEHu9lf3YjnknBicDaVtJOYp" \
|
||||
"wnXJPjZo2EhG79HxDRpjJHH"
|
||||
#define BADDSA "AAAAB3NzaC1kc3MAAACBAITDKqGQ5aC5wHySG6ZdL1+BVBY2nLP5vzw3i3pvZfP" \
|
||||
"yNUS0UCwrt5pajsMvDRGXXebTJhWVonDnv8tpSgiuIBXMZrma8CU1KCFGRzwb/n8" \
|
||||
"cc5tJmIphlOUTrObjBmsRz7u1eZmoaddXC9ask6BNnt0DmhzYi2esL3mbardy8IN" \
|
||||
"zAAAAFQDlPFCm410pgQQPb3X5FWjyVEIl+QAAAIAp0vqfir8K8p+zP4dzFG7ppnt" \
|
||||
"DjaXf3ge6URF7f5xPDo6CClGo2JQ2REF8NxM7K9cLgR9Ifx2ahO48UMgrXEl/BOp" \
|
||||
"IQHpeBqUz26a49O5J0WEW16YSUHxWwMxWVe/SRmyKdTUZJ6fcepH88JNqm3XudNn" \
|
||||
"s78grM+yx9mcXnK2AsAAAAIBxpF8ZQIlGrSgwCmCfwjP156bC3Ya6LYf9ZpLJ0dX" \
|
||||
"EcxqLVllrNEvd2EGD9p16BYO2yaalYon8im59PtOcul2ay5XQ6rVDQ2T0pgNUpsI" \
|
||||
"h0dSi8VJXI1wes5HTyLsv9VBmU1uCXUUvufoQKfF/OcSH0ufcCpnd62g1/adZcy2" \
|
||||
"WJg=="
|
||||
|
||||
static void setup(void **state) {
|
||||
int verbosity=torture_libssh_verbosity();
|
||||
@@ -93,10 +111,184 @@ static void torture_knownhosts_port(void **state) {
|
||||
assert_true(rc == SSH_SERVER_KNOWN_OK);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_fail(void **state) {
|
||||
ssh_session session = *state;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_KNOWN_CHANGED);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_other(void **state) {
|
||||
ssh_session session = *state;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-dss");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_FOUND_OTHER);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_other_auto(void **state) {
|
||||
ssh_session session = *state;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-dss");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_NOT_KNOWN);
|
||||
|
||||
rc = ssh_write_knownhost(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
|
||||
/* connect again and check host key */
|
||||
*state = session = ssh_new();
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
/* ssh-rsa is the default but libssh should try ssh-dss instead */
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_KNOWN_OK);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_conflict(void **state) {
|
||||
ssh_session session = *state;
|
||||
FILE *file;
|
||||
int rc;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, "localhost ssh-dss %s\n", BADDSA);
|
||||
fclose(file);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_KNOWN_CHANGED);
|
||||
|
||||
rc = ssh_write_knownhost(session);
|
||||
assert_true(rc==SSH_OK);
|
||||
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
|
||||
/* connect again and check host key */
|
||||
*state = session = ssh_new();
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_is_server_known(session);
|
||||
assert_true(rc == SSH_SERVER_KNOWN_OK);
|
||||
}
|
||||
|
||||
static void torture_knownhosts_precheck(void **state) {
|
||||
ssh_session session = *state;
|
||||
FILE *file;
|
||||
int rc;
|
||||
char **kex;
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
|
||||
assert_true(rc == SSH_OK);
|
||||
|
||||
file = fopen(KNOWNHOSTFILES, "w");
|
||||
assert_true(file != NULL);
|
||||
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
|
||||
fprintf(file, "localhost ssh-dss %s\n", BADDSA);
|
||||
fclose(file);
|
||||
|
||||
kex = ssh_knownhosts_algorithms(session);
|
||||
assert_true(kex != NULL);
|
||||
assert_string_equal(kex[0],"ssh-rsa");
|
||||
assert_string_equal(kex[1],"ssh-dss");
|
||||
assert_true(kex[2]==NULL);
|
||||
free(kex[1]);
|
||||
free(kex[0]);
|
||||
free(kex);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_knownhosts_port, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_fail, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_other, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_other_auto, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_conflict, setup, teardown),
|
||||
unit_test_setup_teardown(torture_knownhosts_precheck, setup, teardown)
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
114
tests/client/torture_request_env.c
Normal file
114
tests/client/torture_request_env.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013 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.
|
||||
*/
|
||||
|
||||
#define LIBSSH_STATIC
|
||||
|
||||
#include "torture.h"
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
static void setup(void **state)
|
||||
{
|
||||
ssh_session session;
|
||||
const char *host;
|
||||
const char *user;
|
||||
const char *password;
|
||||
|
||||
host = getenv("TORTURE_HOST");
|
||||
if (host == NULL) {
|
||||
host = "localhost";
|
||||
}
|
||||
|
||||
user = getenv("TORTURE_USER");
|
||||
password = getenv("TORTURE_PASSWORD");
|
||||
|
||||
session = torture_ssh_session(host, user, password);
|
||||
|
||||
assert_false(session == NULL);
|
||||
*state = session;
|
||||
}
|
||||
|
||||
static void teardown(void **state)
|
||||
{
|
||||
ssh_session session = *state;
|
||||
|
||||
assert_false(session == NULL);
|
||||
|
||||
if (ssh_is_connected(session)) {
|
||||
ssh_disconnect(session);
|
||||
}
|
||||
ssh_free(session);
|
||||
}
|
||||
|
||||
static void torture_request_env(void **state)
|
||||
{
|
||||
ssh_session session = *state;
|
||||
ssh_channel c;
|
||||
char buffer[4096] = {0};
|
||||
int nbytes;
|
||||
int rc;
|
||||
int lang_found = 0;
|
||||
|
||||
c = ssh_channel_new(session);
|
||||
assert_non_null(c);
|
||||
|
||||
rc = ssh_channel_open_session(c);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_channel_request_env(c, "LC_LIBSSH", "LIBSSH");
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_channel_request_exec(c, "bash -c export");
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
nbytes = ssh_channel_read(c, buffer, sizeof(buffer) - 1, 0);
|
||||
while (nbytes > 0) {
|
||||
#if 0
|
||||
rc = fwrite(buffer, 1, nbytes, stdout);
|
||||
assert_int_equal(rc, nbytes);
|
||||
#endif
|
||||
buffer[nbytes]='\0';
|
||||
if (strstr(buffer, "LC_LIBSSH=\"LIBSSH\"")) {
|
||||
lang_found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
nbytes = ssh_channel_read(c, buffer, sizeof(buffer), 0);
|
||||
}
|
||||
assert_int_equal(lang_found, 1);
|
||||
|
||||
ssh_channel_close(c);
|
||||
}
|
||||
|
||||
int torture_run_tests(void) {
|
||||
int rc;
|
||||
|
||||
const UnitTest tests[] = {
|
||||
unit_test_setup_teardown(torture_request_env, setup, teardown),
|
||||
};
|
||||
|
||||
ssh_init();
|
||||
|
||||
rc = run_tests(tests);
|
||||
|
||||
ssh_finalize();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -68,9 +68,10 @@ static void torture_channel_read_error(void **state) {
|
||||
if (rc == SSH_ERROR) {
|
||||
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
|
||||
}
|
||||
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
rc = ssh_userauth_list(session, NULL);
|
||||
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
|
||||
|
||||
rc = ssh_userauth_autopubkey(session, NULL);
|
||||
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
||||
assert_true(rc == SSH_AUTH_SUCCESS);
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user