diff --git a/libssh/AUTHORS b/libssh/AUTHORS index fd753860..51b3e46f 100644 --- a/libssh/AUTHORS +++ b/libssh/AUTHORS @@ -1,7 +1,7 @@ Author(s): Aris Adamantiadis (project initiator) -Andreas Schneider (developer) +Andreas Schneider (developer) Nick Zitzmann (mostly client SFTP stuff) diff --git a/libssh/CMakeLists.txt b/libssh/CMakeLists.txt index 5998bc50..48559f37 100644 --- a/libssh/CMakeLists.txt +++ b/libssh/CMakeLists.txt @@ -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 "7") +set(APPLICATION_VERSION_PATCH "0") set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}") @@ -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) @@ -101,18 +97,22 @@ 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) diff --git a/libssh/CPackConfig.cmake b/libssh/CPackConfig.cmake index 2e4c9fee..2c4c3b5b 100644 --- a/libssh/CPackConfig.cmake +++ b/libssh/CPackConfig.cmake @@ -19,7 +19,7 @@ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSIO ### 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) diff --git a/libssh/ConfigureChecks.cmake b/libssh/ConfigureChecks.cmake index 472fe79e..5701bc39 100644 --- a/libssh/ConfigureChecks.cmake +++ b/libssh/ConfigureChecks.cmake @@ -48,9 +48,11 @@ endif(CMAKE_COMPILER_IS_GNUCC AND NOT MINGW AND NOT OS2) # HEADER FILES check_include_file(argp.h HAVE_ARGP_H) check_include_file(pty.h HAVE_PTY_H) +check_include_file(utmp.h HAVE_UTMP_H) check_include_file(termios.h HAVE_TERMIOS_H) check_include_file(unistd.h HAVE_UNISTD_H) check_include_file(util.h HAVE_UTIL_H) +check_include_file(libutil.h HAVE_LIBUTIL_H) if (WIN32) check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H) @@ -169,11 +171,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(" diff --git a/libssh/build/.gitkeep b/libssh/build/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/libssh/cmake/Modules/AddCMockaTest.cmake b/libssh/cmake/Modules/AddCMockaTest.cmake index b2d1ca8a..19eff622 100644 --- a/libssh/cmake/Modules/AddCMockaTest.cmake +++ b/libssh/cmake/Modules/AddCMockaTest.cmake @@ -1,7 +1,7 @@ # - ADD_CHECK_TEST(test_name test_source linklib1 ... linklibN) # Copyright (c) 2007 Daniel Gollub -# Copyright (c) 2007-2010 Andreas Schneider +# Copyright (c) 2007-2010 Andreas Schneider # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. diff --git a/libssh/cmake/Modules/DefineCMakeDefaults.cmake b/libssh/cmake/Modules/DefineCMakeDefaults.cmake index 72893c3c..22eda6fa 100644 --- a/libssh/cmake/Modules/DefineCMakeDefaults.cmake +++ b/libssh/cmake/Modules/DefineCMakeDefaults.cmake @@ -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) diff --git a/libssh/cmake/Modules/DefineCompilerFlags.cmake b/libssh/cmake/Modules/DefineCompilerFlags.cmake index 0ab8802c..bfbc38fc 100644 --- a/libssh/cmake/Modules/DefineCompilerFlags.cmake +++ b/libssh/cmake/Modules/DefineCompilerFlags.cmake @@ -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) + diff --git a/libssh/cmake/Modules/FindArgp.cmake b/libssh/cmake/Modules/FindArgp.cmake index aa228557..8dedc855 100644 --- a/libssh/cmake/Modules/FindArgp.cmake +++ b/libssh/cmake/Modules/FindArgp.cmake @@ -6,7 +6,7 @@ # ARGP_LIBRARIES - Link these to use Argp # ARGP_DEFINITIONS - Compiler switches required for using Argp # -# Copyright (c) 2010 Andreas Schneider +# Copyright (c) 2010 Andreas Schneider # # Redistribution and use is allowed according to the terms of the New # BSD license. diff --git a/libssh/cmake/Modules/FindNaCl.cmake b/libssh/cmake/Modules/FindNaCl.cmake index fa9c4090..b1a8da45 100644 --- a/libssh/cmake/Modules/FindNaCl.cmake +++ b/libssh/cmake/Modules/FindNaCl.cmake @@ -6,7 +6,7 @@ # NACL_LIBRARIES - Link these to use NaCl # NACL_DEFINITIONS - Compiler switches required for using NaCl # -# Copyright (c) 2010 Andreas Schneider +# Copyright (c) 2010 Andreas Schneider # Copyright (c) 2013 Aris Adamantiadis # # Redistribution and use is allowed according to the terms of the New diff --git a/libssh/cmake/Modules/MacroAddCompileFlags.cmake b/libssh/cmake/Modules/MacroAddCompileFlags.cmake deleted file mode 100644 index a866689d..00000000 --- a/libssh/cmake/Modules/MacroAddCompileFlags.cmake +++ /dev/null @@ -1,21 +0,0 @@ -# - MACRO_ADD_COMPILE_FLAGS(target_name flag1 ... flagN) - -# Copyright (c) 2006, Oswald Buddenhagen, -# Copyright (c) 2006, Andreas Schneider, -# -# 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) diff --git a/libssh/cmake/Modules/MacroAddLinkFlags.cmake b/libssh/cmake/Modules/MacroAddLinkFlags.cmake deleted file mode 100644 index 91cad306..00000000 --- a/libssh/cmake/Modules/MacroAddLinkFlags.cmake +++ /dev/null @@ -1,20 +0,0 @@ -# - MACRO_ADD_LINK_FLAGS(target_name flag1 ... flagN) - -# Copyright (c) 2006, Oswald Buddenhagen, -# Copyright (c) 2006, Andreas Schneider, -# -# 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) diff --git a/libssh/cmake/Modules/MacroAddPlugin.cmake b/libssh/cmake/Modules/MacroAddPlugin.cmake deleted file mode 100644 index 36b5e57e..00000000 --- a/libssh/cmake/Modules/MacroAddPlugin.cmake +++ /dev/null @@ -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, -# Copyright (c) 2006, Laurent Montel, -# Copyright (c) 2006, Andreas Schneider, -# -# 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) - diff --git a/libssh/cmake/Modules/MacroCopyFile.cmake b/libssh/cmake/Modules/MacroCopyFile.cmake deleted file mode 100644 index cee1cae3..00000000 --- a/libssh/cmake/Modules/MacroCopyFile.cmake +++ /dev/null @@ -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 -# -# 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) diff --git a/libssh/cmake/Modules/UseDoxygen.cmake b/libssh/cmake/Modules/UseDoxygen.cmake index 861afa51..72c384d2 100644 --- a/libssh/cmake/Modules/UseDoxygen.cmake +++ b/libssh/cmake/Modules/UseDoxygen.cmake @@ -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 -# Copyright (c) 2010 Andreas Schneider +# Copyright (c) 2009, 2010, 2011 Tobias Rautenkranz # # 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() diff --git a/libssh/config.h.cmake b/libssh/config.h.cmake index 7e8cb6a8..55e37aca 100644 --- a/libssh/config.h.cmake +++ b/libssh/config.h.cmake @@ -20,9 +20,15 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PTY_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UTMP_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UTIL_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBUTIL_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TERMIOS_H 1 diff --git a/libssh/doc/doxy.config.in b/libssh/doc/Doxyfile.in similarity index 99% rename from libssh/doc/doxy.config.in rename to libssh/doc/Doxyfile.in index 4da9b2c9..a7a9ffbb 100644 --- a/libssh/doc/doxy.config.in +++ b/libssh/doc/Doxyfile.in @@ -721,7 +721,7 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */.git/* \ */.svn/* \ */cmake/* \ - */build/* + */obj/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the diff --git a/libssh/doc/authentication.dox b/libssh/doc/authentication.dox index fbc2103b..30690e8c 100644 --- a/libssh/doc/authentication.dox +++ b/libssh/doc/authentication.dox @@ -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; } diff --git a/libssh/doc/doxy.trac.in b/libssh/doc/doxy.trac.in deleted file mode 100644 index dbd719aa..00000000 --- a/libssh/doc/doxy.trac.in +++ /dev/null @@ -1,1546 +0,0 @@ -# Doxyfile 1.6.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = @APPLICATION_NAME@ - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = @APPLICATION_VERSION@ - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@ - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = @CMAKE_SOURCE_DIR@ - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 2 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it parses. -# With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this tag. -# The format is ext=language, where ext is a file extension, and language is one of -# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, -# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = YES - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = YES - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = YES - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = @CMAKE_INTERNAL_DOC@ - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = YES - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = @CMAKE_SOURCE_DIR@/include \ - @CMAKE_SOURCE_DIR@/libssh \ - @CMAKE_SOURCE_DIR@/doc - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = *.cpp \ - *.cc \ - *.c \ - *.h \ - *.hh \ - *.hpp \ - *.dox - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = */.git/* \ - */.svn/* \ - */cmake/* \ - */build/* - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/examples - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = *.c \ - *.h \ - INSTALL \ - DEPENDENCIES \ - CHANGELOG \ - LICENSE \ - LGPL - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = YES - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 2 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = trac - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = @CMAKE_CURRENT_SOURCE_DIR@/TracHeader.html - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = @CMAKE_CURRENT_SOURCE_DIR@/TracFooter.html - -# If the HTML_TIMESTAMP tag is set to YES then the generated HTML -# documentation will contain the timesstamp. - -HTML_TIMESTAMP = NO - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. -# For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's -# filter section matches. -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. - -USE_INLINE_TREES = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) -# there is already a search function so this one should typically -# be disabled. - -SEARCHENGINE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4 - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = YES - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = YES - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = YES - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# 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. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = @CMAKE_CURRENT_BINARY_DIR@/trac/@PROJECT_NAME@.TAGFILE - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = YES - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = NO - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = @DOXYGEN_DOT_FOUND@ - -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = FreeSans - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = @DOXYGEN_DOT_EXECUTABLE_PATH@ - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = YES - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/libssh/doc/forwarding.dox b/libssh/doc/forwarding.dox index 9dc0df36..be4ab94e 100644 --- a/libssh/doc/forwarding.dox +++ b/libssh/doc/forwarding.dox @@ -144,10 +144,10 @@ 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(). +To do reverse port forwarding, call ssh_channel_listen_forward(), +then ssh_channel_accept_forward(). -When you call ssh_forward_listen(), you can let the remote server +When you call ssh_channel_listen_forward(), you can let the remote server chose the non-priviledged port it should listen to. Otherwise, you can chose your own priviledged or non-priviledged port. Beware that you should have administrative priviledges on the remote server to open a priviledged port @@ -164,6 +164,7 @@ int web_server(ssh_session session) ssh_channel channel; char buffer[256]; int nbytes, nwritten; + int port = 0; char *helloworld = "" "HTTP/1.1 200 OK\n" "Content-Type: text/html\n" @@ -178,7 +179,7 @@ int web_server(ssh_session session) " \n" "\n"; - rc = ssh_forward_listen(session, NULL, 8080, NULL); + rc = ssh_channel_listen_forward(session, NULL, 8080, NULL); if (rc != SSH_OK) { fprintf(stderr, "Error opening remote port: %s\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", diff --git a/libssh/doc/threading.dox b/libssh/doc/threading.dox index a11c82f7..95eee6bb 100644 --- a/libssh/doc/threading.dox +++ b/libssh/doc/threading.dox @@ -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 ! */ diff --git a/libssh/examples/CMakeLists.txt b/libssh/examples/CMakeLists.txt index c155e097..4998f041 100644 --- a/libssh/examples/CMakeLists.txt +++ b/libssh/examples/CMakeLists.txt @@ -25,13 +25,6 @@ if (UNIX AND NOT WIN32) add_executable(sshnetcat sshnetcat.c ${examples_SRCS}) target_link_libraries(sshnetcat ${LIBSSH_SHARED_LIBRARY}) - if (WITH_SERVER) - if (HAVE_LIBUTIL) - add_executable(samplesshd-tty samplesshd-tty.c) - target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES} util) - endif (HAVE_LIBUTIL) - endif (WITH_SERVER) - if (WITH_SFTP) add_executable(samplesftp samplesftp.c ${examples_SRCS}) target_link_libraries(samplesftp ${LIBSSH_SHARED_LIBRARY}) @@ -41,8 +34,10 @@ if (UNIX AND NOT WIN32) target_link_libraries(samplessh ${LIBSSH_SHARED_LIBRARY}) if (WITH_SERVER) - add_executable(samplesshd samplesshd.c) - target_link_libraries(samplesshd ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES}) + if (HAVE_LIBUTIL) + add_executable(ssh_server_fork ssh_server_fork.c) + target_link_libraries(ssh_server_fork ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES} util) + endif (HAVE_LIBUTIL) if (WITH_GSSAPI AND GSSAPI_FOUND) add_executable(samplesshd-cb samplesshd-cb.c) diff --git a/libssh/examples/authentication.c b/libssh/examples/authentication.c index ab5e64d6..b9f70f5b 100644 --- a/libssh/examples/authentication.c +++ b/libssh/examples/authentication.c @@ -116,7 +116,7 @@ int authenticate_console(ssh_session session){ return rc; } - method = ssh_auth_list(session); + method = ssh_userauth_list(session, NULL); while (rc != SSH_AUTH_SUCCESS) { if (method & SSH_AUTH_METHOD_GSSAPI_MIC){ rc = ssh_userauth_gssapi(session); @@ -129,10 +129,10 @@ int authenticate_console(ssh_session session){ } // Try to authenticate with public key first if (method & SSH_AUTH_METHOD_PUBLICKEY) { - rc = ssh_userauth_autopubkey(session, NULL); + rc = ssh_userauth_publickey_auto(session, NULL, NULL); if (rc == SSH_AUTH_ERROR) { - error(session); - return rc; + error(session); + return rc; } else if (rc == SSH_AUTH_SUCCESS) { break; } diff --git a/libssh/examples/samplesshd-tty.c b/libssh/examples/samplesshd-tty.c deleted file mode 100644 index 83b75648..00000000 --- a/libssh/examples/samplesshd-tty.c +++ /dev/null @@ -1,466 +0,0 @@ -/* This is a sample implementation of a libssh based SSH server */ -/* -Copyright 2003-2011 Aris Adamantiadis - -This file is part of the SSH Library - -You are free to copy this file, modify it in any way, consider it being public -domain. This does not apply to the rest of the library though, but it is -allowed to cut-and-paste working code from this file to any license of -program. -The goal is to show the API in action. It's not a reference on how terminal -clients must be made or how a client should react. -*/ - -#include "config.h" - -#include -#include -#include - -#ifdef HAVE_ARGP_H -#include -#endif -#include -#include -#include -#include -#ifdef HAVE_PTY_H -#include -#endif -#ifdef HAVE_UTIL_H -#include -#endif -#define SSHD_USER "libssh" -#define SSHD_PASSWORD "libssh" - -#ifndef KEYS_FOLDER -#ifdef _WIN32 -#define KEYS_FOLDER -#else -#define KEYS_FOLDER "/etc/ssh/" -#endif -#endif - -#ifdef WITH_PCAP -const char *pcap_file="debug.server.pcap"; -ssh_pcap_file pcap; - -static void set_pcap(ssh_session session){ - if(!pcap_file) - return; - pcap=ssh_pcap_file_new(); - if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){ - printf("Error opening pcap file\n"); - ssh_pcap_file_free(pcap); - pcap=NULL; - return; - } - ssh_set_pcap_file(session,pcap); -} - -static void cleanup_pcap(){ - ssh_pcap_file_free(pcap); - pcap=NULL; -} -#endif - - -static int auth_password(const char *user, const char *password){ - if(strcmp(user, SSHD_USER)) - return 0; - if(strcmp(password, SSHD_PASSWORD)) - return 0; - return 1; // authenticated -} -#ifdef HAVE_ARGP_H -const char *argp_program_version = "libssh server example " - SSH_STRINGIFY(LIBSSH_VERSION); -const char *argp_program_bug_address = ""; - -/* Program documentation. */ -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[] = { - { - .name = "port", - .key = 'p', - .arg = "PORT", - .flags = 0, - .doc = "Set the port to bind.", - .group = 0 - }, - { - .name = "hostkey", - .key = 'k', - .arg = "FILE", - .flags = 0, - .doc = "Set the host key.", - .group = 0 - }, - { - .name = "dsakey", - .key = 'd', - .arg = "FILE", - .flags = 0, - .doc = "Set the dsa key.", - .group = 0 - }, - { - .name = "rsakey", - .key = 'r', - .arg = "FILE", - .flags = 0, - .doc = "Set the rsa key.", - .group = 0 - }, - { - .name = "verbose", - .key = 'v', - .arg = NULL, - .flags = 0, - .doc = "Get verbose output.", - .group = 0 - }, - {NULL, 0, 0, 0, NULL, 0} -}; - -/* Parse a single option. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state) { - /* Get the input argument from argp_parse, which we - * know is a pointer to our arguments structure. - */ - ssh_bind sshbind = state->input; - - switch (key) { - case 'p': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg); - port = atoi(arg); - break; - case 'd': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg); - break; - case 'k': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg); - break; - case 'r': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg); - break; - case 'v': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3"); - break; - case ARGP_KEY_ARG: - if (state->arg_num >= 1) { - /* Too many arguments. */ - argp_usage (state); - } - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg); - break; - case ARGP_KEY_END: - if (state->arg_num < 1) { - /* Not enough arguments. */ - argp_usage (state); - } - break; - default: - return ARGP_ERR_UNKNOWN; - } - - return 0; -} - -/* Our argp parser. */ -static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; -#endif /* HAVE_ARGP_H */ - -static int authenticate(ssh_session session) { - ssh_message message; - - do { - message=ssh_message_get(session); - if(!message) - break; - switch(ssh_message_type(message)){ - case SSH_REQUEST_AUTH: - switch(ssh_message_subtype(message)){ - case SSH_AUTH_METHOD_PASSWORD: - printf("User %s wants to auth with pass %s\n", - ssh_message_auth_user(message), - ssh_message_auth_password(message)); - if(auth_password(ssh_message_auth_user(message), - ssh_message_auth_password(message))){ - ssh_message_auth_reply_success(message,0); - ssh_message_free(message); - return 1; - } - ssh_message_auth_set_methods(message, - SSH_AUTH_METHOD_PASSWORD | - SSH_AUTH_METHOD_INTERACTIVE); - // not authenticated, send default message - ssh_message_reply_default(message); - break; - - case SSH_AUTH_METHOD_NONE: - default: - printf("User %s wants to auth with unknown auth %d\n", - ssh_message_auth_user(message), - ssh_message_subtype(message)); - ssh_message_auth_set_methods(message, - SSH_AUTH_METHOD_PASSWORD | - SSH_AUTH_METHOD_INTERACTIVE); - ssh_message_reply_default(message); - break; - } - break; - default: - ssh_message_auth_set_methods(message, - SSH_AUTH_METHOD_PASSWORD | - SSH_AUTH_METHOD_INTERACTIVE); - ssh_message_reply_default(message); - } - ssh_message_free(message); - } while (1); - return 0; -} - -static int copy_fd_to_chan(socket_t fd, int revents, void *userdata) { - ssh_channel chan = (ssh_channel)userdata; - char buf[2048]; - int sz = 0; - - if(!chan) { - close(fd); - return -1; - } - if(revents & POLLIN) { - sz = read(fd, buf, 2048); - if(sz > 0) { - ssh_channel_write(chan, buf, sz); - } - } - if(revents & POLLHUP) { - ssh_channel_close(chan); - sz = -1; - } - return sz; -} - -static int copy_chan_to_fd(ssh_session session, - ssh_channel channel, - void *data, - uint32_t len, - int is_stderr, - void *userdata) { - int fd = *(int*)userdata; - int sz; - (void)session; - (void)channel; - (void)is_stderr; - - sz = write(fd, data, len); - return sz; -} - -static void chan_close(ssh_session session, ssh_channel channel, void *userdata) { - int fd = *(int*)userdata; - (void)session; - (void)channel; - - close(fd); -} - -struct ssh_channel_callbacks_struct cb = { - .channel_data_function = copy_chan_to_fd, - .channel_eof_function = chan_close, - .channel_close_function = chan_close, - .userdata = NULL -}; - -static int main_loop(ssh_channel chan) { - ssh_session session = ssh_channel_get_session(chan); - socket_t fd; - struct termios *term = NULL; - struct winsize *win = NULL; - pid_t childpid; - ssh_event event; - short events; - int rc; - - childpid = forkpty(&fd, NULL, term, win); - if(childpid == 0) { - execl("/bin/bash", "/bin/bash", (char *)NULL); - abort(); - } - - cb.userdata = &fd; - ssh_callbacks_init(&cb); - ssh_set_channel_callbacks(chan, &cb); - - events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL; - - event = ssh_event_new(); - if(event == NULL) { - printf("Couldn't get a event\n"); - return -1; - } - if(ssh_event_add_fd(event, fd, events, copy_fd_to_chan, chan) != SSH_OK) { - printf("Couldn't add an fd to the event\n"); - ssh_event_free(event); - return -1; - } - if(ssh_event_add_session(event, session) != SSH_OK) { - printf("Couldn't add the session to the event\n"); - ssh_event_remove_fd(event, fd); - ssh_event_free(event); - return -1; - } - - do { - rc = ssh_event_dopoll(event, 1000); - if (rc == SSH_ERROR){ - fprintf(stderr, "Error : %s\n", ssh_get_error(session)); - ssh_event_free(event); - ssh_disconnect(session); - return -1; - } - } while(!ssh_channel_is_closed(chan)); - - ssh_event_remove_fd(event, fd); - - ssh_event_remove_session(event, session); - - ssh_event_free(event); - return 0; -} - - -int main(int argc, char **argv){ - ssh_session session; - ssh_bind sshbind; - ssh_message message; - ssh_channel chan=0; - int auth=0; - int shell=0; - int r; - - sshbind=ssh_bind_new(); - session=ssh_new(); - - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, - KEYS_FOLDER "ssh_host_dsa_key"); - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, - KEYS_FOLDER "ssh_host_rsa_key"); - -#ifdef HAVE_ARGP_H - /* - * Parse our arguments; every option seen by parse_opt will - * be reflected in arguments. - */ - argp_parse (&argp, argc, argv, 0, 0, sshbind); -#else - (void) argc; - (void) argv; -#endif -#ifdef WITH_PCAP - set_pcap(session); -#endif - - if(ssh_bind_listen(sshbind)<0){ - printf("Error listening to socket: %s\n", ssh_get_error(sshbind)); - return 1; - } - printf("Started sample libssh sshd on port %d\n", port); - printf("You can login as the user %s with the password %s\n", SSHD_USER, - SSHD_PASSWORD); - r = ssh_bind_accept(sshbind, session); - if(r==SSH_ERROR){ - printf("Error accepting a connection: %s\n", ssh_get_error(sshbind)); - return 1; - } - if (ssh_handle_key_exchange(session)) { - printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session)); - return 1; - } - - /* proceed to authentication */ - auth = authenticate(session); - if(!auth){ - printf("Authentication error: %s\n", ssh_get_error(session)); - ssh_disconnect(session); - return 1; - } - - - /* wait for a channel session */ - do { - message = ssh_message_get(session); - if(message){ - if(ssh_message_type(message) == SSH_REQUEST_CHANNEL_OPEN && - ssh_message_subtype(message) == SSH_CHANNEL_SESSION) { - chan = ssh_message_channel_request_open_reply_accept(message); - ssh_message_free(message); - break; - } else { - ssh_message_reply_default(message); - ssh_message_free(message); - } - } else { - break; - } - } while(!chan); - - if(!chan) { - printf("Error: cleint did not ask for a channel session (%s)\n", - ssh_get_error(session)); - ssh_finalize(); - return 1; - } - - - /* wait for a shell */ - do { - message = ssh_message_get(session); - if(message != NULL) { - if(ssh_message_type(message) == SSH_REQUEST_CHANNEL) { - if(ssh_message_subtype(message) == SSH_CHANNEL_REQUEST_SHELL) { - shell = 1; - ssh_message_channel_request_reply_success(message); - ssh_message_free(message); - break; - } else if(ssh_message_subtype(message) == SSH_CHANNEL_REQUEST_PTY) { - ssh_message_channel_request_reply_success(message); - ssh_message_free(message); - continue; - } - } - ssh_message_reply_default(message); - ssh_message_free(message); - } else { - break; - } - } while(!shell); - - if(!shell) { - printf("Error: No shell requested (%s)\n", ssh_get_error(session)); - return 1; - } - - printf("it works !\n"); - - main_loop(chan); - - ssh_disconnect(session); - ssh_bind_free(sshbind); -#ifdef WITH_PCAP - cleanup_pcap(); -#endif - ssh_finalize(); - return 0; -} - diff --git a/libssh/examples/samplesshd.c b/libssh/examples/samplesshd.c deleted file mode 100644 index f9e0dc8c..00000000 --- a/libssh/examples/samplesshd.c +++ /dev/null @@ -1,314 +0,0 @@ -/* This is a sample implementation of a libssh based SSH server */ -/* -Copyright 2003-2009 Aris Adamantiadis - -This file is part of the SSH Library - -You are free to copy this file, modify it in any way, consider it being public -domain. This does not apply to the rest of the library though, but it is -allowed to cut-and-paste working code from this file to any license of -program. -The goal is to show the API in action. It's not a reference on how terminal -clients must be made or how a client should react. -*/ - -#include "config.h" - -#include -#include - -#ifdef HAVE_ARGP_H -#include -#endif -#include -#include -#include - -#ifndef KEYS_FOLDER -#ifdef _WIN32 -#define KEYS_FOLDER -#else -#define KEYS_FOLDER "/etc/ssh/" -#endif -#endif - -#ifdef WITH_PCAP -static const char *pcap_file="debug.server.pcap"; -static ssh_pcap_file pcap; - -static void set_pcap(ssh_session session) { - if(!pcap_file) - return; - pcap=ssh_pcap_file_new(); - if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){ - printf("Error opening pcap file\n"); - ssh_pcap_file_free(pcap); - pcap=NULL; - return; - } - ssh_set_pcap_file(session,pcap); -} - -static void cleanup_pcap(void) { - ssh_pcap_file_free(pcap); - pcap=NULL; -} -#endif - - -static int auth_password(const char *user, const char *password){ - if(strcmp(user,"aris")) - return 0; - if(strcmp(password,"lala")) - return 0; - return 1; // authenticated -} -#ifdef HAVE_ARGP_H -const char *argp_program_version = "libssh server example " - SSH_STRINGIFY(LIBSSH_VERSION); -const char *argp_program_bug_address = ""; - -/* Program documentation. */ -static char doc[] = "libssh -- a Secure Shell protocol implementation"; - -/* A description of the arguments we accept. */ -static char args_doc[] = "BINDADDR"; - -/* The options we understand. */ -static struct argp_option options[] = { - { - .name = "port", - .key = 'p', - .arg = "PORT", - .flags = 0, - .doc = "Set the port to bind.", - .group = 0 - }, - { - .name = "hostkey", - .key = 'k', - .arg = "FILE", - .flags = 0, - .doc = "Set the host key.", - .group = 0 - }, - { - .name = "dsakey", - .key = 'd', - .arg = "FILE", - .flags = 0, - .doc = "Set the dsa key.", - .group = 0 - }, - { - .name = "rsakey", - .key = 'r', - .arg = "FILE", - .flags = 0, - .doc = "Set the rsa key.", - .group = 0 - }, - { - .name = "verbose", - .key = 'v', - .arg = NULL, - .flags = 0, - .doc = "Get verbose output.", - .group = 0 - }, - {NULL, 0, NULL, 0, NULL, 0} -}; - -/* Parse a single option. */ -static error_t parse_opt (int key, char *arg, struct argp_state *state) { - /* Get the input argument from argp_parse, which we - * know is a pointer to our arguments structure. - */ - ssh_bind sshbind = state->input; - - switch (key) { - case 'p': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg); - break; - case 'd': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg); - break; - case 'k': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg); - break; - case 'r': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg); - break; - case 'v': - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "3"); - break; - case ARGP_KEY_ARG: - if (state->arg_num >= 1) { - /* Too many arguments. */ - argp_usage (state); - } - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg); - break; - case ARGP_KEY_END: - if (state->arg_num < 1) { - /* Not enough arguments. */ - argp_usage (state); - } - break; - default: - return ARGP_ERR_UNKNOWN; - } - - return 0; -} - -/* Our argp parser. */ -static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; -#endif /* HAVE_ARGP_H */ - -int main(int argc, char **argv){ - ssh_session session; - ssh_bind sshbind; - ssh_message message; - ssh_channel chan=0; - char buf[2048]; - int auth=0; - int sftp=0; - int i; - int r; - - sshbind=ssh_bind_new(); - session=ssh_new(); - - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh_host_dsa_key"); - ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh_host_rsa_key"); - -#ifdef HAVE_ARGP_H - /* - * Parse our arguments; every option seen by parse_opt will - * be reflected in arguments. - */ - argp_parse (&argp, argc, argv, 0, 0, sshbind); -#else - (void) argc; - (void) argv; -#endif -#ifdef WITH_PCAP - set_pcap(session); -#endif - - if(ssh_bind_listen(sshbind)<0){ - printf("Error listening to socket: %s\n",ssh_get_error(sshbind)); - return 1; - } - r=ssh_bind_accept(sshbind,session); - if(r==SSH_ERROR){ - printf("error accepting a connection : %s\n",ssh_get_error(sshbind)); - return 1; - } - if (ssh_handle_key_exchange(session)) { - printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session)); - return 1; - } - do { - message=ssh_message_get(session); - if(!message) - break; - switch(ssh_message_type(message)){ - case SSH_REQUEST_AUTH: - switch(ssh_message_subtype(message)){ - case SSH_AUTH_METHOD_PASSWORD: - printf("User %s wants to auth with pass %s\n", - ssh_message_auth_user(message), - ssh_message_auth_password(message)); - if(auth_password(ssh_message_auth_user(message), - ssh_message_auth_password(message))){ - auth=1; - ssh_message_auth_reply_success(message,0); - break; - } - // not authenticated, send default message - case SSH_AUTH_METHOD_NONE: - default: - ssh_message_auth_set_methods(message,SSH_AUTH_METHOD_PASSWORD); - ssh_message_reply_default(message); - break; - } - break; - default: - ssh_message_reply_default(message); - } - ssh_message_free(message); - } while (!auth); - if(!auth){ - printf("auth error: %s\n",ssh_get_error(session)); - ssh_disconnect(session); - return 1; - } - do { - message=ssh_message_get(session); - if(message){ - switch(ssh_message_type(message)){ - case SSH_REQUEST_CHANNEL_OPEN: - if(ssh_message_subtype(message)==SSH_CHANNEL_SESSION){ - chan=ssh_message_channel_request_open_reply_accept(message); - break; - } - default: - ssh_message_reply_default(message); - } - ssh_message_free(message); - } - } while(message && !chan); - if(!chan){ - printf("error : %s\n",ssh_get_error(session)); - ssh_finalize(); - return 1; - } - do { - message=ssh_message_get(session); - if(message && ssh_message_type(message)==SSH_REQUEST_CHANNEL && - (ssh_message_subtype(message)==SSH_CHANNEL_REQUEST_SHELL || - ssh_message_subtype(message)==SSH_CHANNEL_REQUEST_PTY)) { -// if(!strcmp(ssh_message_channel_request_subsystem(message),"sftp")){ - sftp=1; - ssh_message_channel_request_reply_success(message); - break; - // } - } - if(!sftp){ - ssh_message_reply_default(message); - } - ssh_message_free(message); - } while (message && !sftp); - if(!sftp){ - printf("error : %s\n",ssh_get_error(session)); - return 1; - } - printf("it works !\n"); - do{ - i=ssh_channel_read(chan,buf, 2048, 0); - if(i>0) { - ssh_channel_write(chan, buf, i); - if (write(1,buf,i) < 0) { - printf("error writing to buffer\n"); - return 1; - } - if (buf[0] == '\x0d') { - if (write(1, "\n", 1) < 0) { - printf("error writing to buffer\n"); - return 1; - } - ssh_channel_write(chan, "\n", 1); - } - } - } while (i>0); - ssh_disconnect(session); - ssh_bind_free(sshbind); -#ifdef WITH_PCAP - cleanup_pcap(); -#endif - ssh_finalize(); - return 0; -} - diff --git a/libssh/examples/ssh_server_fork.c b/libssh/examples/ssh_server_fork.c new file mode 100644 index 00000000..837db6fe --- /dev/null +++ b/libssh/examples/ssh_server_fork.c @@ -0,0 +1,697 @@ +/* This is a sample implementation of a libssh based SSH server */ +/* +Copyright 2014 Audrius Butkevicius + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +domain. This does not apply to the rest of the library though, but it is +allowed to cut-and-paste working code from this file to any license of +program. +The goal is to show the API in action. +*/ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_ARGP_H +#include +#endif +#include +#ifdef HAVE_LIBUTIL_H +#include +#endif +#ifdef HAVE_PTY_H +#include +#endif +#include +#include +#ifdef HAVE_UTMP_H +#include +#endif +#ifdef HAVE_UTIL_H +#include +#endif +#include +#include +#include + +#ifndef KEYS_FOLDER +#ifdef _WIN32 +#define KEYS_FOLDER +#else +#define KEYS_FOLDER "/etc/ssh/" +#endif +#endif + +#define USER "myuser" +#define PASS "mypassword" +#define BUF_SIZE 1048576 +#define SESSION_END (SSH_CLOSED | SSH_CLOSED_ERROR) +#define SFTP_SERVER_PATH "/usr/lib/sftp-server" + +static void set_default_keys(ssh_bind sshbind, + int rsa_already_set, + int dsa_already_set, + int ecdsa_already_set) { + if (!rsa_already_set) { + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, + KEYS_FOLDER "ssh_host_rsa_key"); + } + if (!dsa_already_set) { + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, + KEYS_FOLDER "ssh_host_dsa_key"); + } + if (!ecdsa_already_set) { + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, + KEYS_FOLDER "ssh_host_ecdsa_key"); + } +} + +#ifdef HAVE_ARGP_H +const char *argp_program_version = "libssh server example " +SSH_STRINGIFY(LIBSSH_VERSION); +const char *argp_program_bug_address = ""; + +/* Program documentation. */ +static char doc[] = "libssh -- a Secure Shell protocol implementation"; + +/* A description of the arguments we accept. */ +static char args_doc[] = "BINDADDR"; + +/* The options we understand. */ +static struct argp_option options[] = { + { + .name = "port", + .key = 'p', + .arg = "PORT", + .flags = 0, + .doc = "Set the port to bind.", + .group = 0 + }, + { + .name = "hostkey", + .key = 'k', + .arg = "FILE", + .flags = 0, + .doc = "Set a host key. Can be used multiple times. " + "Implies no default keys.", + .group = 0 + }, + { + .name = "dsakey", + .key = 'd', + .arg = "FILE", + .flags = 0, + .doc = "Set the dsa key.", + .group = 0 + }, + { + .name = "rsakey", + .key = 'r', + .arg = "FILE", + .flags = 0, + .doc = "Set the rsa key.", + .group = 0 + }, + { + .name = "ecdsakey", + .key = 'e', + .arg = "FILE", + .flags = 0, + .doc = "Set the ecdsa key.", + .group = 0 + }, + { + .name = "no-default-keys", + .key = 'n', + .arg = NULL, + .flags = 0, + .doc = "Do not set default key locations.", + .group = 0 + }, + { + .name = "verbose", + .key = 'v', + .arg = NULL, + .flags = 0, + .doc = "Get verbose output.", + .group = 0 + }, + {NULL, 0, NULL, 0, NULL, 0} +}; + +/* Parse a single option. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state) { + /* Get the input argument from argp_parse, which we + * know is a pointer to our arguments structure. */ + ssh_bind sshbind = state->input; + static int no_default_keys = 0; + static int rsa_already_set = 0, dsa_already_set = 0, ecdsa_already_set = 0; + + switch (key) { + case 'n': + no_default_keys = 1; + break; + case 'p': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg); + break; + case 'd': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg); + dsa_already_set = 1; + break; + case 'k': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg); + /* We can't track the types of keys being added with this + option, so let's ensure we keep the keys we're adding + by just not setting the default keys */ + no_default_keys = 1; + break; + case 'r': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg); + rsa_already_set = 1; + break; + case 'e': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, arg); + ecdsa_already_set = 1; + break; + case 'v': + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, + "3"); + break; + case ARGP_KEY_ARG: + if (state->arg_num >= 1) { + /* Too many arguments. */ + argp_usage (state); + } + ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg); + break; + case ARGP_KEY_END: + if (state->arg_num < 1) { + /* Not enough arguments. */ + argp_usage (state); + } + + if (!no_default_keys) { + set_default_keys(sshbind, + rsa_already_set, + dsa_already_set, + ecdsa_already_set); + } + + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +/* Our argp parser. */ +static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL}; +#endif /* HAVE_ARGP_H */ + +/* A userdata struct for channel. */ +struct channel_data_struct { + /* pid of the child process the channel will spawn. */ + pid_t pid; + /* For PTY allocation */ + socket_t pty_master; + socket_t pty_slave; + /* For communication with the child process. */ + socket_t stdin; + socket_t stdout; + /* Only used for subsystem and exec requests. */ + socket_t stderr; + /* Event which is used to poll the above descriptors. */ + ssh_event event; + /* Terminal size struct. */ + struct winsize *winsize; +}; + +/* A userdata struct for session. */ +struct session_data_struct { + /* Pointer to the channel the session will allocate. */ + ssh_channel channel; + int auth_attempts; + int authenticated; +}; + +static int data_function(ssh_session session, ssh_channel channel, void *data, + uint32_t len, int is_stderr, void *userdata) { + struct channel_data_struct *cdata = (struct channel_data_struct *) userdata; + + (void) session; + (void) channel; + (void) is_stderr; + + if (len == 0 || cdata->pid < 1 || kill(cdata->pid, 0) < 0) { + return 0; + } + + return write(cdata->stdin, (char *) data, len); +} + +static int pty_request(ssh_session session, ssh_channel channel, + const char *term, int cols, int rows, int py, int px, + void *userdata) { + struct channel_data_struct *cdata = (struct channel_data_struct *)userdata; + + (void) session; + (void) channel; + (void) term; + + cdata->winsize->ws_row = rows; + cdata->winsize->ws_col = cols; + cdata->winsize->ws_xpixel = px; + cdata->winsize->ws_ypixel = py; + + if (openpty(&cdata->pty_master, &cdata->pty_slave, NULL, NULL, + cdata->winsize) != 0) { + fprintf(stderr, "Failed to open pty\n"); + return SSH_ERROR; + } + return SSH_OK; +} + +static int pty_resize(ssh_session session, ssh_channel channel, int cols, + int rows, int py, int px, void *userdata) { + struct channel_data_struct *cdata = (struct channel_data_struct *)userdata; + + (void) session; + (void) channel; + + cdata->winsize->ws_row = rows; + cdata->winsize->ws_col = cols; + cdata->winsize->ws_xpixel = px; + cdata->winsize->ws_ypixel = py; + + if (cdata->pty_master != -1) { + return ioctl(cdata->pty_master, TIOCSWINSZ, cdata->winsize); + } + + return SSH_ERROR; +} + +static int exec_pty(const char *mode, const char *command, + struct channel_data_struct *cdata) { + switch(cdata->pid = fork()) { + case -1: + close(cdata->pty_master); + close(cdata->pty_slave); + fprintf(stderr, "Failed to fork\n"); + return SSH_ERROR; + case 0: + close(cdata->pty_master); + if (login_tty(cdata->pty_slave) != 0) { + exit(1); + } + execl("/bin/sh", "sh", mode, command, NULL); + exit(0); + default: + close(cdata->pty_slave); + /* pty fd is bi-directional */ + cdata->stdout = cdata->stdin = cdata->pty_master; + } + return SSH_OK; +} + +static int exec_nopty(const char *command, struct channel_data_struct *cdata) { + int in[2], out[2], err[2]; + + /* Do the plumbing to be able to talk with the child process. */ + if (pipe(in) != 0) { + goto stdin_failed; + } + if (pipe(out) != 0) { + goto stdout_failed; + } + if (pipe(err) != 0) { + goto stderr_failed; + } + + switch(cdata->pid = fork()) { + case -1: + goto fork_failed; + case 0: + /* Finish the plumbing in the child process. */ + close(in[1]); + close(out[0]); + close(err[0]); + dup2(in[0], STDIN_FILENO); + dup2(out[1], STDOUT_FILENO); + dup2(err[1], STDERR_FILENO); + close(in[0]); + close(out[1]); + close(err[1]); + /* exec the requested command. */ + execl("/bin/sh", "sh", "-c", command, NULL); + exit(0); + } + + close(in[0]); + close(out[1]); + close(err[1]); + + cdata->stdin = in[1]; + cdata->stdout = out[0]; + cdata->stderr = err[0]; + + return SSH_OK; + +fork_failed: + close(err[0]); + close(err[1]); +stderr_failed: + close(out[0]); + close(out[1]); +stdout_failed: + close(in[0]); + close(in[1]); +stdin_failed: + return SSH_ERROR; +} + +static int exec_request(ssh_session session, ssh_channel channel, + const char *command, void *userdata) { + struct channel_data_struct *cdata = (struct channel_data_struct *) userdata; + + + (void) session; + (void) channel; + + if(cdata->pid > 0) { + return SSH_ERROR; + } + + if (cdata->pty_master != -1 && cdata->pty_slave != -1) { + return exec_pty("-c", command, cdata); + } + return exec_nopty(command, cdata); +} + +static int shell_request(ssh_session session, ssh_channel channel, + void *userdata) { + struct channel_data_struct *cdata = (struct channel_data_struct *) userdata; + + (void) session; + (void) channel; + + if(cdata->pid > 0) { + return SSH_ERROR; + } + + if (cdata->pty_master != -1 && cdata->pty_slave != -1) { + return exec_pty("-l", NULL, cdata); + } + /* Client requested a shell without a pty, let's pretend we allow that */ + return SSH_OK; +} + +static int subsystem_request(ssh_session session, ssh_channel channel, + const char *subsystem, void *userdata) { + /* subsystem requests behave simillarly to exec requests. */ + if (strcmp(subsystem, "sftp") == 0) { + return exec_request(session, channel, SFTP_SERVER_PATH, userdata); + } + return SSH_ERROR; +} + +static int auth_password(ssh_session session, const char *user, + const char *pass, void *userdata) { + struct session_data_struct *sdata = (struct session_data_struct *) userdata; + + (void) session; + + if (strcmp(user, USER) == 0 && strcmp(pass, PASS) == 0) { + sdata->authenticated = 1; + return SSH_AUTH_SUCCESS; + } + + sdata->auth_attempts++; + return SSH_AUTH_DENIED; +} + +static ssh_channel channel_open(ssh_session session, void *userdata) { + struct session_data_struct *sdata = (struct session_data_struct *) userdata; + + sdata->channel = ssh_channel_new(session); + return sdata->channel; +} + +static int process_stdout(socket_t fd, int revents, void *userdata) { + char buf[BUF_SIZE]; + int n = -1; + ssh_channel channel = (ssh_channel) userdata; + + if (channel != NULL && (revents & POLLIN) != 0) { + n = read(fd, buf, BUF_SIZE); + if (n > 0) { + ssh_channel_write(channel, buf, n); + } + } + + return n; +} + +static int process_stderr(socket_t fd, int revents, void *userdata) { + char buf[BUF_SIZE]; + int n = -1; + ssh_channel channel = (ssh_channel) userdata; + + if (channel != NULL && (revents & POLLIN) != 0) { + n = read(fd, buf, BUF_SIZE); + if (n > 0) { + ssh_channel_write_stderr(channel, buf, n); + } + } + + return n; +} + +static void handle_session(ssh_event event, ssh_session session) { + int n, rc; + + /* Structure for storing the pty size. */ + struct winsize wsize = { + .ws_row = 0, + .ws_col = 0, + .ws_xpixel = 0, + .ws_ypixel = 0 + }; + + /* Our struct holding information about the channel. */ + struct channel_data_struct cdata = { + .pid = 0, + .pty_master = -1, + .pty_slave = -1, + .stdin = -1, + .stdout = -1, + .stderr = -1, + .event = NULL, + .winsize = &wsize + }; + + /* Our struct holding information about the session. */ + struct session_data_struct sdata = { + .channel = NULL, + .auth_attempts = 0, + .authenticated = 0 + }; + + struct ssh_channel_callbacks_struct channel_cb = { + .userdata = &cdata, + .channel_pty_request_function = pty_request, + .channel_pty_window_change_function = pty_resize, + .channel_shell_request_function = shell_request, + .channel_exec_request_function = exec_request, + .channel_data_function = data_function, + .channel_subsystem_request_function = subsystem_request + }; + + struct ssh_server_callbacks_struct server_cb = { + .userdata = &sdata, + .auth_password_function = auth_password, + .channel_open_request_session_function = channel_open, + }; + + ssh_callbacks_init(&server_cb); + ssh_callbacks_init(&channel_cb); + + ssh_set_server_callbacks(session, &server_cb); + + if (ssh_handle_key_exchange(session) != SSH_OK) { + fprintf(stderr, "%s\n", ssh_get_error(session)); + return; + } + + ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD); + ssh_event_add_session(event, session); + + n = 0; + while (sdata.authenticated == 0 || sdata.channel == NULL) { + /* If the user has used up all attempts, or if he hasn't been able to + * authenticate in 10 seconds (n * 100ms), disconnect. */ + if (sdata.auth_attempts >= 3 || n >= 100) { + return; + } + + if (ssh_event_dopoll(event, 100) == SSH_ERROR) { + fprintf(stderr, "%s\n", ssh_get_error(session)); + return; + } + n++; + } + + ssh_set_channel_callbacks(sdata.channel, &channel_cb); + + do { + /* Poll the main event which takes care of the session, the channel and + * even our child process's stdout/stderr (once it's started). */ + if (ssh_event_dopoll(event, -1) == SSH_ERROR) { + ssh_channel_close(sdata.channel); + } + + /* If child process's stdout/stderr has been registered with the event, + * or the child process hasn't started yet, continue. */ + if (cdata.event != NULL || cdata.pid == 0) { + continue; + } + /* Executed only once, once the child process starts. */ + cdata.event = event; + /* If stdout valid, add stdout to be monitored by the poll event. */ + if (cdata.stdout != -1) { + if (ssh_event_add_fd(event, cdata.stdout, POLLIN, process_stdout, + sdata.channel) != SSH_OK) { + fprintf(stderr, "Failed to register stdout to poll context\n"); + ssh_channel_close(sdata.channel); + } + } + + /* If stderr valid, add stderr to be monitored by the poll event. */ + if (cdata.stderr != -1){ + if (ssh_event_add_fd(event, cdata.stderr, POLLIN, process_stderr, + sdata.channel) != SSH_OK) { + fprintf(stderr, "Failed to register stderr to poll context\n"); + ssh_channel_close(sdata.channel); + } + } + } while(ssh_channel_is_open(sdata.channel) && + (cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0)); + + close(cdata.pty_master); + close(cdata.stdin); + close(cdata.stdout); + close(cdata.stderr); + + /* Remove the descriptors from the polling context, since they are now + * closed, they will always trigger during the poll calls. */ + ssh_event_remove_fd(event, cdata.stdout); + ssh_event_remove_fd(event, cdata.stderr); + + /* If the child process exited. */ + if (kill(cdata.pid, 0) < 0 && WIFEXITED(rc)) { + rc = WEXITSTATUS(rc); + ssh_channel_request_send_exit_status(sdata.channel, rc); + /* If client terminated the channel or the process did not exit nicely, + * but only if something has been forked. */ + } else if (cdata.pid > 0) { + kill(cdata.pid, SIGKILL); + } + + ssh_channel_send_eof(sdata.channel); + ssh_channel_close(sdata.channel); + + /* Wait up to 5 seconds for the client to terminate the session. */ + for (n = 0; n < 50 && (ssh_get_status(session) & SESSION_END) == 0; n++) { + ssh_event_dopoll(event, 100); + } +} + +/* SIGCHLD handler for cleaning up dead children. */ +static void sigchld_handler(int signo) { + (void) signo; + while (waitpid(-1, NULL, WNOHANG) > 0); +} + +int main(int argc, char **argv) { + ssh_bind sshbind; + ssh_session session; + ssh_event event; + struct sigaction sa; + + /* Set up SIGCHLD handler. */ + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; + if (sigaction(SIGCHLD, &sa, NULL) != 0) { + fprintf(stderr, "Failed to register SIGCHLD handler\n"); + return 1; + } + + ssh_init(); + sshbind = ssh_bind_new(); + +#ifdef HAVE_ARGP_H + argp_parse(&argp, argc, argv, 0, 0, sshbind); +#else + (void) argc; + (void) argv; + + set_default_keys(sshbind, 0, 0, 0); +#endif /* HAVE_ARGP_H */ + + if(ssh_bind_listen(sshbind) < 0) { + fprintf(stderr, "%s\n", ssh_get_error(sshbind)); + return 1; + } + + while (1) { + session = ssh_new(); + if (session == NULL) { + fprintf(stderr, "Failed to allocate session\n"); + continue; + } + + /* Blocks until there is a new incoming connection. */ + if(ssh_bind_accept(sshbind, session) != SSH_ERROR) { + switch(fork()) { + case 0: + /* Remove the SIGCHLD handler inherited from parent. */ + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); + /* Remove socket binding, which allows us to restart the + * parent process, without terminating existing sessions. */ + ssh_bind_free(sshbind); + + event = ssh_event_new(); + if (event != NULL) { + /* Blocks until the SSH session ends by either + * child process exiting, or client disconnecting. */ + handle_session(event, session); + ssh_event_free(event); + } else { + fprintf(stderr, "Could not create polling context\n"); + } + ssh_disconnect(session); + ssh_free(session); + + exit(0); + case -1: + fprintf(stderr, "Failed to fork\n"); + } + } else { + fprintf(stderr, "%s\n", ssh_get_error(sshbind)); + } + /* Since the session has been passed to a child fork, do some cleaning + * up at the parent process. */ + ssh_disconnect(session); + ssh_free(session); + } + + ssh_bind_free(sshbind); + ssh_finalize(); + return 0; +} diff --git a/libssh/examples/sshnetcat.c b/libssh/examples/sshnetcat.c index 052cabf4..8ac5a212 100644 --- a/libssh/examples/sshnetcat.c +++ b/libssh/examples/sshnetcat.c @@ -87,13 +87,23 @@ static void select_loop(ssh_session session,ssh_channel channel){ int ret; while(channel){ do{ + int fd; + FD_ZERO(&fds); if(!eof) FD_SET(0,&fds); timeout.tv_sec=30; timeout.tv_usec=0; - FD_SET(ssh_get_fd(session),&fds); - maxfd=ssh_get_fd(session)+1; + + fd = ssh_get_fd(session); + if (fd == -1) { + fprintf(stderr, "Error getting the session file descriptor: %s\n", + ssh_get_error(session)); + return; + } + FD_SET(fd, &fds); + maxfd = fd + 1; + channels[0]=channel; // set the first channel we want to read from channels[1]=NULL; ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout); @@ -102,27 +112,27 @@ static void select_loop(ssh_session session,ssh_channel channel){ if(FD_ISSET(0,&fds)){ lus=read(0,buffer,sizeof(buffer)); if(lus) - channel_write(channel,buffer,lus); + ssh_channel_write(channel,buffer,lus); else { eof=1; - channel_send_eof(channel); + ssh_channel_send_eof(channel); } } - if(channel && channel_is_closed(channel)){ - channel_free(channel); + if(channel && ssh_channel_is_closed(channel)){ + ssh_channel_free(channel); channel=NULL; channels[0]=NULL; } if(outchannels[0]){ - while(channel && channel_is_open(channel) && channel_poll(channel,0)){ - lus=channel_read(channel,buffer,sizeof(buffer),0); + while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)){ + lus = ssh_channel_read(channel,buffer,sizeof(buffer),0); if(lus==-1){ fprintf(stderr, "Error reading channel: %s\n", ssh_get_error(session)); return; } if(lus==0){ - channel_free(channel); + ssh_channel_free(channel); channel=channels[0]=NULL; } else { ret = write(1, buffer, lus); @@ -133,27 +143,28 @@ static void select_loop(ssh_session session,ssh_channel channel){ } } } - while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */ - lus=channel_read(channel,buffer,sizeof(buffer),1); + while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)){ /* stderr */ + lus = ssh_channel_read(channel, buffer, sizeof(buffer), 1); if(lus==-1){ fprintf(stderr, "Error reading channel: %s\n", ssh_get_error(session)); return; } if(lus==0){ - channel_free(channel); + ssh_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)){ - channel_free(channel); + if(channel && ssh_channel_is_closed(channel)){ + ssh_channel_free(channel); channel=NULL; } } while (ret==EINTR || ret==SSH_EINTR); @@ -164,8 +175,8 @@ static void select_loop(ssh_session session,ssh_channel channel){ static void forwarding(ssh_session session){ ssh_channel channel; int r; - channel=channel_new(session); - r=channel_open_forward(channel,desthost,atoi(port),"localhost",22); + channel = ssh_channel_new(session); + r = ssh_channel_open_forward(channel, desthost, atoi(port), "localhost", 22); if(r<0) { printf("error forwarding port : %s\n",ssh_get_error(session)); return; diff --git a/libssh/include/libssh/bignum.h b/libssh/include/libssh/bignum.h new file mode 100644 index 00000000..e5f2a472 --- /dev/null +++ b/libssh/include/libssh/bignum.h @@ -0,0 +1,32 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2014 by Aris Adamantiadis + * + * 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, or (at your option) any later version. + * + * 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 BIGNUM_H_ +#define BIGNUM_H_ + +#include "libssh/libcrypto.h" +#include "libssh/libgcrypt.h" + +bignum make_string_bn(ssh_string string); +ssh_string make_bignum_string(bignum num); +void ssh_print_bignum(const char *which,bignum num); + + +#endif /* BIGNUM_H_ */ diff --git a/libssh/include/libssh/buffer.h b/libssh/include/libssh/buffer.h index d7cdfbf4..2aebe7e7 100644 --- a/libssh/include/libssh/buffer.h +++ b/libssh/include/libssh/buffer.h @@ -21,6 +21,8 @@ #ifndef BUFFER_H_ #define BUFFER_H_ +#include + #include "libssh/libssh.h" /* * Describes a buffer state @@ -34,21 +36,32 @@ struct ssh_buffer_struct { uint32_t used; uint32_t allocated; uint32_t pos; + int secure; }; +#define SSH_BUFFER_PACK_END ((uint32_t) 0x4f65feb3) + LIBSSH_API void ssh_buffer_free(ssh_buffer buffer); LIBSSH_API void *ssh_buffer_get_begin(ssh_buffer buffer); LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer); LIBSSH_API ssh_buffer ssh_buffer_new(void); +void ssh_buffer_set_secure(ssh_buffer buffer); int buffer_add_ssh_string(ssh_buffer buffer, ssh_string string); int buffer_add_u8(ssh_buffer buffer, uint8_t data); int buffer_add_u16(ssh_buffer buffer, uint16_t data); int buffer_add_u32(ssh_buffer buffer, uint32_t data); int buffer_add_u64(ssh_buffer buffer, uint64_t data); -int buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len); +int ssh_buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len); +int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer, const char *format, va_list ap); +int _ssh_buffer_pack(struct ssh_buffer_struct *buffer, const char *format, ...); +#define ssh_buffer_pack(buffer, format, ...) _ssh_buffer_pack((buffer),(format), __VA_ARGS__, SSH_BUFFER_PACK_END) +int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer, const char *format, va_list ap); +int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer, const char *format, ...); +#define ssh_buffer_unpack(buffer, format, ...) _ssh_buffer_unpack((buffer),(format), __VA_ARGS__, SSH_BUFFER_PACK_END) + int buffer_prepend_data(ssh_buffer buffer, const void *data, uint32_t len); int buffer_add_buffer(ssh_buffer buffer, ssh_buffer source); -int buffer_reinit(ssh_buffer buffer); +int ssh_buffer_reinit(ssh_buffer buffer); /* buffer_get_rest returns a pointer to the current position into the buffer */ void *buffer_get_rest(ssh_buffer buffer); diff --git a/libssh/include/libssh/callbacks.h b/libssh/include/libssh/callbacks.h index a841f2e5..6bd8c573 100644 --- a/libssh/include/libssh/callbacks.h +++ b/libssh/include/libssh/callbacks.h @@ -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, @@ -801,6 +803,8 @@ struct ssh_threads_callbacks_struct { * * @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); diff --git a/libssh/include/libssh/channels.h b/libssh/include/libssh/channels.h index 4c726453..b05c4c02 100644 --- a/libssh/include/libssh/channels.h +++ b/libssh/include/libssh/channels.h @@ -75,6 +75,8 @@ struct ssh_channel_struct { int exit_status; enum ssh_channel_request_state_e request_state; ssh_channel_callbacks callbacks; + /* counters */ + ssh_counter counter; }; SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf); diff --git a/libssh/include/libssh/crypto.h b/libssh/include/libssh/crypto.h index eaff2ffd..61a2b27b 100644 --- a/libssh/include/libssh/crypto.h +++ b/libssh/include/libssh/crypto.h @@ -46,6 +46,8 @@ #include "libssh/kex.h" #include "libssh/curve25519.h" +#define DIGEST_MAX_LEN 64 + enum ssh_key_exchange_e { /* diffie-hellman-group1-sha1 */ SSH_KEX_DH_GROUP1_SHA1=1, @@ -79,8 +81,10 @@ struct ssh_crypto_struct { unsigned char *encryptkey; unsigned char *encryptMAC; unsigned char *decryptMAC; - unsigned char hmacbuf[EVP_MAX_MD_SIZE]; + unsigned char hmacbuf[DIGEST_MAX_LEN]; struct ssh_cipher_struct *in_cipher, *out_cipher; /* the cipher structures/objects */ + enum ssh_hmac_e in_hmac, out_hmac; /* the MAC algorithms used */ + ssh_string server_pubkey; const char *server_pubkey_type; int do_compress_out; /* idem */ @@ -111,9 +115,9 @@ struct ssh_cipher_struct { /* sets the new key for immediate use */ int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV); int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV); - void (*cbc_encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out, + void (*encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out, unsigned long len); - void (*cbc_decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out, + void (*decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out, unsigned long len); }; diff --git a/libssh/include/libssh/curve25519.h b/libssh/include/libssh/curve25519.h index 35e25be0..0406b9ee 100644 --- a/libssh/include/libssh/curve25519.h +++ b/libssh/include/libssh/curve25519.h @@ -39,7 +39,10 @@ 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 */ -#define HAVE_CURVE25519 +#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]; diff --git a/libssh/include/libssh/dh.h b/libssh/include/libssh/dh.h index e1039e24..95b76cdd 100644 --- a/libssh/include/libssh/dh.h +++ b/libssh/include/libssh/dh.h @@ -25,7 +25,6 @@ #include "libssh/crypto.h" -void ssh_print_bignum(const char *which,bignum num); int dh_generate_e(ssh_session session); int dh_generate_f(ssh_session session); int dh_generate_x(ssh_session session); @@ -48,8 +47,5 @@ int make_sessionid(ssh_session session); int hashbufin_add_cookie(ssh_session session, unsigned char *cookie); int hashbufout_add_cookie(ssh_session session); int generate_session_keys(ssh_session session); -bignum make_string_bn(ssh_string string); -ssh_string make_bignum_string(bignum num); - #endif /* DH_H_ */ diff --git a/libssh/include/libssh/ecdh.h b/libssh/include/libssh/ecdh.h index b35b2af7..8d1e7515 100644 --- a/libssh/include/libssh/ecdh.h +++ b/libssh/include/libssh/ecdh.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 */ diff --git a/libssh/include/libssh/ed25519.h b/libssh/include/libssh/ed25519.h new file mode 100644 index 00000000..7b48856c --- /dev/null +++ b/libssh/include/libssh/ed25519.h @@ -0,0 +1,79 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2014 by Aris Adamantiadis + * + * 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, or (at your option) any later version. + * + * 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 ED25519_H_ +#define ED25519_H_ +#include "libssh/priv.h" + +/** + * @defgroup ed25519 ed25519 API + * @internal + * @brief API for DJB's ed25519 + * + * @{ */ + +#define ED25519_PK_LEN 32 +#define ED25519_SK_LEN 64 +#define ED25519_SIG_LEN 64 + +typedef uint8_t ed25519_pubkey[ED25519_PK_LEN]; +typedef uint8_t ed25519_privkey[ED25519_SK_LEN]; +typedef uint8_t ed25519_signature[ED25519_SIG_LEN]; + +/** @internal + * @brief generate an ed25519 key pair + * @param[out] pk generated public key + * @param[out] sk generated secret key + * @return 0 on success, -1 on error. + * */ +int crypto_sign_ed25519_keypair(ed25519_pubkey pk, ed25519_privkey sk); + +/** @internal + * @brief sign a message with ed25519 + * @param[out] sm location to store the signed message. + * Its length should be mlen + 64. + * @param[out] smlen pointer to the size of the signed message + * @param[in] m message to be signed + * @param[in] mlen length of the message to be signed + * @param[in] sk secret key to sign the message with + * @return 0 on success. + */ +int crypto_sign_ed25519( + unsigned char *sm,unsigned long long *smlen, + const unsigned char *m,unsigned long long mlen, + const ed25519_privkey sk); + +/** @internal + * @brief "open" and verify the signature of a signed message + * @param[out] m location to store the verified message. + * Its length should be equal to smlen. + * @param[out] mlen pointer to the size of the verified message + * @param[in] sm signed message to verify + * @param[in] smlen length of the signed message to verify + * @param[in] pk public key used to sign the message + * @returns 0 on success (supposedly). + */ +int crypto_sign_ed25519_open( + unsigned char *m,unsigned long long *mlen, + const unsigned char *sm,unsigned long long smlen, + const ed25519_pubkey pk); + +/** @} */ +#endif /* ED25519_H_ */ diff --git a/libssh/include/libssh/fe25519.h b/libssh/include/libssh/fe25519.h new file mode 100644 index 00000000..e959912e --- /dev/null +++ b/libssh/include/libssh/fe25519.h @@ -0,0 +1,68 @@ +/* $OpenBSD: fe25519.h,v 1.3 2013/12/09 11:03:45 markus Exp $ */ + +/* + * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange, + * Peter Schwabe, Bo-Yin Yang. + * Copied from supercop-20130419/crypto_sign/ed25519/ref/fe25519.h + */ + +#ifndef FE25519_H +#define FE25519_H + +#include "libssh/priv.h" + +#define fe25519 crypto_sign_ed25519_ref_fe25519 +#define fe25519_freeze crypto_sign_ed25519_ref_fe25519_freeze +#define fe25519_unpack crypto_sign_ed25519_ref_fe25519_unpack +#define fe25519_pack crypto_sign_ed25519_ref_fe25519_pack +#define fe25519_iszero crypto_sign_ed25519_ref_fe25519_iszero +#define fe25519_iseq_vartime crypto_sign_ed25519_ref_fe25519_iseq_vartime +#define fe25519_cmov crypto_sign_ed25519_ref_fe25519_cmov +#define fe25519_setone crypto_sign_ed25519_ref_fe25519_setone +#define fe25519_setzero crypto_sign_ed25519_ref_fe25519_setzero +#define fe25519_neg crypto_sign_ed25519_ref_fe25519_neg +#define fe25519_getparity crypto_sign_ed25519_ref_fe25519_getparity +#define fe25519_add crypto_sign_ed25519_ref_fe25519_add +#define fe25519_sub crypto_sign_ed25519_ref_fe25519_sub +#define fe25519_mul crypto_sign_ed25519_ref_fe25519_mul +#define fe25519_square crypto_sign_ed25519_ref_fe25519_square +#define fe25519_invert crypto_sign_ed25519_ref_fe25519_invert +#define fe25519_pow2523 crypto_sign_ed25519_ref_fe25519_pow2523 + +typedef struct { + uint32_t v[32]; +} fe25519; + +void fe25519_freeze(fe25519 *r); + +void fe25519_unpack(fe25519 *r, const unsigned char x[32]); + +void fe25519_pack(unsigned char r[32], const fe25519 *x); + +int fe25519_iszero(const fe25519 *x); + +int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y); + +void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b); + +void fe25519_setone(fe25519 *r); + +void fe25519_setzero(fe25519 *r); + +void fe25519_neg(fe25519 *r, const fe25519 *x); + +unsigned char fe25519_getparity(const fe25519 *x); + +void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y); + +void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y); + +void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y); + +void fe25519_square(fe25519 *r, const fe25519 *x); + +void fe25519_invert(fe25519 *r, const fe25519 *x); + +void fe25519_pow2523(fe25519 *r, const fe25519 *x); + +#endif diff --git a/libssh/include/libssh/ge25519.h b/libssh/include/libssh/ge25519.h new file mode 100644 index 00000000..64f63c6f --- /dev/null +++ b/libssh/include/libssh/ge25519.h @@ -0,0 +1,43 @@ +/* $OpenBSD: ge25519.h,v 1.3 2013/12/09 11:03:45 markus Exp $ */ + +/* + * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange, + * Peter Schwabe, Bo-Yin Yang. + * Copied from supercop-20130419/crypto_sign/ed25519/ref/ge25519.h + */ + +#ifndef GE25519_H +#define GE25519_H + +#include "fe25519.h" +#include "sc25519.h" + +#define ge25519 crypto_sign_ed25519_ref_ge25519 +#define ge25519_base crypto_sign_ed25519_ref_ge25519_base +#define ge25519_unpackneg_vartime crypto_sign_ed25519_ref_unpackneg_vartime +#define ge25519_pack crypto_sign_ed25519_ref_pack +#define ge25519_isneutral_vartime crypto_sign_ed25519_ref_isneutral_vartime +#define ge25519_double_scalarmult_vartime crypto_sign_ed25519_ref_double_scalarmult_vartime +#define ge25519_scalarmult_base crypto_sign_ed25519_ref_scalarmult_base + +typedef struct +{ + fe25519 x; + fe25519 y; + fe25519 z; + fe25519 t; +} ge25519; + +const ge25519 ge25519_base; + +int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]); + +void ge25519_pack(unsigned char r[32], const ge25519 *p); + +int ge25519_isneutral_vartime(const ge25519 *p); + +void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const sc25519 *s1, const ge25519 *p2, const sc25519 *s2); + +void ge25519_scalarmult_base(ge25519 *r, const sc25519 *s); + +#endif diff --git a/libssh/include/libssh/knownhosts.h b/libssh/include/libssh/knownhosts.h new file mode 100644 index 00000000..723c7ebc --- /dev/null +++ b/libssh/include/libssh/knownhosts.h @@ -0,0 +1,27 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 20014 by Aris Adamantiadis + * + * 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_ */ diff --git a/libssh/include/libssh/legacy.h b/libssh/include/libssh/legacy.h index 771fe56f..911173ee 100644 --- a/libssh/include/libssh/legacy.h +++ b/libssh/include/libssh/legacy.h @@ -42,51 +42,51 @@ LIBSSH_API int ssh_userauth_autopubkey(ssh_session session, const char *passphra LIBSSH_API int ssh_userauth_privatekey_file(ssh_session session, const char *username, const char *filename, const char *passphrase); -LIBSSH_API void buffer_free(ssh_buffer buffer); -LIBSSH_API void *buffer_get(ssh_buffer buffer); -LIBSSH_API uint32_t buffer_get_len(ssh_buffer buffer); -LIBSSH_API ssh_buffer buffer_new(void); +SSH_DEPRECATED LIBSSH_API void buffer_free(ssh_buffer buffer); +SSH_DEPRECATED LIBSSH_API void *buffer_get(ssh_buffer buffer); +SSH_DEPRECATED LIBSSH_API uint32_t buffer_get_len(ssh_buffer buffer); +SSH_DEPRECATED LIBSSH_API ssh_buffer buffer_new(void); -LIBSSH_API ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms); -LIBSSH_API int channel_change_pty_size(ssh_channel channel,int cols,int rows); -LIBSSH_API ssh_channel channel_forward_accept(ssh_session session, int timeout_ms); -LIBSSH_API int channel_close(ssh_channel channel); -LIBSSH_API int channel_forward_cancel(ssh_session session, const char *address, int port); -LIBSSH_API int channel_forward_listen(ssh_session session, const char *address, int port, int *bound_port); -LIBSSH_API void channel_free(ssh_channel channel); -LIBSSH_API int channel_get_exit_status(ssh_channel channel); -LIBSSH_API ssh_session channel_get_session(ssh_channel channel); -LIBSSH_API int channel_is_closed(ssh_channel channel); -LIBSSH_API int channel_is_eof(ssh_channel channel); -LIBSSH_API int channel_is_open(ssh_channel channel); -LIBSSH_API ssh_channel channel_new(ssh_session session); -LIBSSH_API int channel_open_forward(ssh_channel channel, const char *remotehost, +SSH_DEPRECATED LIBSSH_API ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms); +SSH_DEPRECATED LIBSSH_API int channel_change_pty_size(ssh_channel channel,int cols,int rows); +SSH_DEPRECATED LIBSSH_API ssh_channel channel_forward_accept(ssh_session session, int timeout_ms); +SSH_DEPRECATED LIBSSH_API int channel_close(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_forward_cancel(ssh_session session, const char *address, int port); +SSH_DEPRECATED LIBSSH_API int channel_forward_listen(ssh_session session, const char *address, int port, int *bound_port); +SSH_DEPRECATED LIBSSH_API void channel_free(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_get_exit_status(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API ssh_session channel_get_session(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_is_closed(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_is_eof(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_is_open(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API ssh_channel channel_new(ssh_session session); +SSH_DEPRECATED LIBSSH_API int channel_open_forward(ssh_channel channel, const char *remotehost, int remoteport, const char *sourcehost, int localport); -LIBSSH_API int channel_open_session(ssh_channel channel); -LIBSSH_API int channel_poll(ssh_channel channel, int is_stderr); -LIBSSH_API int channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr); +SSH_DEPRECATED LIBSSH_API int channel_open_session(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_poll(ssh_channel channel, int is_stderr); +SSH_DEPRECATED LIBSSH_API int channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr); -LIBSSH_API int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, +SSH_DEPRECATED LIBSSH_API int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, int is_stderr); -LIBSSH_API int channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count, +SSH_DEPRECATED LIBSSH_API int channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count, int is_stderr); -LIBSSH_API int channel_request_env(ssh_channel channel, const char *name, const char *value); -LIBSSH_API int channel_request_exec(ssh_channel channel, const char *cmd); -LIBSSH_API int channel_request_pty(ssh_channel channel); -LIBSSH_API int channel_request_pty_size(ssh_channel channel, const char *term, +SSH_DEPRECATED LIBSSH_API int channel_request_env(ssh_channel channel, const char *name, const char *value); +SSH_DEPRECATED LIBSSH_API int channel_request_exec(ssh_channel channel, const char *cmd); +SSH_DEPRECATED LIBSSH_API int channel_request_pty(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_request_pty_size(ssh_channel channel, const char *term, int cols, int rows); -LIBSSH_API int channel_request_shell(ssh_channel channel); -LIBSSH_API int channel_request_send_signal(ssh_channel channel, const char *signum); -LIBSSH_API int channel_request_sftp(ssh_channel channel); -LIBSSH_API int channel_request_subsystem(ssh_channel channel, const char *subsystem); -LIBSSH_API int channel_request_x11(ssh_channel channel, int single_connection, const char *protocol, +SSH_DEPRECATED LIBSSH_API int channel_request_shell(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_request_send_signal(ssh_channel channel, const char *signum); +SSH_DEPRECATED LIBSSH_API int channel_request_sftp(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_request_subsystem(ssh_channel channel, const char *subsystem); +SSH_DEPRECATED LIBSSH_API int channel_request_x11(ssh_channel channel, int single_connection, const char *protocol, const char *cookie, int screen_number); -LIBSSH_API int channel_send_eof(ssh_channel channel); -LIBSSH_API int channel_select(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct +SSH_DEPRECATED LIBSSH_API int channel_send_eof(ssh_channel channel); +SSH_DEPRECATED LIBSSH_API int channel_select(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct timeval * timeout); -LIBSSH_API void channel_set_blocking(ssh_channel channel, int blocking); -LIBSSH_API int channel_write(ssh_channel channel, const void *data, uint32_t len); +SSH_DEPRECATED LIBSSH_API void channel_set_blocking(ssh_channel channel, int blocking); +SSH_DEPRECATED LIBSSH_API int channel_write(ssh_channel channel, const void *data, uint32_t len); LIBSSH_API void privatekey_free(ssh_private_key prv); LIBSSH_API ssh_private_key privatekey_from_file(ssh_session session, const char *filename, @@ -107,14 +107,14 @@ LIBSSH_API ssh_string ssh_get_pubkey(ssh_session session); LIBSSH_API ssh_message ssh_message_retrieve(ssh_session session, uint32_t packettype); LIBSSH_API ssh_public_key ssh_message_auth_publickey(ssh_message msg); -LIBSSH_API void string_burn(ssh_string str); -LIBSSH_API ssh_string string_copy(ssh_string str); -LIBSSH_API void *string_data(ssh_string str); -LIBSSH_API int string_fill(ssh_string str, const void *data, size_t len); -LIBSSH_API void string_free(ssh_string str); -LIBSSH_API ssh_string string_from_char(const char *what); -LIBSSH_API size_t string_len(ssh_string str); -LIBSSH_API ssh_string string_new(size_t size); -LIBSSH_API char *string_to_char(ssh_string str); +SSH_DEPRECATED LIBSSH_API void string_burn(ssh_string str); +SSH_DEPRECATED LIBSSH_API ssh_string string_copy(ssh_string str); +SSH_DEPRECATED LIBSSH_API void *string_data(ssh_string str); +SSH_DEPRECATED LIBSSH_API int string_fill(ssh_string str, const void *data, size_t len); +SSH_DEPRECATED LIBSSH_API void string_free(ssh_string str); +SSH_DEPRECATED LIBSSH_API ssh_string string_from_char(const char *what); +SSH_DEPRECATED LIBSSH_API size_t string_len(ssh_string str); +SSH_DEPRECATED LIBSSH_API ssh_string string_new(size_t size); +SSH_DEPRECATED LIBSSH_API char *string_to_char(ssh_string str); #endif /* LEGACY_H_ */ diff --git a/libssh/include/libssh/libcrypto.h b/libssh/include/libssh/libcrypto.h index 5cf2da28..c3783880 100644 --- a/libssh/include/libssh/libcrypto.h +++ b/libssh/include/libssh/libcrypto.h @@ -36,6 +36,8 @@ typedef SHA_CTX* SHACTX; typedef SHA256_CTX* SHA256CTX; +typedef SHA512_CTX* SHA384CTX; +typedef SHA512_CTX* SHA512CTX; typedef MD5_CTX* MD5CTX; typedef HMAC_CTX* HMACCTX; #ifdef HAVE_ECC @@ -45,6 +47,9 @@ typedef void *EVPCTX; #endif #define SHA_DIGEST_LEN SHA_DIGEST_LENGTH +#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH +#define SHA384_DIGEST_LEN SHA384_DIGEST_LENGTH +#define SHA512_DIGEST_LEN SHA512_DIGEST_LENGTH #ifdef MD5_DIGEST_LEN #undef MD5_DIGEST_LEN #endif @@ -84,6 +89,14 @@ SHA256CTX sha256_init(void); void sha256_update(SHA256CTX c, const void *data, unsigned long len); void sha256_final(unsigned char *md, SHA256CTX c); +SHA384CTX sha384_init(void); +void sha384_update(SHA384CTX c, const void *data, unsigned long len); +void sha384_final(unsigned char *md, SHA384CTX c); + +SHA512CTX sha512_init(void); +void sha512_update(SHA512CTX c, const void *data, unsigned long len); +void sha512_final(unsigned char *md, SHA512CTX c); + struct ssh_cipher_struct *ssh_get_ciphertab(void); #endif /* HAVE_LIBCRYPTO */ diff --git a/libssh/include/libssh/libgcrypt.h b/libssh/include/libssh/libgcrypt.h index c1844a53..8e52a681 100644 --- a/libssh/include/libssh/libgcrypt.h +++ b/libssh/include/libssh/libgcrypt.h @@ -27,6 +27,9 @@ #include typedef gcry_md_hd_t SHACTX; +typedef gcry_md_hd_t SHA256CTX; +typedef gcry_md_hd_t SHA384CTX; +typedef gcry_md_hd_t SHA512CTX; typedef gcry_md_hd_t MD5CTX; typedef gcry_md_hd_t HMACCTX; typedef void *EVPCTX; @@ -34,11 +37,14 @@ typedef void *EVPCTX; #define SHA_DIGEST_LEN SHA_DIGEST_LENGTH #define MD5_DIGEST_LEN 16 #define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH #define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_LEN SHA384_DIGEST_LENGTH #define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_LEN SHA512_DIGEST_LENGTH #ifndef EVP_MAX_MD_SIZE -#define EVP_MAX_MD_SIZE 36 +#define EVP_MAX_MD_SIZE 64 #endif #define EVP_DIGEST_LEN EVP_MAX_MD_SIZE diff --git a/libssh/include/libssh/libssh.h b/libssh/include/libssh/libssh.h index 3833adcd..ba4f5f44 100644 --- a/libssh/include/libssh/libssh.h +++ b/libssh/include/libssh/libssh.h @@ -104,6 +104,13 @@ extern "C" { #endif +struct ssh_counter_struct { + uint64_t in_bytes; + uint64_t out_bytes; + uint64_t in_packets; + uint64_t out_packets; +}; +typedef struct ssh_counter_struct *ssh_counter; typedef struct ssh_agent_struct* ssh_agent; typedef struct ssh_buffer_struct* ssh_buffer; @@ -245,7 +252,8 @@ enum ssh_keytypes_e{ SSH_KEYTYPE_DSS=1, SSH_KEYTYPE_RSA, SSH_KEYTYPE_RSA1, - SSH_KEYTYPE_ECDSA + SSH_KEYTYPE_ECDSA, + SSH_KEYTYPE_ED25519 }; enum ssh_keycmp_e { @@ -331,7 +339,12 @@ 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, + SSH_OPTIONS_HMAC_C_S, + SSH_OPTIONS_HMAC_S_C, }; enum { @@ -374,6 +387,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); @@ -391,6 +405,8 @@ LIBSSH_API int ssh_channel_send_eof(ssh_channel channel); LIBSSH_API int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans, ssh_channel *exceptchans, struct timeval * timeout); LIBSSH_API void ssh_channel_set_blocking(ssh_channel channel, int blocking); +LIBSSH_API void ssh_channel_set_counter(ssh_channel channel, + ssh_counter counter); LIBSSH_API int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len); LIBSSH_API uint32_t ssh_channel_window_size(ssh_channel channel); @@ -401,9 +417,19 @@ LIBSSH_API const char *ssh_copyright(void); 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 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); + +/* REVERSE PORT FORWARDING */ +LIBSSH_API ssh_channel ssh_channel_accept_forward(ssh_session session, + int timeout_ms, + int *destination_port); +LIBSSH_API int ssh_channel_cancel_forward(ssh_session session, + const char *address, + int port); +LIBSSH_API int ssh_channel_listen_forward(ssh_session session, + const char *address, + int port, + int *bound_port); + LIBSSH_API void ssh_free(ssh_session session); LIBSSH_API const char *ssh_get_disconnect_message(ssh_session session); LIBSSH_API const char *ssh_get_error(void *error); @@ -424,11 +450,17 @@ LIBSSH_API int ssh_get_publickey_hash(const ssh_key key, unsigned char **hash, size_t *hlen); +/* DEPRECATED FUNCTIONS */ SSH_DEPRECATED LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash); +SSH_DEPRECATED LIBSSH_API ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms); +SSH_DEPRECATED LIBSSH_API int ssh_forward_cancel(ssh_session session, const char *address, int port); +SSH_DEPRECATED LIBSSH_API int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port); + 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); @@ -509,6 +541,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, @@ -523,6 +560,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); @@ -550,6 +589,8 @@ LIBSSH_API int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socke LIBSSH_API int ssh_service_request(ssh_session session, const char *service); LIBSSH_API int ssh_set_agent_channel(ssh_session session, ssh_channel channel); LIBSSH_API void ssh_set_blocking(ssh_session session, int blocking); +LIBSSH_API void ssh_set_counters(ssh_session session, ssh_counter scounter, + ssh_counter rcounter); LIBSSH_API void ssh_set_fd_except(ssh_session session); LIBSSH_API void ssh_set_fd_toread(ssh_session session); LIBSSH_API void ssh_set_fd_towrite(ssh_session session); @@ -615,7 +656,12 @@ 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); +LIBSSH_API const char* ssh_get_hmac_in(ssh_session session); +LIBSSH_API const char* ssh_get_hmac_out(ssh_session session); #ifndef LIBSSH_LEGACY_0_4 #include "libssh/legacy.h" diff --git a/libssh/include/libssh/libsshpp.hpp b/libssh/include/libssh/libsshpp.hpp index 1a5d80a9..af08a914 100644 --- a/libssh/include/libssh/libsshpp.hpp +++ b/libssh/include/libssh/libsshpp.hpp @@ -56,6 +56,7 @@ #include #include #include +#include namespace ssh { @@ -361,18 +362,18 @@ 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); + int err=ssh_channel_cancel_forward(c_session, address, port); ssh_throw(err); return_throwable; } void_throwable listenForward(const char *address, int port, int &boundport){ - int err=ssh_forward_listen(c_session, address, port, &boundport); + int err=ssh_channel_listen_forward(c_session, address, port, &boundport); ssh_throw(err); return_throwable; } @@ -480,12 +481,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; } @@ -581,10 +600,9 @@ private: }; -/* This code cannot be put inline due to references to Channel */ -Channel *Session::acceptForward(int timeout_ms){ - ssh_channel forward = ssh_forward_accept(c_session, - timeout_ms); +inline Channel *Session::acceptForward(int timeout_ms){ + ssh_channel forward = + ssh_channel_accept_forward(c_session, timeout_ms, NULL); ssh_throw_null(c_session,forward); Channel *newchan = new Channel(*this,forward); return newchan; diff --git a/libssh/include/libssh/packet.h b/libssh/include/libssh/packet.h index 513eaa81..d8ef35bb 100644 --- a/libssh/include/libssh/packet.h +++ b/libssh/include/libssh/packet.h @@ -21,6 +21,8 @@ #ifndef PACKET_H_ #define PACKET_H_ +#include "libssh/wrapper.h" + struct ssh_socket_struct; /* this structure should go someday */ @@ -82,6 +84,6 @@ unsigned char *packet_encrypt(ssh_session session, void *packet, unsigned int len); int packet_hmac_verify(ssh_session session,ssh_buffer buffer, - unsigned char *mac); + unsigned char *mac, enum ssh_hmac_e type); #endif /* PACKET_H_ */ diff --git a/libssh/include/libssh/pki.h b/libssh/include/libssh/pki.h index 89a0f982..9f9ddf4a 100644 --- a/libssh/include/libssh/pki.h +++ b/libssh/include/libssh/pki.h @@ -21,6 +21,7 @@ #ifndef PKI_H_ #define PKI_H_ +#include "libssh/priv.h" #ifdef HAVE_OPENSSL_EC_H #include #endif @@ -29,6 +30,7 @@ #endif #include "libssh/crypto.h" +#include "libssh/ed25519.h" #define MAX_PUBKEY_SIZE 0x100000 /* 1M */ #define MAX_PRIVKEY_SIZE 0x400000 /* 4M */ @@ -55,6 +57,8 @@ struct ssh_key_struct { void *ecdsa; #endif /* HAVE_OPENSSL_EC_H */ #endif + ed25519_pubkey *ed25519_pubkey; + ed25519_privkey *ed25519_privkey; void *cert; }; @@ -74,6 +78,7 @@ struct ssh_signature_struct { void *ecdsa_sig; # endif #endif + ed25519_signature *ed25519_sig; }; typedef struct ssh_signature_struct *ssh_signature; diff --git a/libssh/include/libssh/pki_priv.h b/libssh/include/libssh/pki_priv.h index 2c361e43..0aaadb60 100644 --- a/libssh/include/libssh/pki_priv.h +++ b/libssh/include/libssh/pki_priv.h @@ -34,12 +34,15 @@ 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); int pki_key_generate_rsa(ssh_key key, int parameter); int pki_key_generate_dss(ssh_key key, int parameter); int pki_key_generate_ecdsa(ssh_key key, int parameter); +int pki_key_generate_ed25519(ssh_key key); + int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what); @@ -51,6 +54,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, @@ -85,4 +93,16 @@ ssh_signature pki_do_sign(const ssh_key privkey, ssh_signature pki_do_sign_sessionid(const ssh_key key, const unsigned char *hash, size_t hlen); +int pki_ed25519_sign(const ssh_key privkey, ssh_signature sig, + const unsigned char *hash, size_t hlen); +int pki_ed25519_verify(const ssh_key pubkey, ssh_signature sig, + const unsigned char *hash, size_t hlen); +int pki_ed25519_key_cmp(const ssh_key k1, + const ssh_key k2, + enum ssh_keycmp_e what); +int pki_ed25519_key_dup(ssh_key new, const ssh_key key); +int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key); +ssh_string pki_ed25519_sig_to_blob(ssh_signature sig); +int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob); + #endif /* PKI_PRIV_H_ */ diff --git a/libssh/include/libssh/priv.h b/libssh/include/libssh/priv.h index d8176d90..0e3bab5b 100644 --- a/libssh/include/libssh/priv.h +++ b/libssh/include/libssh/priv.h @@ -120,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) @@ -155,16 +168,6 @@ int gettimeofday(struct timeval *__p, void *__t); #include #endif -/* - * get rid of deprecacy warnings on OSX when using OpenSSL - */ -#if defined(__APPLE__) - #ifdef MAC_OS_X_VERSION_MIN_REQUIRED - #undef MAC_OS_X_VERSION_MIN_REQUIRED - #endif - #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6 -#endif - /* forward declarations */ struct ssh_common_struct; struct ssh_kex_struct; @@ -275,7 +278,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 */ diff --git a/libssh/include/libssh/sc25519.h b/libssh/include/libssh/sc25519.h new file mode 100644 index 00000000..5a2c1b85 --- /dev/null +++ b/libssh/include/libssh/sc25519.h @@ -0,0 +1,74 @@ +/* $OpenBSD: sc25519.h,v 1.3 2013/12/09 11:03:45 markus Exp $ */ + +/* + * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange, + * Peter Schwabe, Bo-Yin Yang. + * Copied from supercop-20130419/crypto_sign/ed25519/ref/sc25519.h + */ + +#ifndef SC25519_H +#define SC25519_H + +#define sc25519 crypto_sign_ed25519_ref_sc25519 +#define shortsc25519 crypto_sign_ed25519_ref_shortsc25519 +#define sc25519_from32bytes crypto_sign_ed25519_ref_sc25519_from32bytes +#define shortsc25519_from16bytes crypto_sign_ed25519_ref_shortsc25519_from16bytes +#define sc25519_from64bytes crypto_sign_ed25519_ref_sc25519_from64bytes +#define sc25519_from_shortsc crypto_sign_ed25519_ref_sc25519_from_shortsc +#define sc25519_to32bytes crypto_sign_ed25519_ref_sc25519_to32bytes +#define sc25519_iszero_vartime crypto_sign_ed25519_ref_sc25519_iszero_vartime +#define sc25519_isshort_vartime crypto_sign_ed25519_ref_sc25519_isshort_vartime +#define sc25519_lt_vartime crypto_sign_ed25519_ref_sc25519_lt_vartime +#define sc25519_add crypto_sign_ed25519_ref_sc25519_add +#define sc25519_sub_nored crypto_sign_ed25519_ref_sc25519_sub_nored +#define sc25519_mul crypto_sign_ed25519_ref_sc25519_mul +#define sc25519_mul_shortsc crypto_sign_ed25519_ref_sc25519_mul_shortsc +#define sc25519_window3 crypto_sign_ed25519_ref_sc25519_window3 +#define sc25519_window5 crypto_sign_ed25519_ref_sc25519_window5 +#define sc25519_2interleave2 crypto_sign_ed25519_ref_sc25519_2interleave2 + +typedef struct { + uint32_t v[32]; +} sc25519; + +typedef struct { + uint32_t v[16]; +} shortsc25519; + +void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]); + +void shortsc25519_from16bytes(shortsc25519 *r, const unsigned char x[16]); + +void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]); + +void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x); + +void sc25519_to32bytes(unsigned char r[32], const sc25519 *x); + +int sc25519_iszero_vartime(const sc25519 *x); + +int sc25519_isshort_vartime(const sc25519 *x); + +int sc25519_lt_vartime(const sc25519 *x, const sc25519 *y); + +void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y); + +void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y); + +void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y); + +void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y); + +/* Convert s into a representation of the form \sum_{i=0}^{84}r[i]2^3 + * with r[i] in {-4,...,3} + */ +void sc25519_window3(signed char r[85], const sc25519 *s); + +/* Convert s into a representation of the form \sum_{i=0}^{50}r[i]2^5 + * with r[i] in {-16,...,15} + */ +void sc25519_window5(signed char r[51], const sc25519 *s); + +void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2); + +#endif diff --git a/libssh/include/libssh/server.h b/libssh/include/libssh/server.h index 9d095feb..385a10a7 100644 --- a/libssh/include/libssh/server.h +++ b/libssh/include/libssh/server.h @@ -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); diff --git a/libssh/include/libssh/session.h b/libssh/include/libssh/session.h index 281c7c66..29bdd60b 100644 --- a/libssh/include/libssh/session.h +++ b/libssh/include/libssh/session.h @@ -127,6 +127,15 @@ struct ssh_session_struct { struct ssh_agent_state_struct *agent_state; struct ssh_auth_auto_state_struct *auth_auto_state; + /* + * RFC 4253, 7.1: if the first_kex_packet_follows flag was set in + * the received SSH_MSG_KEXINIT, but the guess was wrong, this + * field will be set such that the following guessed packet will + * be ignored. Once that packet has been received and ignored, + * this field is cleared. + */ + int first_kex_follows_guess_wrong; + ssh_buffer in_hashbuf; ssh_buffer out_hashbuf; struct ssh_crypto_struct *current_crypto; @@ -175,6 +184,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; @@ -183,7 +193,13 @@ struct ssh_session_struct { int ssh2; int ssh1; char compressionlevel; + char *gss_server_identity; + char *gss_client_identity; + int gss_delegate_creds; } opts; + /* counters */ + ssh_counter socket_counter; + ssh_counter raw_counter; }; /** @internal diff --git a/libssh/include/libssh/sftp.h b/libssh/include/libssh/sftp.h index d370f0ec..8fb8f116 100644 --- a/libssh/include/libssh/sftp.h +++ b/libssh/include/libssh/sftp.h @@ -143,10 +143,10 @@ struct sftp_request_queue_struct { /* SSH_FXP_MESSAGE described into .7 page 26 */ struct sftp_status_message_struct { - uint32_t id; - uint32_t status; - ssh_string error; - ssh_string lang; + uint32_t id; + uint32_t status; + ssh_string error_unused; /* not used anymore */ + ssh_string lang_unused; /* not used anymore */ char *errormsg; char *langmsg; }; diff --git a/libssh/include/libssh/socket.h b/libssh/include/libssh/socket.h index 285a02e3..8e1eac21 100644 --- a/libssh/include/libssh/socket.h +++ b/libssh/include/libssh/socket.h @@ -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); diff --git a/libssh/include/libssh/wrapper.h b/libssh/include/libssh/wrapper.h index 7374a88a..a327e188 100644 --- a/libssh/include/libssh/wrapper.h +++ b/libssh/include/libssh/wrapper.h @@ -22,6 +22,7 @@ #define WRAPPER_H_ #include "config.h" +#include "libssh/libssh.h" #include "libssh/libcrypto.h" #include "libssh/libgcrypt.h" @@ -34,6 +35,9 @@ enum ssh_mac_e { enum ssh_hmac_e { SSH_HMAC_SHA1 = 1, + SSH_HMAC_SHA256, + SSH_HMAC_SHA384, + SSH_HMAC_SHA512, SSH_HMAC_MD5 }; @@ -42,16 +46,36 @@ enum ssh_des_e { SSH_DES }; +struct ssh_hmac_struct { + const char* name; + enum ssh_hmac_e hmac_type; +}; + typedef struct ssh_mac_ctx_struct *ssh_mac_ctx; MD5CTX md5_init(void); void md5_update(MD5CTX c, const void *data, unsigned long len); void md5_final(unsigned char *md,MD5CTX c); + SHACTX sha1_init(void); void sha1_update(SHACTX c, const void *data, unsigned long len); void sha1_final(unsigned char *md,SHACTX c); void sha1(unsigned char *digest,int len,unsigned char *hash); + +SHA256CTX sha256_init(void); +void sha256_update(SHA256CTX c, const void *data, unsigned long len); +void sha256_final(unsigned char *md,SHA256CTX c); void sha256(unsigned char *digest, int len, unsigned char *hash); +SHA384CTX sha384_init(void); +void sha384_update(SHA384CTX c, const void *data, unsigned long len); +void sha384_final(unsigned char *md,SHA384CTX c); +void sha384(unsigned char *digest, int len, unsigned char *hash); + +SHA512CTX sha512_init(void); +void sha512_update(SHA512CTX c, const void *data, unsigned long len); +void sha512_final(unsigned char *md,SHA512CTX c); +void sha512(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); @@ -64,11 +88,16 @@ void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx); HMACCTX hmac_init(const void *key,int len, enum ssh_hmac_e type); void hmac_update(HMACCTX c, const void *data, unsigned long len); void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len); +size_t hmac_digest_len(enum ssh_hmac_e type); int crypt_set_algorithms(ssh_session session, enum ssh_des_e des_type); int crypt_set_algorithms_server(ssh_session session); struct ssh_crypto_struct *crypto_new(void); void crypto_free(struct ssh_crypto_struct *crypto); +void ssh_reseed(void); + +struct ssh_hmac_struct *ssh_get_hmactab(void); +const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type); #endif /* WRAPPER_H_ */ diff --git a/libssh/libssh-config.cmake.in b/libssh/libssh-config.cmake.in index 1e287fae..fa9cecf8 100644 --- a/libssh/libssh-config.cmake.in +++ b/libssh/libssh-config.cmake.in @@ -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@) diff --git a/libssh/build/build_make.sh b/libssh/obj/build_make.sh similarity index 98% rename from libssh/build/build_make.sh rename to libssh/obj/build_make.sh index ba03c99c..2f2e4a6c 100755 --- a/libssh/build/build_make.sh +++ b/libssh/obj/build_make.sh @@ -4,7 +4,7 @@ # # Script to build libssh on UNIX. # -# Copyright (c) 2006-2007 Andreas Schneider +# Copyright (c) 2006-2007 Andreas Schneider # SOURCE_DIR=".." diff --git a/libssh/src/CMakeLists.txt b/libssh/src/CMakeLists.txt index 83435d0c..a4bc8595 100644 --- a/libssh/src/CMakeLists.txt +++ b/libssh/src/CMakeLists.txt @@ -28,7 +28,7 @@ if (HAVE_LIBSOCKET) ) endif (HAVE_LIBSOCKET) -if (OPENSSL_LIBRARIES) +if (OPENSSL_CRYPTO_LIBRARIES) set(LIBSSH_PRIVATE_INCLUDE_DIRS ${LIBSSH_PRIVATE_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS} @@ -36,9 +36,9 @@ if (OPENSSL_LIBRARIES) set(LIBSSH_LINK_LIBRARIES ${LIBSSH_LINK_LIBRARIES} - ${OPENSSL_LIBRARIES} + ${OPENSSL_CRYPTO_LIBRARIES} ) -endif (OPENSSL_LIBRARIES) +endif (OPENSSL_CRYPTO_LIBRARIES) if (GCRYPT_LIBRARY) set(LIBSSH_PRIVATE_INCLUDE_DIRS @@ -109,6 +109,7 @@ set(libssh_SRCS agent.c auth.c base64.c + bignum.c buffer.c callbacks.c channels.c @@ -118,7 +119,10 @@ set(libssh_SRCS curve25519.c dh.c ecdh.c + ed25519.c error.c + fe25519.c + ge25519.c getpass.c init.c kex.c @@ -135,8 +139,10 @@ set(libssh_SRCS packet_crypt.c pcap.c pki.c + pki_ed25519.c poll.c session.c + sc25519.c scp.c socket.c string.c @@ -288,6 +294,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) diff --git a/libssh/src/agent.c b/libssh/src/agent.c index 1b094ed4..d5257604 100644 --- a/libssh/src/agent.c +++ b/libssh/src/agent.c @@ -3,7 +3,7 @@ * * This file is part of the SSH Library * - * Copyright (c) 2008-2009 by Andreas Schneider + * Copyright (c) 2008-2013 by Andreas Schneider * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -300,7 +300,7 @@ static int agent_talk(struct ssh_session_struct *session, "Error reading response from authentication socket."); return -1; } - if (buffer_add_data(reply, payload, n) < 0) { + if (ssh_buffer_add_data(reply, payload, n) < 0) { SSH_LOG(SSH_LOG_WARN, "Not enough space"); return -1; } @@ -393,7 +393,7 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) { } if (session->agent->ident) { - buffer_reinit(session->agent->ident); + ssh_buffer_reinit(session->agent->ident); } session->agent->ident = reply; @@ -526,7 +526,7 @@ ssh_string ssh_agent_sign_data(ssh_session session, ssh_buffer_free(request); return NULL; } - if (buffer_add_data(request, buffer_get_rest(data), dlen) < 0) { + if (ssh_buffer_add_data(request, buffer_get_rest(data), dlen) < 0) { ssh_buffer_free(request); return NULL; } diff --git a/libssh/src/auth.c b/libssh/src/auth.c index 6664c203..d56111d2 100644 --- a/libssh/src/auth.c +++ b/libssh/src/auth.c @@ -3,8 +3,8 @@ * * This file is part of the SSH Library * - * Copyright (c) 2003-2011 by Aris Adamantiadis - * Copyright (c) 2008-2011 Andreas Schneider + * Copyright (c) 2003-2013 by Aris Adamantiadis + * Copyright (c) 2008-2013 Andreas Schneider * * 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 @@ -182,25 +182,19 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_banner){ */ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){ char *auth_methods = NULL; - ssh_string auth; uint8_t partial = 0; + int rc; (void) type; (void) user; - auth = buffer_get_ssh_string(packet); - if (auth == NULL || buffer_get_u8(packet, &partial) != 1) { + rc = ssh_buffer_unpack(packet, "sb", &auth_methods, &partial); + if (rc != SSH_OK) { ssh_set_error(session, SSH_FATAL, "Invalid SSH_MSG_USERAUTH_FAILURE message"); session->auth_state=SSH_AUTH_STATE_ERROR; goto end; } - auth_methods = ssh_string_to_char(auth); - if (auth_methods == NULL) { - ssh_set_error_oom(session); - goto end; - } - if (partial) { session->auth_state=SSH_AUTH_STATE_PARTIAL; SSH_LOG(SSH_LOG_INFO, @@ -234,7 +228,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure){ } end: - ssh_string_free(auth); SAFE_FREE(auth_methods); return SSH_PACKET_USED; @@ -359,7 +352,6 @@ int ssh_userauth_list(ssh_session session, const char *username) * before you connect to the server. */ int ssh_userauth_none(ssh_session session, const char *username) { - ssh_string str; int rc; #ifdef WITH_SSH1 @@ -387,47 +379,12 @@ int ssh_userauth_none(ssh_session session, const char *username) { } /* request */ - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); - if (rc < 0) { - goto fail; - } - - /* username */ - if (username) { - str = ssh_string_from_char(username); - } else { - str = ssh_string_from_char(session->opts.username); - } - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* service */ - str = ssh_string_from_char("ssh-connection"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* method */ - str = ssh_string_from_char("none"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); + rc = ssh_buffer_pack(session->out_buffer, "bsss", + SSH2_MSG_USERAUTH_REQUEST, + username ? username : session->opts.username, + "ssh-connection", + "none" + ); if (rc < 0) { goto fail; } @@ -448,7 +405,7 @@ pending: return rc; fail: ssh_set_error_oom(session); - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_AUTH_ERROR; } @@ -485,7 +442,7 @@ int ssh_userauth_try_publickey(ssh_session session, const char *username, const ssh_key pubkey) { - ssh_string str; + ssh_string pubkey_s = NULL; int rc; if (session == NULL) { @@ -522,82 +479,28 @@ int ssh_userauth_try_publickey(ssh_session session, return SSH_AUTH_ERROR; } - /* request */ - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); - if (rc < 0) { - goto fail; - } - - /* username */ - if (username) { - str = ssh_string_from_char(username); - } else { - str = ssh_string_from_char(session->opts.username); - } - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* service */ - str = ssh_string_from_char("ssh-connection"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* method */ - str = ssh_string_from_char("publickey"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* private key? */ - rc = buffer_add_u8(session->out_buffer, 0); - if (rc < 0) { - goto fail; - } - - /* algo */ - str = ssh_string_from_char(pubkey->type_c); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - /* public key */ - rc = ssh_pki_export_pubkey_blob(pubkey, &str); + rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s); if (rc < 0) { goto fail; } - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); + /* request */ + rc = ssh_buffer_pack(session->out_buffer, "bsssbsS", + SSH2_MSG_USERAUTH_REQUEST, + username ? username : session->opts.username, + "ssh-connection", + "publickey", + 0, /* private key ? */ + pubkey->type_c, /* algo */ + pubkey_s /* public key */ + ); if (rc < 0) { goto fail; } + ssh_string_free(pubkey_s); + session->auth_state = SSH_AUTH_STATE_NONE; session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY; rc = packet_send(session); @@ -613,8 +516,9 @@ pending: return rc; fail: + ssh_string_free(pubkey_s); ssh_set_error_oom(session); - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_AUTH_ERROR; } @@ -647,7 +551,7 @@ int ssh_userauth_publickey(ssh_session session, const char *username, const ssh_key privkey) { - ssh_string str; + ssh_string str = NULL; int rc; if (session == NULL) { @@ -684,81 +588,26 @@ int ssh_userauth_publickey(ssh_session session, return SSH_AUTH_ERROR; } - /* request */ - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); - if (rc < 0) { - goto fail; - } - - /* username */ - if (username) { - str = ssh_string_from_char(username); - } else { - str = ssh_string_from_char(session->opts.username); - } - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* service */ - str = ssh_string_from_char("ssh-connection"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* method */ - str = ssh_string_from_char("publickey"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* private key? */ - rc = buffer_add_u8(session->out_buffer, 1); - if (rc < 0) { - goto fail; - } - - /* algo */ - str = ssh_string_from_char(privkey->type_c); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - /* public key */ rc = ssh_pki_export_pubkey_blob(privkey, &str); if (rc < 0) { goto fail; } - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); + /* request */ + rc = ssh_buffer_pack(session->out_buffer, "bsssbsS", + SSH2_MSG_USERAUTH_REQUEST, + username ? username : session->opts.username, + "ssh-connection", + "publickey", + 1, /* private key */ + privkey->type_c, /* algo */ + str /* public key */ + ); if (rc < 0) { goto fail; } + ssh_string_free(str); /* sign the buffer with the private key */ str = ssh_pki_do_sign(session, session->out_buffer, privkey); @@ -768,6 +617,7 @@ int ssh_userauth_publickey(ssh_session session, rc = buffer_add_ssh_string(session->out_buffer, str); ssh_string_free(str); + str = NULL; if (rc < 0) { goto fail; } @@ -787,8 +637,9 @@ pending: return rc; fail: + ssh_string_free(str); ssh_set_error_oom(session); - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_AUTH_ERROR; } @@ -798,7 +649,7 @@ static int ssh_userauth_agent_publickey(ssh_session session, const char *username, ssh_key pubkey) { - ssh_string str; + ssh_string str = NULL; int rc; switch(session->pending_call_state) { @@ -820,69 +671,6 @@ static int ssh_userauth_agent_publickey(ssh_session session, return SSH_AUTH_ERROR; } - /* request */ - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); - if (rc < 0) { - goto fail; - } - - /* username */ - if (username) { - str = ssh_string_from_char(username); - } else { - str = ssh_string_from_char(session->opts.username); - } - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* service */ - str = ssh_string_from_char("ssh-connection"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* method */ - str = ssh_string_from_char("publickey"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* private key? */ - rc = buffer_add_u8(session->out_buffer, 1); - if (rc < 0) { - goto fail; - } - - /* algo */ - str = ssh_string_from_char(pubkey->type_c); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } /* public key */ rc = ssh_pki_export_pubkey_blob(pubkey, &str); @@ -890,12 +678,22 @@ static int ssh_userauth_agent_publickey(ssh_session session, goto fail; } - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); + /* request */ + rc = ssh_buffer_pack(session->out_buffer, "bsssbsS", + SSH2_MSG_USERAUTH_REQUEST, + username ? username : session->opts.username, + "ssh-connection", + "publickey", + 1, /* private key */ + pubkey->type_c, /* algo */ + str /* public key */ + ); if (rc < 0) { goto fail; } + ssh_string_free(str); + /* sign the buffer with the private key */ str = ssh_pki_do_sign_agent(session, session->out_buffer, pubkey); if (str == NULL) { @@ -924,7 +722,8 @@ pending: return rc; fail: ssh_set_error_oom(session); - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); + ssh_string_free(str); return SSH_AUTH_ERROR; } @@ -1306,7 +1105,6 @@ int ssh_userauth_publickey_auto(ssh_session session, int ssh_userauth_password(ssh_session session, const char *username, const char *password) { - ssh_string str; int rc; #ifdef WITH_SSH1 @@ -1336,65 +1134,14 @@ int ssh_userauth_password(ssh_session session, } /* request */ - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); - if (rc < 0) { - goto fail; - } - - /* username */ - if (username) { - str = ssh_string_from_char(username); - } else { - str = ssh_string_from_char(session->opts.username); - } - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* service */ - str = ssh_string_from_char("ssh-connection"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* method */ - str = ssh_string_from_char("password"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* FALSE */ - rc = buffer_add_u8(session->out_buffer, 0); - if (rc < 0) { - goto fail; - } - - /* password */ - str = ssh_string_from_char(password); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); + rc = ssh_buffer_pack(session->out_buffer, "bsssbs", + SSH2_MSG_USERAUTH_REQUEST, + username ? username : session->opts.username, + "ssh-connection", + "password", + 0, /* false */ + password + ); if (rc < 0) { goto fail; } @@ -1415,7 +1162,7 @@ pending: return rc; fail: ssh_set_error_oom(session); - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_AUTH_ERROR; } @@ -1536,7 +1283,6 @@ static int ssh_userauth_kbdint_init(ssh_session session, const char *username, const char *submethods) { - ssh_string str; int rc; if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_INIT) goto pending; @@ -1552,78 +1298,18 @@ static int ssh_userauth_kbdint_init(ssh_session session, } /* request */ - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); + rc = ssh_buffer_pack(session->out_buffer, "bsssss", + SSH2_MSG_USERAUTH_REQUEST, + username ? username : session->opts.username, + "ssh-connection", + "keyboard-interactive", + "", /* lang (ignore it) */ + submethods ? submethods : "" + ); if (rc < 0) { goto fail; } - /* username */ - if (username) { - str = ssh_string_from_char(username); - } else { - str = ssh_string_from_char(session->opts.username); - } - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* service */ - str = ssh_string_from_char("ssh-connection"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* method */ - str = ssh_string_from_char("keyboard-interactive"); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* lang string (ignore it) */ - str = ssh_string_from_char(""); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - - /* submethods */ - if (submethods == NULL) { - submethods = ""; - } - - str = ssh_string_from_char(submethods); - if (str == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } session->auth_state = SSH_AUTH_STATE_KBDINT_SENT; session->pending_call_state = SSH_PENDING_CALL_AUTH_KBDINT_INIT; @@ -1642,7 +1328,7 @@ pending: return rc; fail: ssh_set_error_oom(session); - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_AUTH_ERROR; } @@ -1660,7 +1346,6 @@ fail: */ static int ssh_userauth_kbdint_send(ssh_session session) { - ssh_string answer; uint32_t i; int rc; if (session->pending_call_state == SSH_PENDING_CALL_AUTH_KBDINT_SEND) @@ -1669,29 +1354,17 @@ static int ssh_userauth_kbdint_send(ssh_session session) ssh_set_error_invalid(session); return SSH_ERROR; } - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE); - if (rc < 0) { - goto fail; - } - - rc = buffer_add_u32(session->out_buffer, htonl(session->kbdint->nprompts)); + rc = ssh_buffer_pack(session->out_buffer, "bd", + SSH2_MSG_USERAUTH_INFO_RESPONSE, + session->kbdint->nprompts); if (rc < 0) { goto fail; } for (i = 0; i < session->kbdint->nprompts; i++) { - if (session->kbdint->answers && session->kbdint->answers[i]) { - answer = ssh_string_from_char(session->kbdint->answers[i]); - } else { - answer = ssh_string_from_char(""); - } - if (answer == NULL) { - goto fail; - } - - rc = buffer_add_ssh_string(session->out_buffer, answer); - string_burn(answer); - string_free(answer); + rc = ssh_buffer_pack(session->out_buffer, "s", + session->kbdint->answers && session->kbdint->answers[i] ? + session->kbdint->answers[i]:""); if (rc < 0) { goto fail; } @@ -1716,7 +1389,7 @@ pending: return rc; fail: ssh_set_error_oom(session); - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_AUTH_ERROR; } @@ -1728,64 +1401,41 @@ fail: * authentication state. */ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { - ssh_string name; /* name of the "asking" window showed to client */ - ssh_string instruction; - ssh_string tmp; + ssh_string tmp = NULL; uint32_t nprompts; uint32_t i; + int rc; (void)user; (void)type; - name = buffer_get_ssh_string(packet); - instruction = buffer_get_ssh_string(packet); - tmp = buffer_get_ssh_string(packet); - buffer_get_u32(packet, &nprompts); - - /* We don't care about tmp */ - ssh_string_free(tmp); - - if (name == NULL || instruction == NULL) { - ssh_string_free(name); - ssh_string_free(instruction); - ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg"); - - return SSH_PACKET_USED; - } if (session->kbdint == NULL) { session->kbdint = ssh_kbdint_new(); if (session->kbdint == NULL) { ssh_set_error_oom(session); - ssh_string_free(name); - ssh_string_free(instruction); - return SSH_PACKET_USED; } } else { ssh_kbdint_clean(session->kbdint); } - session->kbdint->name = ssh_string_to_char(name); - ssh_string_free(name); - if (session->kbdint->name == NULL) { - ssh_set_error_oom(session); - ssh_kbdint_free(session->kbdint); - ssh_string_free(instruction); + rc = ssh_buffer_unpack(packet, "ssSd", + &session->kbdint->name, /* name of the "asking" window shown to client */ + &session->kbdint->instruction, + &tmp, /* to ignore */ + &nprompts + ); - return SSH_PACKET_USED; + /* We don't care about tmp */ + ssh_string_free(tmp); + + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Invalid USERAUTH_INFO_REQUEST msg"); + ssh_kbdint_free(session->kbdint); + session->kbdint = NULL; + return SSH_PACKET_USED; } - session->kbdint->instruction = ssh_string_to_char(instruction); - ssh_string_free(instruction); - if (session->kbdint->instruction == NULL) { - ssh_set_error_oom(session); - ssh_kbdint_free(session->kbdint); - session->kbdint = NULL; - - return SSH_PACKET_USED; - } - - nprompts = ntohl(nprompts); SSH_LOG(SSH_LOG_DEBUG, "%d keyboard-interactive prompts", nprompts); if (nprompts > KBDINT_MAX_PROMPT) { @@ -1823,23 +1473,14 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_request) { memset(session->kbdint->echo, 0, nprompts); for (i = 0; i < nprompts; i++) { - tmp = buffer_get_ssh_string(packet); - buffer_get_u8(packet, &session->kbdint->echo[i]); - if (tmp == NULL) { + rc = ssh_buffer_unpack(packet, "sb", + &session->kbdint->prompts[i], + &session->kbdint->echo[i]); + if (rc == SSH_ERROR) { ssh_set_error(session, SSH_FATAL, "Short INFO_REQUEST packet"); ssh_kbdint_free(session->kbdint); session->kbdint = NULL; - return SSH_PACKET_USED; - } - session->kbdint->prompts[i] = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (session->kbdint->prompts[i] == NULL) { - ssh_set_error_oom(session); - session->kbdint->nprompts = i; - ssh_kbdint_free(session->kbdint); - session->kbdint = NULL; - return SSH_PACKET_USED; } } diff --git a/libssh/src/base64.c b/libssh/src/base64.c index ff7671c1..2a162d0b 100644 --- a/libssh/src/base64.c +++ b/libssh/src/base64.c @@ -82,13 +82,18 @@ ssh_buffer base64_to_bin(const char *source) { SAFE_FREE(base64); return NULL; } + /* + * The base64 buffer often contains sensitive data. Make sure we don't leak + * sensitive data + */ + ssh_buffer_set_secure(buffer); len = strlen(ptr); while (len > 4) { if (_base64_to_bin(block, ptr, 3) < 0) { goto error; } - if (buffer_add_data(buffer, block, 3) < 0) { + if (ssh_buffer_add_data(buffer, block, 3) < 0) { goto error; } len -= 4; @@ -112,7 +117,7 @@ ssh_buffer base64_to_bin(const char *source) { if (_base64_to_bin(block, ptr, 3) < 0) { goto error; } - if (buffer_add_data(buffer, block, 3) < 0) { + if (ssh_buffer_add_data(buffer, block, 3) < 0) { goto error; } SAFE_FREE(base64); @@ -131,7 +136,7 @@ ssh_buffer base64_to_bin(const char *source) { if (_base64_to_bin(block, ptr, 1) < 0) { goto error; } - if (buffer_add_data(buffer, block, 1) < 0) { + if (ssh_buffer_add_data(buffer, block, 1) < 0) { goto error; } SAFE_FREE(base64); @@ -149,7 +154,7 @@ ssh_buffer base64_to_bin(const char *source) { if (_base64_to_bin(block, ptr, 2) < 0) { goto error; } - if (buffer_add_data(buffer,block,2) < 0) { + if (ssh_buffer_add_data(buffer,block,2) < 0) { goto error; } SAFE_FREE(base64); diff --git a/libssh/src/bignum.c b/libssh/src/bignum.c new file mode 100644 index 00000000..14b5aa54 --- /dev/null +++ b/libssh/src/bignum.c @@ -0,0 +1,96 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2014 by Aris Adamantiadis + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include + +#include "libssh/priv.h" +#include "libssh/bignum.h" +#include "libssh/string.h" + +ssh_string make_bignum_string(bignum num) { + ssh_string ptr = NULL; + int pad = 0; + unsigned int len = bignum_num_bytes(num); + unsigned int bits = bignum_num_bits(num); + + if (len == 0) { + return NULL; + } + + /* If the first bit is set we have a negative number */ + if (!(bits % 8) && bignum_is_bit_set(num, bits - 1)) { + pad++; + } + +#ifdef DEBUG_CRYPTO + fprintf(stderr, "%d bits, %d bytes, %d padding\n", bits, len, pad); +#endif /* DEBUG_CRYPTO */ + + ptr = ssh_string_new(len + pad); + if (ptr == NULL) { + return NULL; + } + + /* We have a negative number so we need a leading zero */ + if (pad) { + ptr->data[0] = 0; + } + +#ifdef HAVE_LIBGCRYPT + bignum_bn2bin(num, len, ptr->data + pad); +#elif HAVE_LIBCRYPTO + bignum_bn2bin(num, ptr->data + pad); +#endif + + return ptr; +} + +bignum make_string_bn(ssh_string string){ + bignum bn = NULL; + unsigned int len = ssh_string_len(string); + +#ifdef DEBUG_CRYPTO + fprintf(stderr, "Importing a %d bits, %d bytes object ...\n", + len * 8, len); +#endif /* DEBUG_CRYPTO */ + +#ifdef HAVE_LIBGCRYPT + bignum_bin2bn(string->data, len, &bn); +#elif defined HAVE_LIBCRYPTO + bn = bignum_bin2bn(string->data, len, NULL); +#endif + + return bn; +} + +/* prints the bignum on stderr */ +void ssh_print_bignum(const char *which, bignum num) { +#ifdef HAVE_LIBGCRYPT + unsigned char *hex = NULL; + bignum_bn2hex(num, &hex); +#elif defined HAVE_LIBCRYPTO + char *hex = NULL; + hex = bignum_bn2hex(num); +#endif + fprintf(stderr, "%s value: ", which); + fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex); + SAFE_FREE(hex); +} diff --git a/libssh/src/bind.c b/libssh/src/bind.c index 8132e3e9..b3239462 100644 --- a/libssh/src/bind.c +++ b/libssh/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"); @@ -368,7 +394,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){ session->version = 2; /* copy options */ - for (i = 0; i < 10; ++i) { + for (i = 0; i < 10; i++) { if (sshbind->wanted_methods[i]) { session->opts.wanted_methods[i] = strdup(sshbind->wanted_methods[i]); if (session->opts.wanted_methods[i] == 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; } diff --git a/libssh/src/buffer.c b/libssh/src/buffer.c index ca120868..be25a32f 100644 --- a/libssh/src/buffer.c +++ b/libssh/src/buffer.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifndef _WIN32 #include @@ -32,6 +33,8 @@ #include "libssh/priv.h" #include "libssh/buffer.h" +#include "libssh/misc.h" +#include "libssh/bignum.h" /** * @defgroup libssh_buffer The SSH buffer functions. @@ -104,13 +107,25 @@ void ssh_buffer_free(struct ssh_buffer_struct *buffer) { if (buffer->data) { /* burn the data */ - memset(buffer->data, 0, buffer->allocated); + BURN_BUFFER(buffer->data, buffer->allocated); SAFE_FREE(buffer->data); } - memset(buffer, 'X', sizeof(*buffer)); + BURN_BUFFER(buffer, sizeof(struct ssh_buffer_struct)); SAFE_FREE(buffer); } +/** + * @brief Sets the buffer as secure. + * + * A secure buffer will never leave cleartext data in the heap + * after being reallocated or freed. + * + * @param[in] buffer buffer to set secure. + */ +void ssh_buffer_set_secure(ssh_buffer buffer){ + buffer->secure = 1; +} + static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed) { size_t smallest = 1; char *new; @@ -125,9 +140,20 @@ static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed) { smallest <<= 1; } needed = smallest; - new = realloc(buffer->data, needed); - if (new == NULL) { - return -1; + if (buffer->secure){ + new = malloc(needed); + if (new == NULL) { + return -1; + } + memcpy(new, buffer->data,buffer->used); + BURN_BUFFER(buffer->data, buffer->used); + SAFE_FREE(buffer->data); + } else { + new = realloc(buffer->data, needed); + if (new == NULL) { + buffer->data = NULL; + return -1; + } } buffer->data = new; buffer->allocated = needed; @@ -140,12 +166,20 @@ static int realloc_buffer(struct ssh_buffer_struct *buffer, size_t needed) { * @param buffer SSH buffer */ static void buffer_shift(ssh_buffer buffer){ + uint32_t burn_pos = buffer->pos; + buffer_verify(buffer); if(buffer->pos==0) return; memmove(buffer->data, buffer->data + buffer->pos, buffer->used - buffer->pos); buffer->used -= buffer->pos; buffer->pos=0; + + if (buffer->secure){ + void *ptr = buffer->data + buffer->used; + BURN_BUFFER(ptr, burn_pos); + } + buffer_verify(buffer); } @@ -158,9 +192,10 @@ static void buffer_shift(ssh_buffer buffer){ * * @return 0 on success, < 0 on error. */ -int buffer_reinit(struct ssh_buffer_struct *buffer) { +int ssh_buffer_reinit(struct ssh_buffer_struct *buffer) +{ buffer_verify(buffer); - memset(buffer->data, 0, buffer->used); + BURN_BUFFER(buffer->data, buffer->used); buffer->used = 0; buffer->pos = 0; if(buffer->allocated > 127) { @@ -185,7 +220,8 @@ int buffer_reinit(struct ssh_buffer_struct *buffer) { * * @return 0 on success, < 0 on error. */ -int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) { +int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) +{ buffer_verify(buffer); if (buffer->used + len < len) { @@ -222,7 +258,7 @@ int buffer_add_ssh_string(struct ssh_buffer_struct *buffer, uint32_t len = 0; len = ssh_string_len(string); - if (buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) { + if (ssh_buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) { return -1; } @@ -240,12 +276,16 @@ int buffer_add_ssh_string(struct ssh_buffer_struct *buffer, * * @return 0 on success, -1 on error. */ -int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data){ - if (buffer_add_data(buffer, &data, sizeof(data)) < 0) { - return -1; - } +int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data) +{ + int rc; - return 0; + rc = ssh_buffer_add_data(buffer, &data, sizeof(data)); + if (rc < 0) { + return -1; + } + + return 0; } /** @@ -259,12 +299,16 @@ int buffer_add_u32(struct ssh_buffer_struct *buffer,uint32_t data){ * * @return 0 on success, -1 on error. */ -int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data){ - if (buffer_add_data(buffer, &data, sizeof(data)) < 0) { - return -1; - } +int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data) +{ + int rc; - return 0; + rc = ssh_buffer_add_data(buffer, &data, sizeof(data)); + if (rc < 0) { + return -1; + } + + return 0; } /** @@ -278,12 +322,16 @@ int buffer_add_u16(struct ssh_buffer_struct *buffer,uint16_t data){ * * @return 0 on success, -1 on error. */ -int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data){ - if (buffer_add_data(buffer, &data, sizeof(data)) < 0) { - return -1; - } +int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data) +{ + int rc; - return 0; + rc = ssh_buffer_add_data(buffer, &data, sizeof(data)); + if (rc < 0) { + return -1; + } + + return 0; } /** @@ -297,12 +345,16 @@ int buffer_add_u64(struct ssh_buffer_struct *buffer, uint64_t data){ * * @return 0 on success, -1 on error. */ -int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data){ - if (buffer_add_data(buffer, &data, sizeof(uint8_t)) < 0) { - return -1; - } +int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data) +{ + int rc; - return 0; + rc = ssh_buffer_add_data(buffer, &data, sizeof(uint8_t)); + if (rc < 0) { + return -1; + } + + return 0; } /** @@ -360,12 +412,18 @@ int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data, * @return 0 on success, -1 on error. */ int buffer_add_buffer(struct ssh_buffer_struct *buffer, - struct ssh_buffer_struct *source) { - if (buffer_add_data(buffer, buffer_get_rest(source), buffer_get_rest_len(source)) < 0) { - return -1; - } + struct ssh_buffer_struct *source) +{ + int rc; - return 0; + rc = ssh_buffer_add_data(buffer, + buffer_get_rest(source), + buffer_get_rest_len(source)); + if (rc < 0) { + return -1; + } + + return 0; } /** @@ -621,6 +679,318 @@ struct ssh_string_struct *buffer_get_mpint(struct ssh_buffer_struct *buffer) { return str; } +/** @internal + * @brief Add multiple values in a buffer on a single function call + * @param[in] buffer The buffer to add to + * @param[in] format A format string of arguments. + * @param[in] ap A va_list of arguments. + * @returns SSH_OK on success + * SSH_ERROR on error + * @see ssh_buffer_add_format() for format list values. + */ +int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer, const char *format, va_list ap){ + int rc = SSH_ERROR; + const char *p; + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + ssh_string string; + void *data; + } o; + char *cstring; + bignum b; + size_t len; + + for (p = format; *p != '\0'; p++) { + switch(*p) { + case 'b': + o.byte = (uint8_t)va_arg(ap, unsigned int); + rc = buffer_add_u8(buffer, o.byte); + break; + case 'w': + o.word = (uint16_t)va_arg(ap, unsigned int); + o.word = htons(o.word); + rc = buffer_add_u16(buffer, o.word); + break; + case 'd': + o.dword = va_arg(ap, uint32_t); + o.dword = htonl(o.dword); + rc = buffer_add_u32(buffer, o.dword); + break; + case 'q': + o.qword = va_arg(ap, uint64_t); + o.qword = htonll(o.qword); + rc = buffer_add_u64(buffer, o.qword); + break; + case 'S': + o.string = va_arg(ap, ssh_string); + rc = buffer_add_ssh_string(buffer, o.string); + o.string = NULL; + break; + case 's': + cstring = va_arg(ap, char *); + len = strlen(cstring); + rc = buffer_add_u32(buffer, htonl(len)); + if (rc == SSH_OK){ + rc = ssh_buffer_add_data(buffer, cstring, len); + } + cstring = NULL; + break; + case 'P': + len = va_arg(ap, size_t); + o.data = va_arg(ap, void *); + rc = ssh_buffer_add_data(buffer, o.data, len); + o.data = NULL; + break; + case 'B': + b = va_arg(ap, bignum); + o.string = make_bignum_string(b); + if(o.string == NULL){ + rc = SSH_ERROR; + break; + } + rc = buffer_add_ssh_string(buffer, o.string); + SAFE_FREE(o.string); + break; + case 't': + cstring = va_arg(ap, char *); + len = strlen(cstring); + rc = ssh_buffer_add_data(buffer, cstring, len); + cstring = NULL; + break; + default: + SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p); + rc = SSH_ERROR; + } + if (rc != SSH_OK){ + break; + } + } + + if (rc != SSH_ERROR){ + /* verify that the last hidden argument is correct */ + o.dword = va_arg(ap, uint32_t); + if (o.dword != SSH_BUFFER_PACK_END){ + rc = SSH_ERROR; + } + } + return rc; +} + +/** @internal + * @brief Add multiple values in a buffer on a single function call + * @param[in] buffer The buffer to add to + * @param[in] format A format string of arguments. This string contains single + * letters describing the order and type of arguments: + * 'b': uint8_t (pushed in network byte order) + * 'w': uint16_t (pushed in network byte order) + * 'd': uint32_t (pushed in network byte order) + * 'q': uint64_t (pushed in network byte order) + * 'S': ssh_string + * 's': char * (C string, pushed as SSH string) + * 't': char * (C string, pushed as free text) + * 'P': size_t, void * (len of data, pointer to data) + * only pushes data. + * 'B': bignum (pushed as SSH string) + * @returns SSH_OK on success + * SSH_ERROR on error + * @warning when using 'P' with a constant size (e.g. 8), do not + * forget to cast to (size_t). + */ +int _ssh_buffer_pack(struct ssh_buffer_struct *buffer, const char *format, ...){ + va_list ap; + int rc; + + va_start(ap, format); + rc = ssh_buffer_pack_va(buffer, format, ap); + va_end(ap); + return rc; +} + +/** @internal + * @brief Get multiple values from a buffer on a single function call + * @param[in] buffer The buffer to get from + * @param[in] format A format string of arguments. + * @param[in] ap A va_list of arguments. + * @returns SSH_OK on success + * SSH_ERROR on error + * @see ssh_buffer_get_format() for format list values. + */ +int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer, const char *format, va_list ap){ + int rc = SSH_ERROR; + const char *p, *last; + union { + uint8_t *byte; + uint16_t *word; + uint32_t *dword; + uint64_t *qword; + ssh_string *string; + char **cstring; + void **data; + } o; + size_t len, rlen; + uint32_t u32len; + va_list ap_copy; + + /* copy the argument list in case a rollback is needed */ + va_copy(ap_copy, ap); + + for (p = format; *p != '\0'; p++) { + switch (*p) { + case 'b': + o.byte = va_arg(ap, uint8_t *); + rlen = buffer_get_u8(buffer, o.byte); + rc = rlen==1 ? SSH_OK : SSH_ERROR; + break; + case 'w': + o.word = va_arg(ap, uint16_t *); + rlen = buffer_get_data(buffer, o.word, sizeof(uint16_t)); + *o.word = ntohs(*o.word); + rc = rlen==2 ? SSH_OK : SSH_ERROR; + break; + case 'd': + o.dword = va_arg(ap, uint32_t *); + rlen = buffer_get_u32(buffer, o.dword); + *o.dword = ntohl(*o.dword); + rc = rlen==4 ? SSH_OK : SSH_ERROR; + break; + case 'q': + o.qword = va_arg(ap, uint64_t*); + rlen = buffer_get_u64(buffer, o.qword); + *o.qword = ntohll(*o.qword); + rc = rlen==8 ? SSH_OK : SSH_ERROR; + break; + case 'S': + o.string = va_arg(ap, ssh_string *); + *o.string = buffer_get_ssh_string(buffer); + rc = *o.string != NULL ? SSH_OK : SSH_ERROR; + o.string = NULL; + break; + case 's': + o.cstring = va_arg(ap, char **); + *o.cstring = NULL; + rc = buffer_get_u32(buffer, &u32len); + if (rc != 4){ + rc = SSH_ERROR; + break; + } + len = ntohl(u32len); + if (len > UINT_MAX - 1){ + rc = SSH_ERROR; + break; + } + *o.cstring = malloc(len + 1); + if (*o.cstring == NULL){ + rc = SSH_ERROR; + break; + } + rlen = buffer_get_data(buffer, *o.cstring, len); + if (rlen != len){ + SAFE_FREE(*o.cstring); + rc = SSH_ERROR; + break; + } + (*o.cstring)[len] = '\0'; + o.cstring = NULL; + rc = SSH_OK; + break; + case 'P': + len = va_arg(ap, size_t); + o.data = va_arg(ap, void **); + *o.data = malloc(len); + if(*o.data == NULL){ + rc = SSH_ERROR; + break; + } + rlen = buffer_get_data(buffer, *o.data, len); + if (rlen != len){ + SAFE_FREE(*o.data); + rc = SSH_ERROR; + break; + } + o.data = NULL; + rc = SSH_OK; + break; + default: + SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p); + rc = SSH_ERROR; + } + if (rc != SSH_OK) { + break; + } + } + if (rc != SSH_ERROR){ + /* verify that the last hidden argument is correct */ + uint32_t canary = va_arg(ap, uint32_t); + if (canary != SSH_BUFFER_PACK_END){ + rc = SSH_ERROR; + } + } + if (rc != SSH_OK){ + /* Reset the format string and erase everything that was allocated */ + last = p; + for(p=format;p + * Copyright (c) 2009-2013 by Andreas Schneider * * 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 diff --git a/libssh/src/channels.c b/libssh/src/channels.c index f7bcded2..7a4e71fe 100644 --- a/libssh/src/channels.c +++ b/libssh/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 + * Copyright (c) 2003-2013 by Aris Adamantiadis + * Copyright (c) 2009-2013 by Andreas Schneider * * 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 @@ -139,15 +139,16 @@ uint32_t ssh_channel_new_id(ssh_session session) { */ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ uint32_t channelid=0; - uint32_t tmp; ssh_channel channel; + int rc; (void)type; (void)user; SSH_LOG(SSH_LOG_PACKET,"Received SSH2_MSG_CHANNEL_OPEN_CONFIRMATION"); - buffer_get_u32(packet, &channelid); - channelid=ntohl(channelid); + rc = ssh_buffer_unpack(packet, "d", &channelid); + if (rc != SSH_OK) + goto error; channel=ssh_channel_from_local(session,channelid); if(channel==NULL){ ssh_set_error(session, SSH_FATAL, @@ -158,14 +159,12 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ return SSH_PACKET_USED; } - buffer_get_u32(packet, &tmp); - channel->remote_channel = ntohl(tmp); - - buffer_get_u32(packet, &tmp); - channel->remote_window = ntohl(tmp); - - buffer_get_u32(packet,&tmp); - channel->remote_maxpacket=ntohl(tmp); + rc = ssh_buffer_unpack(packet, "ddd", + &channel->remote_channel, + &channel->remote_window, + &channel->remote_maxpacket); + if (rc != SSH_OK) + goto error; SSH_LOG(SSH_LOG_PROTOCOL, "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", @@ -177,8 +176,11 @@ 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; +error: + ssh_set_error(session, SSH_FATAL, "Invalid packet"); return SSH_PACKET_USED; } @@ -190,31 +192,28 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){ ssh_channel channel; - ssh_string error_s; char *error = NULL; uint32_t code; + int rc; (void)user; (void)type; + channel=channel_from_msg(session,packet); if(channel==NULL){ SSH_LOG(SSH_LOG_RARE,"Invalid channel in packet"); return SSH_PACKET_USED; } - buffer_get_u32(packet, &code); - error_s = buffer_get_ssh_string(packet); - if(error_s != NULL) - error = ssh_string_to_char(error_s); - ssh_string_free(error_s); - if (error == NULL) { - ssh_set_error_oom(session); - return SSH_PACKET_USED; + rc = ssh_buffer_unpack(packet, "ds", &code, &error); + if (rc != SSH_OK){ + ssh_set_error(session, SSH_FATAL, "Invalid packet"); + return SSH_PACKET_USED; } ssh_set_error(session, SSH_REQUEST_DENIED, "Channel opening failure: channel %u error (%lu) %s", channel->local_channel, - (long unsigned int) ntohl(code), + (long unsigned int) code, error); SAFE_FREE(error); channel->state=SSH_CHANNEL_STATE_OPEN_DENIED; @@ -238,7 +237,7 @@ static int ssh_channel_open_termination(void *c){ * * @param[in] channel The current channel. * - * @param[in] type_c A C string describing the kind of channel (e.g. "exec"). + * @param[in] type A C string describing the kind of channel (e.g. "exec"). * * @param[in] window The receiving window of the channel. The window is the * maximum size of data that can stay in buffers and @@ -248,11 +247,11 @@ static int ssh_channel_open_termination(void *c){ * * @param[in] payload The buffer containing additional payload for the query. */ -static int channel_open(ssh_channel channel, const char *type_c, int window, +static int channel_open(ssh_channel channel, const char *type, int window, int maxpacket, ssh_buffer payload) { ssh_session session = channel->session; - ssh_string type = NULL; int err=SSH_ERROR; + int rc; switch(channel->state){ case SSH_CHANNEL_STATE_NOT_OPEN: @@ -274,26 +273,18 @@ static int channel_open(ssh_channel channel, const char *type_c, int window, "Creating a channel %d with %d window and %d max packet", channel->local_channel, window, maxpacket); - type = ssh_string_from_char(type_c); - if (type == NULL) { + rc = ssh_buffer_pack(session->out_buffer, + "bsddd", + SSH2_MSG_CHANNEL_OPEN, + type, + channel->local_channel, + channel->local_window, + channel->local_maxpacket); + if (rc != SSH_OK){ ssh_set_error_oom(session); - return err; } - if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN) < 0 || - buffer_add_ssh_string(session->out_buffer,type) < 0 || - buffer_add_u32(session->out_buffer, htonl(channel->local_channel)) < 0 || - buffer_add_u32(session->out_buffer, htonl(channel->local_window)) < 0 || - buffer_add_u32(session->out_buffer, htonl(channel->local_maxpacket)) < 0) { - ssh_set_error_oom(session); - ssh_string_free(type); - - return err; - } - - ssh_string_free(type); - if (payload != NULL) { if (buffer_add_buffer(session->out_buffer, payload) < 0) { ssh_set_error_oom(session); @@ -309,7 +300,7 @@ static int channel_open(ssh_channel channel, const char *type_c, int window, SSH_LOG(SSH_LOG_PACKET, "Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d", - type_c, channel->local_channel); + type, channel->local_channel); pending: /* wait until channel is opened by server */ err = ssh_handle_packets_termination(session, @@ -353,6 +344,7 @@ ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) { */ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize) { uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE; + int rc; #ifdef WITH_SSH1 if (session->version == 1){ @@ -372,9 +364,12 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize /* WINDOW_ADJUST packet needs a relative increment rather than an absolute * value, so we give here the missing bytes needed to reach new_window */ - if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_WINDOW_ADJUST) < 0 || - buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 || - buffer_add_u32(session->out_buffer, htonl(new_window - channel->local_window)) < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bdd", + SSH2_MSG_CHANNEL_WINDOW_ADJUST, + channel->remote_channel, + new_window - channel->local_window); + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } @@ -393,7 +388,7 @@ static int grow_window(ssh_session session, ssh_channel channel, int minimumsize return SSH_OK; error: - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_ERROR; } @@ -416,22 +411,24 @@ error: static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) { ssh_channel channel; uint32_t chan; + int rc; #ifdef WITH_SSH1 /* With SSH1, the channel is always the first one */ if(session->version==1) return ssh_get_channel1(session); #endif - if (buffer_get_u32(packet, &chan) != sizeof(uint32_t)) { + rc = ssh_buffer_unpack(packet,"d",&chan); + if (rc != SSH_OK) { ssh_set_error(session, SSH_FATAL, "Getting channel from message: short read"); return NULL; } - channel = ssh_channel_from_local(session, ntohl(chan)); + channel = ssh_channel_from_local(session, chan); if (channel == NULL) { ssh_set_error(session, SSH_FATAL, "Server specified invalid channel %lu", - (long unsigned int) ntohl(chan)); + (long unsigned int) chan); } return channel; @@ -449,15 +446,14 @@ SSH_PACKET_CALLBACK(channel_rcv_change_window) { SSH_LOG(SSH_LOG_FUNCTIONS, "%s", ssh_get_error(session)); } - rc = buffer_get_u32(packet, &bytes); - if (channel == NULL || rc != sizeof(uint32_t)) { + rc = ssh_buffer_unpack(packet, "d", &bytes); + if (channel == NULL || rc != SSH_OK) { SSH_LOG(SSH_LOG_PACKET, "Error getting a window adjust message: invalid packet"); return SSH_PACKET_USED; } - bytes = ntohl(bytes); SSH_LOG(SSH_LOG_PROTOCOL, "Adding %d bytes to channel (%d:%d) (from %d bytes)", bytes, @@ -507,7 +503,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ } len = ssh_string_len(str); - SSH_LOG(SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PACKET, "Channel receiving %" PRIdS " bytes data in %d (local win=%d remote win=%d)", len, is_stderr, @@ -535,7 +531,7 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ channel->local_window = 0; /* buggy remote */ } - SSH_LOG(SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PACKET, "Channel windows are now (local win=%d remote win=%d)", channel->local_window, channel->remote_window); @@ -555,6 +551,9 @@ SSH_PACKET_CALLBACK(channel_rcv_data){ is_stderr, channel->callbacks->userdata); if(rest > 0) { + if (channel->counter != NULL) { + channel->counter->in_bytes += rest; + } buffer_pass_bytes(buf, rest); } if (channel->local_window + buffer_get_rest_len(buf) < WINDOWLIMIT) { @@ -635,7 +634,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); @@ -644,8 +643,7 @@ SSH_PACKET_CALLBACK(channel_rcv_close) { SSH_PACKET_CALLBACK(channel_rcv_request) { ssh_channel channel; - ssh_string request_s; - char *request; + char *request=NULL; uint8_t status; int rc; (void)user; @@ -654,32 +652,22 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { channel = channel_from_msg(session,packet); if (channel == NULL) { SSH_LOG(SSH_LOG_FUNCTIONS,"%s", ssh_get_error(session)); - return SSH_PACKET_USED; } - request_s = buffer_get_ssh_string(packet); - if (request_s == NULL) { + rc = ssh_buffer_unpack(packet, "sb", + &request, + &status); + if (rc != SSH_OK) { SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - return SSH_PACKET_USED; } - request = ssh_string_to_char(request_s); - ssh_string_free(request_s); - if (request == NULL) { - - return SSH_PACKET_USED; - } - - buffer_get_u8(packet, (uint8_t *) &status); - if (strcmp(request,"exit-status") == 0) { uint32_t exit_status = 0; SAFE_FREE(request); - buffer_get_u32(packet, &exit_status); - channel->exit_status = ntohl(exit_status); + rc = ssh_buffer_unpack(packet, "d", &exit_status); SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status); if(ssh_callbacks_exists(channel->callbacks, channel_exit_status_function)) { @@ -693,27 +681,17 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { } if (strcmp(request,"signal") == 0) { - ssh_string signal_str; - char *sig; + char *sig = NULL; SAFE_FREE(request); SSH_LOG(SSH_LOG_PACKET, "received signal"); - signal_str = buffer_get_ssh_string(packet); - if (signal_str == NULL) { + rc = ssh_buffer_unpack(packet, "s", &sig); + if (rc != SSH_OK) { SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - return SSH_PACKET_USED; } - sig = ssh_string_to_char(signal_str); - ssh_string_free(signal_str); - if (sig == NULL) { - - return SSH_PACKET_USED; - } - - SSH_LOG(SSH_LOG_PACKET, "Remote connection sent a signal SIG %s", sig); if(ssh_callbacks_exists(channel->callbacks, channel_signal_function)) { @@ -729,73 +707,33 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { if (strcmp(request, "exit-signal") == 0) { const char *core = "(core dumped)"; - ssh_string tmp; - char *sig; + char *sig = NULL; char *errmsg = NULL; char *lang = NULL; - uint8_t i; + uint8_t core_dumped; SAFE_FREE(request); - tmp = buffer_get_ssh_string(packet); - if (tmp == NULL) { + rc = ssh_buffer_unpack(packet, "sbs", + &sig, /* signal name */ + &core_dumped, /* core dumped */ + &errmsg, /* error message */ + &lang); + if (rc != SSH_OK) { SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - return SSH_PACKET_USED; } - sig = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (sig == NULL) { - - return SSH_PACKET_USED; - } - - buffer_get_u8(packet, &i); - if (i == 0) { + if (core_dumped == 0) { core = ""; } - tmp = buffer_get_ssh_string(packet); - if (tmp == NULL) { - SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - SAFE_FREE(sig); - - return SSH_PACKET_USED; - } - - errmsg = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (errmsg == NULL) { - SAFE_FREE(sig); - - return SSH_PACKET_USED; - } - - tmp = buffer_get_ssh_string(packet); - if (tmp == NULL) { - SSH_LOG(SSH_LOG_PACKET, "Invalid MSG_CHANNEL_REQUEST"); - SAFE_FREE(errmsg); - SAFE_FREE(sig); - - return SSH_PACKET_USED; - } - - lang = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (lang == NULL) { - SAFE_FREE(errmsg); - SAFE_FREE(sig); - - return SSH_PACKET_USED; - } - SSH_LOG(SSH_LOG_PACKET, "Remote connection closed by signal SIG %s %s", sig, core); if(ssh_callbacks_exists(channel->callbacks, channel_exit_signal_function)) { channel->callbacks->channel_exit_signal_function(channel->session, channel, - sig, i, errmsg, lang, + sig, core_dumped, errmsg, lang, channel->callbacks->userdata); } @@ -808,12 +746,12 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { if(strcmp(request,"keepalive@openssh.com")==0){ SAFE_FREE(request); SSH_LOG(SSH_LOG_PROTOCOL,"Responding to Openssh's keepalive"); - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_FAILURE); - if (rc < 0) { - return SSH_PACKET_USED; - } - rc = buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)); - if (rc < 0) { + + rc = ssh_buffer_pack(session->out_buffer, + "bd", + SSH2_MSG_CHANNEL_FAILURE, + channel->remote_channel); + if (rc != SSH_OK) { return SSH_PACKET_USED; } packet_send(session); @@ -867,7 +805,7 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len, return -1; } - SSH_LOG(SSH_LOG_RARE, + SSH_LOG(SSH_LOG_PACKET, "placing %d bytes into channel buffer (stderr=%d)", len, is_stderr); if (is_stderr == 0) { /* stdout */ @@ -879,7 +817,7 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len, } } - if (buffer_add_data(channel->stdout_buffer, data, len) < 0) { + if (ssh_buffer_add_data(channel->stdout_buffer, data, len) < 0) { ssh_set_error_oom(session); ssh_buffer_free(channel->stdout_buffer); channel->stdout_buffer = NULL; @@ -895,7 +833,7 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len, } } - if (buffer_add_data(channel->stderr_buffer, data, len) < 0) { + if (ssh_buffer_add_data(channel->stderr_buffer, data, len) < 0) { ssh_set_error_oom(session); ssh_buffer_free(channel->stderr_buffer); channel->stderr_buffer = NULL; @@ -916,10 +854,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) { @@ -952,7 +890,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) { @@ -1021,27 +959,14 @@ int ssh_channel_open_forward(ssh_channel channel, const char *remotehost, ssh_set_error_oom(session); goto error; } - str = ssh_string_from_char(remotehost); - if (str == NULL) { - ssh_set_error_oom(session); - goto error; - } - if (buffer_add_ssh_string(payload, str) < 0 || - buffer_add_u32(payload,htonl(remoteport)) < 0) { - ssh_set_error_oom(session); - goto error; - } - - ssh_string_free(str); - str = ssh_string_from_char(sourcehost); - if (str == NULL) { - ssh_set_error_oom(session); - goto error; - } - - if (buffer_add_ssh_string(payload, str) < 0 || - buffer_add_u32(payload,htonl(localport)) < 0) { + rc = ssh_buffer_pack(payload, + "sdsd", + remotehost, + remoteport, + sourcehost, + localport); + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } @@ -1078,7 +1003,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. @@ -1120,12 +1045,29 @@ 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; int rc = SSH_ERROR; + int err; if(channel == NULL) { return rc; @@ -1133,25 +1075,30 @@ int ssh_channel_send_eof(ssh_channel channel){ session = channel->session; - if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) { - ssh_set_error_oom(session); - goto error; - } - if (buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)) < 0) { + err = ssh_buffer_pack(session->out_buffer, + "bd", + SSH2_MSG_CHANNEL_EOF, + channel->remote_channel); + if (err != SSH_OK) { ssh_set_error_oom(session); goto error; } + rc = packet_send(session); SSH_LOG(SSH_LOG_PACKET, "Sent a EOF on client channel (%d:%d)", channel->local_channel, channel->remote_channel); + rc = ssh_channel_flush(channel); + if(rc == SSH_ERROR) + goto error; + channel->local_eof = 1; return rc; error: - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return rc; } @@ -1166,8 +1113,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; @@ -1187,8 +1134,11 @@ int ssh_channel_close(ssh_channel channel){ return rc; } - if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_CLOSE) < 0 || - buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bd", + SSH2_MSG_CHANNEL_CLOSE, + channel->remote_channel); + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } @@ -1203,9 +1153,13 @@ 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); + ssh_buffer_reinit(session->out_buffer); return rc; } @@ -1214,7 +1168,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; @@ -1321,7 +1276,10 @@ static int channel_write_common(ssh_channel channel, "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; } @@ -1332,39 +1290,32 @@ static int channel_write_common(ssh_channel channel, effectivelen = MIN(effectivelen, maxpacketlen);; - rc = buffer_add_u8(session->out_buffer, - is_stderr ? SSH2_MSG_CHANNEL_EXTENDED_DATA - : SSH2_MSG_CHANNEL_DATA); - if (rc < 0) { - ssh_set_error_oom(session); - goto error; - } - - rc = buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)); - if (rc < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bd", + is_stderr ? SSH2_MSG_CHANNEL_EXTENDED_DATA : SSH2_MSG_CHANNEL_DATA, + channel->remote_channel); + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } /* stderr message has an extra field */ if (is_stderr) { - rc = buffer_add_u32(session->out_buffer, - htonl(SSH2_EXTENDED_DATA_STDERR)); - if (rc < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "d", + SSH2_EXTENDED_DATA_STDERR); + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } } /* append payload data */ - rc = buffer_add_u32(session->out_buffer, htonl(effectivelen)); - if (rc < 0) { - ssh_set_error_oom(session); - goto error; - } - - rc = buffer_add_data(session->out_buffer, data, effectivelen); - if (rc < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "dP", + effectivelen, + (size_t)effectivelen, data); + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } @@ -1374,12 +1325,15 @@ static int channel_write_common(ssh_channel channel, return SSH_ERROR; } - SSH_LOG(SSH_LOG_RARE, + SSH_LOG(SSH_LOG_PACKET, "channel_write wrote %ld bytes", (long int) effectivelen); channel->remote_window -= effectivelen; len -= effectivelen; data = ((uint8_t*)data + effectivelen); + if (channel->counter != NULL) { + channel->counter->out_bytes += effectivelen; + } } /* it's a good idea to flush the socket now */ @@ -1392,7 +1346,7 @@ out: return (int)(origlen - len); error: - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_ERROR; } @@ -1412,7 +1366,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); @@ -1425,7 +1379,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) { @@ -1441,7 +1395,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) { @@ -1566,8 +1520,8 @@ static int ssh_channel_request_termination(void *c){ static int channel_request(ssh_channel channel, const char *request, ssh_buffer buffer, int reply) { ssh_session session = channel->session; - ssh_string req = NULL; int rc = SSH_ERROR; + int ret; switch(channel->request_state){ case SSH_CHANNEL_REQ_STATE_NONE: @@ -1576,24 +1530,19 @@ static int channel_request(ssh_channel channel, const char *request, goto pending; } - req = ssh_string_from_char(request); - if (req == NULL) { + ret = ssh_buffer_pack(session->out_buffer, + "bdsb", + SSH2_MSG_CHANNEL_REQUEST, + channel->remote_channel, + request, + reply == 0 ? 0 : 1); + if (ret != SSH_OK) { ssh_set_error_oom(session); goto error; } - if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_REQUEST) < 0 || - buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 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); - ssh_string_free(req); - goto error; - } - ssh_string_free(req); - if (buffer != NULL) { - if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer), + if (ssh_buffer_add_data(session->out_buffer, buffer_get_rest(buffer), buffer_get_rest_len(buffer)) < 0) { ssh_set_error_oom(session); goto error; @@ -1647,7 +1596,7 @@ pending: return rc; error: - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return rc; } @@ -1671,7 +1620,6 @@ error: int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal, int col, int row) { ssh_session session; - ssh_string term = NULL; ssh_buffer buffer = NULL; int rc = SSH_ERROR; @@ -1705,19 +1653,17 @@ int ssh_channel_request_pty_size(ssh_channel channel, const char *terminal, goto error; } - term = ssh_string_from_char(terminal); - if (term == NULL) { - ssh_set_error_oom(session); - goto error; - } + rc = ssh_buffer_pack(buffer, + "sdddddb", + terminal, + col, + row, + 0, /* pix */ + 0, /* pix */ + 1, /* add a 0byte string */ + 0); - if (buffer_add_ssh_string(buffer, term) < 0 || - buffer_add_u32(buffer, htonl(col)) < 0 || - buffer_add_u32(buffer, htonl(row)) < 0 || - buffer_add_u32(buffer, 0) < 0 || - buffer_add_u32(buffer, 0) < 0 || - buffer_add_u32(buffer, htonl(1)) < 0 || /* Add a 0byte string */ - buffer_add_u8(buffer, 0) < 0) { + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } @@ -1725,7 +1671,6 @@ pending: rc = channel_request(channel, "pty-req", buffer, 1); error: ssh_buffer_free(buffer); - ssh_string_free(term); return rc; } @@ -1740,7 +1685,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); @@ -1780,10 +1725,13 @@ int ssh_channel_change_pty_size(ssh_channel channel, int cols, int rows) { goto error; } - if (buffer_add_u32(buffer, htonl(cols)) < 0 || - buffer_add_u32(buffer, htonl(rows)) < 0 || - buffer_add_u32(buffer, 0) < 0 || - buffer_add_u32(buffer, 0) < 0) { + rc = ssh_buffer_pack(buffer, + "dddd", + cols, + rows, + 0, /* pix */ + 0 /* pix */); + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } @@ -1833,7 +1781,6 @@ int ssh_channel_request_shell(ssh_channel channel) { */ int ssh_channel_request_subsystem(ssh_channel channel, const char *subsys) { ssh_buffer buffer = NULL; - ssh_string subsystem = NULL; int rc = SSH_ERROR; if(channel == NULL) { @@ -1856,13 +1803,8 @@ int ssh_channel_request_subsystem(ssh_channel channel, const char *subsys) { goto error; } - subsystem = ssh_string_from_char(subsys); - if (subsystem == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - if (buffer_add_ssh_string(buffer, subsystem) < 0) { + rc = ssh_buffer_pack(buffer, "s", subsys); + if (rc != SSH_OK) { ssh_set_error_oom(channel->session); goto error; } @@ -1870,7 +1812,6 @@ pending: rc = channel_request(channel, "subsystem", buffer, 1); error: ssh_buffer_free(buffer); - ssh_string_free(subsystem); return rc; } @@ -1882,7 +1823,7 @@ int ssh_channel_request_sftp( ssh_channel channel){ return ssh_channel_request_subsystem(channel, "sftp"); } -static ssh_string generate_cookie(void) { +static char *generate_cookie(void) { static const char *hex = "0123456789abcdef"; char s[36]; unsigned char rnd[16]; @@ -1894,7 +1835,7 @@ static ssh_string generate_cookie(void) { s[i*2+1] = hex[rnd[i] >> 4]; } s[32] = '\0'; - return ssh_string_from_char(s); + return strdup(s); } /** @@ -1925,8 +1866,7 @@ static ssh_string generate_cookie(void) { int ssh_channel_request_x11(ssh_channel channel, int single_connection, const char *protocol, const char *cookie, int screen_number) { ssh_buffer buffer = NULL; - ssh_string p = NULL; - ssh_string c = NULL; + char *c = NULL; int rc = SSH_ERROR; if(channel == NULL) { @@ -1945,26 +1885,24 @@ int ssh_channel_request_x11(ssh_channel channel, int single_connection, const ch goto error; } - p = ssh_string_from_char(protocol ? protocol : "MIT-MAGIC-COOKIE-1"); - if (p == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - if (cookie) { - c = ssh_string_from_char(cookie); - } else { + if (cookie == NULL) { c = generate_cookie(); - } - if (c == NULL) { - ssh_set_error_oom(channel->session); - goto error; + if (c == NULL) { + ssh_set_error_oom(channel->session); + goto error; + } } - if (buffer_add_u8(buffer, single_connection == 0 ? 0 : 1) < 0 || - buffer_add_ssh_string(buffer, p) < 0 || - buffer_add_ssh_string(buffer, c) < 0 || - buffer_add_u32(buffer, htonl(screen_number)) < 0) { + rc = ssh_buffer_pack(buffer, + "bssd", + single_connection == 0 ? 0 : 1, + protocol ? protocol : "MIT-MAGIC-COOKIE-1", + cookie ? cookie : c, + screen_number); + if (c != NULL){ + SAFE_FREE(c); + } + if (rc != SSH_OK) { ssh_set_error_oom(channel->session); goto error; } @@ -1973,13 +1911,11 @@ pending: error: ssh_buffer_free(buffer); - ssh_string_free(p); - ssh_string_free(c); return rc; } 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, @@ -1996,7 +1932,11 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype, * 50 ms. So we need to decrement by 100 ms. */ for (t = timeout_ms; t >= 0; t -= 100) { - ssh_handle_packets(session, 50); + 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); @@ -2006,6 +1946,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; } @@ -2036,7 +1980,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); } /** @@ -2116,7 +2060,6 @@ 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; switch (session->global_req_state) { @@ -2126,35 +2069,19 @@ static int global_request(ssh_session session, const char *request, 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); - rc = SSH_ERROR; - goto error; - } - - rc = buffer_add_ssh_string(session->out_buffer, req); - ssh_string_free(req); - 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) { + rc = ssh_buffer_pack(session->out_buffer, + "bsb", + SSH2_MSG_GLOBAL_REQUEST, + request, + reply == 0 ? 0 : 1); + if (rc != SSH_OK){ ssh_set_error_oom(session); rc = SSH_ERROR; goto error; } if (buffer != NULL) { - rc = buffer_add_data(session->out_buffer, + rc = ssh_buffer_add_data(session->out_buffer, buffer_get_rest(buffer), buffer_get_rest_len(buffer)); if (rc < 0) { @@ -2210,7 +2137,7 @@ pending: return rc; error: - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return rc; } @@ -2237,11 +2164,13 @@ error: * SSH_AGAIN if in nonblocking mode and call has * to be done again. **/ -int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port) { +int ssh_channel_listen_forward(ssh_session session, + const char *address, + int port, + int *bound_port) +{ ssh_buffer buffer = NULL; - ssh_string addr = NULL; int rc = SSH_ERROR; - uint32_t tmp; if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) goto pending; @@ -2252,14 +2181,11 @@ int ssh_forward_listen(ssh_session session, const char *address, int port, int * goto error; } - addr = ssh_string_from_char(address ? address : ""); - if (addr == NULL) { - ssh_set_error_oom(session); - goto error; - } - - if (buffer_add_ssh_string(buffer, addr) < 0 || - buffer_add_u32(buffer, htonl(port)) < 0) { + rc = ssh_buffer_pack(buffer, + "sd", + address ? address : "", + port); + if (rc != SSH_OK){ ssh_set_error_oom(session); goto error; } @@ -2268,29 +2194,36 @@ pending: /* TODO: FIXME no guarantee the last packet we received contains * that info */ - if (rc == SSH_OK && port == 0 && bound_port) { - buffer_get_u32(session->in_buffer, &tmp); - *bound_port = ntohl(tmp); + if (rc == SSH_OK && port == 0 && bound_port != NULL) { + rc = ssh_buffer_unpack(session->in_buffer, "d", bound_port); + if (rc != SSH_OK) + *bound_port = 0; } error: ssh_buffer_free(buffer); - ssh_string_free(addr); return rc; } +/* DEPRECATED */ +ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) { + return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, NULL); +} + /** - * @brief Accept an incoming TCP/IP forwarding channel. - * + * @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_forward_accept(ssh_session session, int timeout_ms) { - return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms); +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); } /** @@ -2308,9 +2241,11 @@ ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) { * SSH_AGAIN if in nonblocking mode and call has * to be done again. */ -int ssh_forward_cancel(ssh_session session, const char *address, int port) { +int ssh_channel_cancel_forward(ssh_session session, + const char *address, + int port) +{ ssh_buffer buffer = NULL; - ssh_string addr = NULL; int rc = SSH_ERROR; if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) @@ -2322,26 +2257,25 @@ int ssh_forward_cancel(ssh_session session, const char *address, int port) { goto error; } - addr = ssh_string_from_char(address ? address : ""); - if (addr == NULL) { - ssh_set_error_oom(session); - goto error; - } - - if (buffer_add_ssh_string(buffer, addr) < 0 || - buffer_add_u32(buffer, htonl(port)) < 0) { - ssh_set_error_oom(session); - goto error; + rc = ssh_buffer_pack(buffer, "sd", + address ? address : "", + port); + if (rc != SSH_OK){ + ssh_set_error_oom(session); + goto error; } pending: rc = global_request(session, "cancel-tcpip-forward", buffer, 1); error: ssh_buffer_free(buffer); - ssh_string_free(addr); return rc; } +int ssh_forward_cancel(ssh_session session, const char *address, int port) { + return ssh_channel_cancel_forward(session, address, port); +} + /** * @brief Set environment variables. * @@ -2359,7 +2293,6 @@ error: */ int ssh_channel_request_env(ssh_channel channel, const char *name, const char *value) { ssh_buffer buffer = NULL; - ssh_string str = NULL; int rc = SSH_ERROR; if(channel == NULL) { @@ -2381,25 +2314,11 @@ int ssh_channel_request_env(ssh_channel channel, const char *name, const char *v goto error; } - str = ssh_string_from_char(name); - if (str == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - if (buffer_add_ssh_string(buffer, str) < 0) { - ssh_set_error_oom(channel->session); - goto error; - } - - ssh_string_free(str); - str = ssh_string_from_char(value); - if (str == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - if (buffer_add_ssh_string(buffer, str) < 0) { + rc = ssh_buffer_pack(buffer, + "ss", + name, + value); + if (rc != SSH_OK){ ssh_set_error_oom(channel->session); goto error; } @@ -2407,7 +2326,6 @@ pending: rc = channel_request(channel, "env", buffer,1); error: ssh_buffer_free(buffer); - ssh_string_free(str); return rc; } @@ -2426,24 +2344,25 @@ 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; - ssh_string command = NULL; int rc = SSH_ERROR; if(channel == NULL) { @@ -2471,13 +2390,9 @@ int ssh_channel_request_exec(ssh_channel channel, const char *cmd) { goto error; } - command = ssh_string_from_char(cmd); - if (command == NULL) { - goto error; - ssh_set_error_oom(channel->session); - } + rc = ssh_buffer_pack(buffer, "s", cmd); - if (buffer_add_ssh_string(buffer, command) < 0) { + if (rc != SSH_OK) { ssh_set_error_oom(channel->session); goto error; } @@ -2485,7 +2400,6 @@ pending: rc = channel_request(channel, "exec", buffer, 1); error: ssh_buffer_free(buffer); - ssh_string_free(command); return rc; } @@ -2524,7 +2438,6 @@ error: */ int ssh_channel_request_send_signal(ssh_channel channel, const char *sig) { ssh_buffer buffer = NULL; - ssh_string encoded_signal = NULL; int rc = SSH_ERROR; if(channel == NULL) { @@ -2547,13 +2460,8 @@ int ssh_channel_request_send_signal(ssh_channel channel, const char *sig) { goto error; } - encoded_signal = ssh_string_from_char(sig); - if (encoded_signal == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - - if (buffer_add_ssh_string(buffer, encoded_signal) < 0) { + rc = ssh_buffer_pack(buffer, "s", sig); + if (rc != SSH_OK) { ssh_set_error_oom(channel->session); goto error; } @@ -2561,7 +2469,6 @@ int ssh_channel_request_send_signal(ssh_channel channel, const char *sig) { rc = channel_request(channel, "signal", buffer, 0); error: ssh_buffer_free(buffer); - ssh_string_free(encoded_signal); return rc; } @@ -2602,7 +2509,7 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, return SSH_ERROR; } - buffer_reinit(buffer); + ssh_buffer_reinit(buffer); if(count==0){ do { r=ssh_channel_poll(channel, is_stderr); @@ -2614,7 +2521,7 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, if(r < 0){ return r; } - if(buffer_add_data(buffer,buffer_tmp,r) < 0){ + if(ssh_buffer_add_data(buffer,buffer_tmp,r) < 0){ ssh_set_error_oom(session); r = SSH_ERROR; } @@ -2635,7 +2542,7 @@ int channel_read_buffer(ssh_channel channel, ssh_buffer buffer, uint32_t count, if(r==0){ return total; } - if(buffer_add_data(buffer,buffer_tmp,r) < 0){ + if (ssh_buffer_add_data(buffer,buffer_tmp,r) < 0) { ssh_set_error_oom(session); return SSH_ERROR; @@ -2685,7 +2592,40 @@ static int ssh_channel_read_termination(void *s){ * @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; @@ -2715,7 +2655,7 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std * We may have problem if the window is too small to accept as much data * as asked */ - SSH_LOG(SSH_LOG_PROTOCOL, + SSH_LOG(SSH_LOG_PACKET, "Read (%d) buffered : %d bytes. Window: %d", count, buffer_get_rest_len(stdbuf), @@ -2733,8 +2673,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; } @@ -2749,6 +2696,9 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std len = (len > count ? count : len); memcpy(dest, buffer_get_rest(stdbuf), len); buffer_pass_bytes(stdbuf,len); + if (channel->counter != NULL) { + channel->counter->in_bytes += len; + } /* Authorize some buffering while userapp is busy */ if (channel->local_window < WINDOWLIMIT) { if (grow_window(session, channel, 0) < 0) { @@ -2778,7 +2728,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) { @@ -2830,7 +2780,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; @@ -2882,7 +2832,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; @@ -2955,6 +2905,11 @@ 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; @@ -3175,6 +3130,31 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans, return 0; } +/** + * @brief Set the channel data counter. + * + * @code + * struct ssh_counter_struct counter = { + * .in_bytes = 0, + * .out_bytes = 0, + * .in_packets = 0, + * .out_packets = 0 + * }; + * + * ssh_channel_set_counter(channel, &counter); + * @endcode + * + * @param[in] channel The SSH channel. + * + * @param[in] counter Counter for bytes handled by the channel. + */ +void ssh_channel_set_counter(ssh_channel channel, + ssh_counter counter) { + if (channel != NULL) { + channel->counter = counter; + } +} + #if WITH_SERVER /** * @brief Blocking write on a channel stderr. @@ -3187,7 +3167,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); @@ -3221,7 +3201,6 @@ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost int remoteport, const char *sourcehost, int localport) { ssh_session session; ssh_buffer payload = NULL; - ssh_string str = NULL; int rc = SSH_ERROR; if(channel == NULL) { @@ -3232,7 +3211,6 @@ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost return rc; } - session = channel->session; if(channel->state != SSH_CHANNEL_STATE_NOT_OPEN) @@ -3242,27 +3220,13 @@ int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost ssh_set_error_oom(session); goto error; } - str = ssh_string_from_char(remotehost); - if (str == NULL) { - ssh_set_error_oom(session); - goto error; - } - - if (buffer_add_ssh_string(payload, str) < 0 || - buffer_add_u32(payload,htonl(remoteport)) < 0) { - ssh_set_error_oom(session); - goto error; - } - - ssh_string_free(str); - str = ssh_string_from_char(sourcehost); - if (str == NULL) { - ssh_set_error_oom(session); - goto error; - } - - if (buffer_add_ssh_string(payload, str) < 0 || - buffer_add_u32(payload,htonl(localport)) < 0) { + rc = ssh_buffer_pack(payload, + "sdsd", + remotehost, + remoteport, + sourcehost, + localport); + if (rc != SSH_OK){ ssh_set_error_oom(session); goto error; } @@ -3275,7 +3239,6 @@ pending: error: ssh_buffer_free(payload); - ssh_string_free(str); return rc; } @@ -3298,10 +3261,9 @@ error: * use channel_read and channel_write for this. */ int ssh_channel_open_x11(ssh_channel channel, - const char *orig_addr, int orig_port) { + const char *orig_addr, int orig_port) { ssh_session session; ssh_buffer payload = NULL; - ssh_string str = NULL; int rc = SSH_ERROR; if(channel == NULL) { @@ -3322,14 +3284,11 @@ int ssh_channel_open_x11(ssh_channel channel, goto error; } - str = ssh_string_from_char(orig_addr); - if (str == NULL) { - ssh_set_error_oom(session); - goto error; - } - - if (buffer_add_ssh_string(payload, str) < 0 || - buffer_add_u32(payload,htonl(orig_port)) < 0) { + rc = ssh_buffer_pack(payload, + "sd", + orig_addr, + orig_port); + if (rc != SSH_OK) { ssh_set_error_oom(session); goto error; } @@ -3342,7 +3301,6 @@ pending: error: ssh_buffer_free(payload); - ssh_string_free(str); return rc; } @@ -3381,7 +3339,8 @@ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) { goto error; } - if (buffer_add_u32(buffer, ntohl(exit_status)) < 0) { + rc = ssh_buffer_pack(buffer, "d", exit_status); + if (rc != SSH_OK) { ssh_set_error_oom(channel->session); goto error; } @@ -3393,9 +3352,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). @@ -3414,7 +3373,6 @@ error: int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig, int core, const char *errmsg, const char *lang) { ssh_buffer buffer = NULL; - ssh_string tmp = NULL; int rc = SSH_ERROR; if(channel == NULL) { @@ -3436,48 +3394,20 @@ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig, goto error; } - tmp = ssh_string_from_char(sig); - if (tmp == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - if (buffer_add_ssh_string(buffer, tmp) < 0) { + rc = ssh_buffer_pack(buffer, + "sbss", + sig, + core ? 1 : 0, + errmsg, + lang); + if (rc != SSH_OK) { ssh_set_error_oom(channel->session); goto error; } - if (buffer_add_u8(buffer, core?1:0) < 0) { - ssh_set_error_oom(channel->session); - goto error; - } - - ssh_string_free(tmp); - tmp = ssh_string_from_char(errmsg); - if (tmp == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - if (buffer_add_ssh_string(buffer, tmp) < 0) { - ssh_set_error_oom(channel->session); - goto error; - } - - ssh_string_free(tmp); - tmp = ssh_string_from_char(lang); - if (tmp == NULL) { - ssh_set_error_oom(channel->session); - goto error; - } - if (buffer_add_ssh_string(buffer, tmp) < 0) { - ssh_set_error_oom(channel->session); - goto error; - } - - rc = channel_request(channel, "signal", buffer, 0); + rc = channel_request(channel, "exit-signal", buffer, 0); error: ssh_buffer_free(buffer); - if(tmp) - ssh_string_free(tmp); return rc; } diff --git a/libssh/src/channels1.c b/libssh/src/channels1.c index bc66488d..4d82c636 100644 --- a/libssh/src/channels1.c +++ b/libssh/src/channels1.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 + * Copyright (c) 2009 by Andreas Schneider * * 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 @@ -356,7 +356,7 @@ int channel_write1(ssh_channel channel, const void *data, int len) { effectivelen = len > 32000 ? 32000 : len; if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 || - buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) { + ssh_buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) { return -1; } @@ -367,6 +367,9 @@ int channel_write1(ssh_channel channel, const void *data, int len) { return -1; } ssh_handle_packets(session, SSH_TIMEOUT_NONBLOCKING); + if (channel->counter != NULL) { + channel->counter->out_bytes += effectivelen; + } } if (ssh_blocking_flush(session,SSH_TIMEOUT_USER) == SSH_ERROR) return -1; diff --git a/libssh/src/client.c b/libssh/src/client.c index 1fb963d7..0a45944c 100644 --- a/libssh/src/client.c +++ b/libssh/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; @@ -152,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; } @@ -258,24 +269,19 @@ static int ssh_service_request_termination(void *s){ * @bug actually only works with ssh-userauth */ int ssh_service_request(ssh_session session, const char *service) { - ssh_string service_s = NULL; int rc=SSH_ERROR; if(session->auth_service_state != SSH_AUTH_SERVICE_NONE) goto pending; - if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_REQUEST) < 0) { - return SSH_ERROR; - } - service_s = ssh_string_from_char(service); - if (service_s == NULL) { - return SSH_ERROR; - } - if (buffer_add_ssh_string(session->out_buffer,service_s) < 0) { - ssh_string_free(service_s); + rc = ssh_buffer_pack(session->out_buffer, + "bs", + SSH2_MSG_SERVICE_REQUEST, + service); + if (rc != SSH_OK){ + ssh_set_error_oom(session); return SSH_ERROR; } - ssh_string_free(service_s); session->auth_service_state=SSH_AUTH_SERVICE_SENT; if (packet_send(session) == SSH_ERROR) { ssh_set_error(session, SSH_FATAL, @@ -495,7 +501,12 @@ int ssh_connect(ssh_session session) { ssh_set_error(session, SSH_FATAL, "Couldn't apply options"); return SSH_ERROR; } - SSH_LOG(SSH_LOG_RARE,"libssh %s, using threading %s", ssh_copyright(), ssh_threads_get_type()); + + SSH_LOG(SSH_LOG_PROTOCOL, + "libssh %s, using threading %s", + ssh_copyright(), + ssh_threads_get_type()); + session->ssh_connection_callback = ssh_client_connection_callback; session->session_state=SSH_SESSION_STATE_CONNECTING; ssh_socket_set_callbacks(session->socket,&session->socket_callbacks); @@ -504,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 @@ -535,7 +547,8 @@ pending: } SSH_LOG(SSH_LOG_PACKET,"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; @@ -612,32 +625,23 @@ int ssh_get_openssh_version(ssh_session session) { * @param[in] session The SSH session to use. */ void ssh_disconnect(ssh_session session) { - ssh_string str = NULL; struct ssh_iterator *it; + int rc; if (session == NULL) { return; } if (session->socket != NULL && ssh_socket_is_open(session->socket)) { - if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bds", + SSH2_MSG_DISCONNECT, + SSH2_DISCONNECT_BY_APPLICATION, + "Bye Bye"); + if (rc != SSH_OK){ + ssh_set_error_oom(session); goto error; } - if (buffer_add_u32(session->out_buffer, - htonl(SSH2_DISCONNECT_BY_APPLICATION)) < 0) { - goto error; - } - - str = ssh_string_from_char("Bye Bye"); - if (str == NULL) { - goto error; - } - - if (buffer_add_ssh_string(session->out_buffer,str) < 0) { - ssh_string_free(str); - goto error; - } - ssh_string_free(str); packet_send(session); ssh_socket_close(session->socket); @@ -651,21 +655,25 @@ 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){ crypto_free(session->current_crypto); session->current_crypto=NULL; } - if(session->in_buffer) - buffer_reinit(session->in_buffer); - if(session->out_buffer) - buffer_reinit(session->out_buffer); - if(session->in_hashbuf) - buffer_reinit(session->in_hashbuf); - if(session->out_hashbuf) - buffer_reinit(session->out_hashbuf); + if (session->in_buffer) { + ssh_buffer_reinit(session->in_buffer); + } + if (session->out_buffer) { + ssh_buffer_reinit(session->out_buffer); + } + if (session->in_hashbuf) { + ssh_buffer_reinit(session->in_hashbuf); + } + if (session->out_hashbuf) { + ssh_buffer_reinit(session->out_hashbuf); + } session->auth_methods = 0; SAFE_FREE(session->serverbanner); SAFE_FREE(session->clientbanner); @@ -687,8 +695,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"; } /** @} */ diff --git a/libssh/src/config.c b/libssh/src/config.c index 7935e884..4c966ed3 100644 --- a/libssh/src/config.c +++ b/libssh/src/config.c @@ -3,7 +3,7 @@ * * This file is part of the SSH Library * - * Copyright (c) 2009 by Andreas Schneider + * Copyright (c) 2009-2013 by Andreas Schneider * * 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 } }; @@ -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); @@ -350,7 +383,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) { return 0; } - SSH_LOG(SSH_LOG_RARE, "Reading configuration data from %s", filename); + SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename); parsing = 1; while (fgets(line, sizeof(line), f)) { diff --git a/libssh/src/connect.c b/libssh/src/connect.c index b299d41e..4ef85bc4 100644 --- a/libssh/src/connect.c +++ b/libssh/src/connect.c @@ -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, diff --git a/libssh/src/curve25519.c b/libssh/src/curve25519.c index 153fbcd9..99d7145b 100644 --- a/libssh/src/curve25519.c +++ b/libssh/src/curve25519.c @@ -37,19 +37,14 @@ #include "libssh/crypto.h" #include "libssh/dh.h" #include "libssh/pki.h" +#include "libssh/bignum.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"); @@ -58,15 +53,14 @@ int ssh_client_curve25519_init(ssh_session session){ 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); - if (rc < 0) { - ssh_string_free(client_pubkey); + + rc = ssh_buffer_pack(session->out_buffer, + "bdP", + SSH2_MSG_KEX_ECDH_INIT, + CURVE25519_PUBKEY_SIZE, + (size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_client_pubkey); + if (rc != SSH_OK) { + ssh_set_error_oom(session); return SSH_ERROR; } @@ -90,7 +84,7 @@ static int ssh_curve25519_build_k(ssh_session session) { crypto_scalarmult(k, session->next_crypto->curve25519_privkey, session->next_crypto->curve25519_server_pubkey); - BN_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k); + bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k); #ifdef DEBUG_CRYPTO ssh_print_hexa("Session server cookie", @@ -133,6 +127,7 @@ int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){ 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) { @@ -194,44 +189,36 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){ 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; + 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); - q_s_string = ssh_string_new(CURVE25519_PUBKEY_SIZE); - if (q_s_string == NULL) { - return SSH_ERROR; - } - - ssh_string_fill(q_s_string, session->next_crypto->curve25519_server_pubkey, - CURVE25519_PUBKEY_SIZE); - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY); if (rc < 0) { ssh_set_error_oom(session); - return SSH_ERROR; + 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"); - return SSH_ERROR; + goto error; } /* privkey is not allocated */ rc = ssh_get_key_params(session, &privkey); if (rc == SSH_ERROR) { - return SSH_ERROR; + goto error; } rc = make_sessionid(session); if (rc != SSH_OK) { ssh_set_error(session, SSH_FATAL, "Could not create a session id"); - return SSH_ERROR; + goto error; } /* add host's public key */ @@ -239,29 +226,37 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){ session->next_crypto->server_pubkey); if (rc < 0) { ssh_set_error_oom(session); - return SSH_ERROR; + 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); - return SSH_ERROR; + 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"); - return SSH_ERROR; + 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); - return SSH_ERROR; + goto error; } SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent"); @@ -273,7 +268,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){ /* Send the MSG_NEWKEYS */ rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); if (rc < 0) { - return SSH_ERROR;; + goto error; } session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; @@ -281,6 +276,9 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){ SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); return rc; +error: + ssh_buffer_reinit(session->out_buffer); + return SSH_ERROR; } #endif /* WITH_SERVER */ diff --git a/libssh/src/dh.c b/libssh/src/dh.c index 5ebbc91e..e489a1d5 100644 --- a/libssh/src/dh.c +++ b/libssh/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 + * Copyright (c) 2003-2013 by Aris Adamantiadis + * Copyright (c) 2009-2013 by Andreas Schneider * Copyright (c) 2012 by Dmitriy Kuznetsov * * The SSH Library is free software; you can redistribute it and/or modify @@ -60,6 +60,7 @@ #include "libssh/dh.h" #include "libssh/ssh2.h" #include "libssh/pki.h" +#include "libssh/bignum.h" /* todo: remove it */ #include "libssh/string.h" @@ -170,7 +171,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; @@ -225,20 +226,6 @@ void ssh_crypto_finalize(void) { } } -/* prints the bignum on stderr */ -void ssh_print_bignum(const char *which, bignum num) { -#ifdef HAVE_LIBGCRYPT - unsigned char *hex = NULL; - bignum_bn2hex(num, &hex); -#elif defined HAVE_LIBCRYPTO - char *hex = NULL; - hex = bignum_bn2hex(num); -#endif - fprintf(stderr, "%s value: ", which); - fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex); - SAFE_FREE(hex); -} - int dh_generate_x(ssh_session session) { session->next_crypto->x = bignum_new(); if (session->next_crypto->x == NULL) { @@ -351,62 +338,6 @@ int dh_generate_f(ssh_session session) { return 0; } -ssh_string make_bignum_string(bignum num) { - ssh_string ptr = NULL; - int pad = 0; - unsigned int len = bignum_num_bytes(num); - unsigned int bits = bignum_num_bits(num); - - if (len == 0) { - return NULL; - } - - /* If the first bit is set we have a negative number */ - if (!(bits % 8) && bignum_is_bit_set(num, bits - 1)) { - pad++; - } - -#ifdef DEBUG_CRYPTO - fprintf(stderr, "%d bits, %d bytes, %d padding\n", bits, len, pad); -#endif /* DEBUG_CRYPTO */ - - ptr = ssh_string_new(len + pad); - if (ptr == NULL) { - return NULL; - } - - /* We have a negative number so we need a leading zero */ - if (pad) { - ptr->data[0] = 0; - } - -#ifdef HAVE_LIBGCRYPT - bignum_bn2bin(num, len, ptr->data + pad); -#elif HAVE_LIBCRYPTO - bignum_bn2bin(num, ptr->data + pad); -#endif - - return ptr; -} - -bignum make_string_bn(ssh_string string){ - bignum bn = NULL; - unsigned int len = ssh_string_len(string); - -#ifdef DEBUG_CRYPTO - fprintf(stderr, "Importing a %d bits, %d bytes object ...\n", - len * 8, len); -#endif /* DEBUG_CRYPTO */ - -#ifdef HAVE_LIBGCRYPT - bignum_bin2bn(string->data, len, &bn); -#elif defined HAVE_LIBCRYPTO - bn = bignum_bin2bn(string->data, len, NULL); -#endif - - return bn; -} - ssh_string dh_get_e(ssh_session session) { return make_bignum_string(session->next_crypto->e); } @@ -504,10 +435,6 @@ int ssh_client_dh_init(ssh_session session){ ssh_string e = NULL; int rc; - if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_INIT) < 0) { - goto error; - } - if (dh_generate_x(session) < 0) { goto error; } @@ -520,9 +447,11 @@ int ssh_client_dh_init(ssh_session session){ goto error; } - if (buffer_add_ssh_string(session->out_buffer, e) < 0) { + rc = ssh_buffer_pack(session->out_buffer, "bS", SSH2_MSG_KEXDH_INIT, e); + if (rc != SSH_OK) { goto error; } + ssh_string_burn(e); ssh_string_free(e); e=NULL; @@ -587,218 +516,180 @@ error: return SSH_ERROR; } - -/* -static void sha_add(ssh_string str,SHACTX ctx){ - sha1_update(ctx,str,string_len(str)+4); -#ifdef DEBUG_CRYPTO - ssh_print_hexa("partial hashed sessionid",str,string_len(str)+4); -#endif -} -*/ - int make_sessionid(ssh_session session) { - ssh_string num = NULL; - ssh_string str = NULL; - ssh_buffer server_hash = NULL; - ssh_buffer client_hash = NULL; - ssh_buffer buf = NULL; - uint32_t len; - int rc = SSH_ERROR; + ssh_string num = NULL; + ssh_buffer server_hash = NULL; + ssh_buffer client_hash = NULL; + ssh_buffer buf = NULL; + int rc = SSH_ERROR; - buf = ssh_buffer_new(); - if (buf == NULL) { - return rc; - } - - str = ssh_string_from_char(session->clientbanner); - if (str == NULL) { - goto error; - } - - if (buffer_add_ssh_string(buf, str) < 0) { - goto error; - } - ssh_string_free(str); - - str = ssh_string_from_char(session->serverbanner); - if (str == NULL) { - goto error; - } - - if (buffer_add_ssh_string(buf, str) < 0) { - goto error; - } - - if (session->client) { - server_hash = session->in_hashbuf; - client_hash = session->out_hashbuf; - } else { - server_hash = session->out_hashbuf; - client_hash = session->in_hashbuf; - } - - if (buffer_add_u32(server_hash, 0) < 0) { - goto error; - } - if (buffer_add_u8(server_hash, 0) < 0) { - goto error; - } - if (buffer_add_u32(client_hash, 0) < 0) { - goto error; - } - if (buffer_add_u8(client_hash, 0) < 0) { - goto error; - } - - len = ntohl(buffer_get_rest_len(client_hash)); - if (buffer_add_u32(buf,len) < 0) { - goto error; - } - if (buffer_add_data(buf, buffer_get_rest(client_hash), - buffer_get_rest_len(client_hash)) < 0) { - goto error; - } - - len = ntohl(buffer_get_rest_len(server_hash)); - if (buffer_add_u32(buf, len) < 0) { - goto error; - } - if (buffer_add_data(buf, buffer_get_rest(server_hash), - buffer_get_rest_len(server_hash)) < 0) { - goto error; - } - - len = ssh_string_len(session->next_crypto->server_pubkey) + 4; - if (buffer_add_data(buf, session->next_crypto->server_pubkey, len) < 0) { - goto error; - } - if(session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1 || - session->next_crypto->kex_type == SSH_KEX_DH_GROUP14_SHA1) { - - num = make_bignum_string(session->next_crypto->e); - if (num == NULL) { - goto error; + buf = ssh_buffer_new(); + if (buf == NULL) { + return rc; } - len = ssh_string_len(num) + 4; - if (buffer_add_data(buf, num, len) < 0) { - goto error; + rc = ssh_buffer_pack(buf, + "ss", + session->clientbanner, + session->serverbanner); + if (rc == SSH_ERROR) { + goto error; } - ssh_string_free(num); - num = make_bignum_string(session->next_crypto->f); - if (num == NULL) { - goto error; + if (session->client) { + server_hash = session->in_hashbuf; + client_hash = session->out_hashbuf; + } else { + server_hash = session->out_hashbuf; + client_hash = session->in_hashbuf; } - len = ssh_string_len(num) + 4; - if (buffer_add_data(buf, num, len) < 0) { - goto error; + /* + * Handle the two final fields for the KEXINIT message (RFC 4253 7.1): + * + * boolean first_kex_packet_follows + * uint32 0 (reserved for future extension) + */ + rc = buffer_add_u8(server_hash, 0); + if (rc < 0) { + goto error; + } + rc = buffer_add_u32(server_hash, 0); + if (rc < 0) { + goto error; } - ssh_string_free(num); + /* These fields are handled for the server case in ssh_packet_kexinit. */ + if (session->client) { + rc = buffer_add_u8(client_hash, 0); + if (rc < 0) { + goto error; + } + rc = buffer_add_u32(client_hash, 0); + if (rc < 0) { + goto error; + } + } + + rc = ssh_buffer_pack(buf, + "dPdPS", + buffer_get_rest_len(client_hash), + buffer_get_rest_len(client_hash), + buffer_get_rest(client_hash), + buffer_get_rest_len(server_hash), + buffer_get_rest_len(server_hash), + buffer_get_rest(server_hash), + session->next_crypto->server_pubkey); + + if(rc != SSH_OK){ + goto error; + } + + if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1 || + session->next_crypto->kex_type == SSH_KEX_DH_GROUP14_SHA1) { + rc = ssh_buffer_pack(buf, + "BB", + session->next_crypto->e, + session->next_crypto->f); + if (rc != SSH_OK) { + goto error; + } + #ifdef HAVE_ECDH - } else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256){ - if(session->next_crypto->ecdh_client_pubkey == NULL || - session->next_crypto->ecdh_server_pubkey == NULL){ - SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing"); - goto error; - } - rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_client_pubkey); - if (rc < 0) { - goto error; - } - rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_server_pubkey); - if (rc < 0) { - goto error; - } + } else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) { + if (session->next_crypto->ecdh_client_pubkey == NULL || + session->next_crypto->ecdh_server_pubkey == NULL) { + SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing"); + goto error; + } + rc = ssh_buffer_pack(buf, + "SS", + session->next_crypto->ecdh_client_pubkey, + session->next_crypto->ecdh_server_pubkey); + if (rc != SSH_OK) { + 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); - if (num == NULL) { - goto error; - } + } else if (session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG) { + rc = ssh_buffer_pack(buf, + "dPdP", + CURVE25519_PUBKEY_SIZE, + (size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_client_pubkey, + CURVE25519_PUBKEY_SIZE, + (size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_server_pubkey); - len = ssh_string_len(num) + 4; - if (buffer_add_data(buf, num, len) < 0) { - goto error; - } + if (rc != SSH_OK) { + goto error; + } +#endif + } + rc = ssh_buffer_pack(buf, "B", session->next_crypto->k); + if (rc != SSH_OK) { + goto error; + } #ifdef DEBUG_CRYPTO - ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf)); + ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf)); #endif - switch(session->next_crypto->kex_type){ + switch (session->next_crypto->kex_type) { case SSH_KEX_DH_GROUP1_SHA1: case SSH_KEX_DH_GROUP14_SHA1: - session->next_crypto->digest_len = SHA_DIGEST_LENGTH; - session->next_crypto->mac_type = SSH_MAC_SHA1; - session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len); - if(session->next_crypto->secret_hash == NULL){ - ssh_set_error_oom(session); - goto error; - } - sha1(buffer_get_rest(buf), buffer_get_rest_len(buf), - session->next_crypto->secret_hash); - break; + session->next_crypto->digest_len = SHA_DIGEST_LENGTH; + session->next_crypto->mac_type = SSH_MAC_SHA1; + session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len); + if (session->next_crypto->secret_hash == NULL) { + ssh_set_error_oom(session); + goto error; + } + sha1(buffer_get_rest(buf), buffer_get_rest_len(buf), + session->next_crypto->secret_hash); + break; case SSH_KEX_ECDH_SHA2_NISTP256: case SSH_KEX_CURVE25519_SHA256_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); - if(session->next_crypto->secret_hash == NULL){ - ssh_set_error_oom(session); - goto error; - } - sha256(buffer_get_rest(buf), buffer_get_rest_len(buf), - session->next_crypto->secret_hash); - break; - } - /* During the first kex, secret hash and session ID are equal. However, after - * a key re-exchange, a new secret hash is calculated. This hash will not replace - * but complement existing session id. - */ - if (!session->next_crypto->session_id){ - session->next_crypto->session_id = malloc(session->next_crypto->digest_len); - if (session->next_crypto->session_id == NULL){ - ssh_set_error_oom(session); - goto error; - } - memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash, - session->next_crypto->digest_len); - } + 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); + if (session->next_crypto->secret_hash == NULL) { + ssh_set_error_oom(session); + goto error; + } + sha256(buffer_get_rest(buf), buffer_get_rest_len(buf), + session->next_crypto->secret_hash); + break; + } + /* During the first kex, secret hash and session ID are equal. However, after + * a key re-exchange, a new secret hash is calculated. This hash will not replace + * but complement existing session id. + */ + if (!session->next_crypto->session_id) { + session->next_crypto->session_id = malloc(session->next_crypto->digest_len); + if (session->next_crypto->session_id == NULL) { + ssh_set_error_oom(session); + goto error; + } + memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash, + session->next_crypto->digest_len); + } #ifdef DEBUG_CRYPTO - printf("Session hash: \n"); - ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len); - ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len); + printf("Session hash: \n"); + ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len); + ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len); #endif - rc = SSH_OK; + rc = SSH_OK; error: - ssh_buffer_free(buf); - ssh_buffer_free(client_hash); - ssh_buffer_free(server_hash); + ssh_buffer_free(buf); + ssh_buffer_free(client_hash); + ssh_buffer_free(server_hash); - session->in_hashbuf = NULL; - session->out_hashbuf = NULL; + session->in_hashbuf = NULL; + session->out_hashbuf = NULL; - ssh_string_free(str); - ssh_string_free(num); + ssh_string_free(num); - return rc; + return rc; } int hashbufout_add_cookie(ssh_session session) { @@ -808,20 +699,20 @@ int hashbufout_add_cookie(ssh_session session) { } if (buffer_add_u8(session->out_hashbuf, 20) < 0) { - buffer_reinit(session->out_hashbuf); + ssh_buffer_reinit(session->out_hashbuf); return -1; } if (session->server) { - if (buffer_add_data(session->out_hashbuf, + if (ssh_buffer_add_data(session->out_hashbuf, session->next_crypto->server_kex.cookie, 16) < 0) { - buffer_reinit(session->out_hashbuf); + ssh_buffer_reinit(session->out_hashbuf); return -1; } } else { - if (buffer_add_data(session->out_hashbuf, + if (ssh_buffer_add_data(session->out_hashbuf, session->next_crypto->client_kex.cookie, 16) < 0) { - buffer_reinit(session->out_hashbuf); + ssh_buffer_reinit(session->out_hashbuf); return -1; } } @@ -836,11 +727,11 @@ int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) { } if (buffer_add_u8(session->in_hashbuf, 20) < 0) { - buffer_reinit(session->in_hashbuf); + ssh_buffer_reinit(session->in_hashbuf); return -1; } - if (buffer_add_data(session->in_hashbuf,cookie, 16) < 0) { - buffer_reinit(session->in_hashbuf); + if (ssh_buffer_add_data(session->in_hashbuf,cookie, 16) < 0) { + ssh_buffer_reinit(session->in_hashbuf); return -1; } @@ -848,8 +739,10 @@ int hashbufin_add_cookie(ssh_session session, unsigned char *cookie) { } static int generate_one_key(ssh_string k, - struct ssh_crypto_struct *crypto, unsigned char *output, char letter) { + struct ssh_crypto_struct *crypto, unsigned char **output, char letter, size_t requested_size) { ssh_mac_ctx ctx; + unsigned char *tmp; + size_t size = crypto->digest_len; ctx=ssh_mac_ctx_init(crypto->mac_type); if (ctx == NULL) { @@ -860,14 +753,32 @@ static int generate_one_key(ssh_string k, ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len); ssh_mac_update(ctx, &letter, 1); ssh_mac_update(ctx, crypto->session_id, crypto->digest_len); - ssh_mac_final(output, ctx); + ssh_mac_final(*output, ctx); + + while(requested_size > size) { + tmp = realloc(*output, size + crypto->digest_len); + if (tmp == NULL) { + return -1; + } + *output = tmp; + + ctx = ssh_mac_ctx_init(crypto->mac_type); + if (ctx == NULL) { + return -1; + } + ssh_mac_update(ctx, k, ssh_string_len(k) + 4); + ssh_mac_update(ctx, crypto->secret_hash, + crypto->digest_len); + ssh_mac_update(ctx, tmp, size); + ssh_mac_final(tmp + size, ctx); + size += crypto->digest_len; + } return 0; } 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; int rc = -1; @@ -892,88 +803,71 @@ int generate_session_keys(ssh_session session) { /* IV */ if (session->client) { - if (generate_one_key(k_string, crypto, crypto->encryptIV, 'A') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->encryptIV, 'A', crypto->digest_len); + if (rc < 0) { goto error; } - if (generate_one_key(k_string, crypto, crypto->decryptIV, 'B') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->decryptIV, 'B', crypto->digest_len); + if (rc < 0) { goto error; } } else { - if (generate_one_key(k_string, crypto, crypto->decryptIV, 'A') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->decryptIV, 'A', crypto->digest_len); + if (rc < 0) { goto error; } - if (generate_one_key(k_string, crypto, crypto->encryptIV, 'B') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->encryptIV, 'B', crypto->digest_len); + if (rc < 0) { goto error; } } if (session->client) { - if (generate_one_key(k_string, crypto, crypto->encryptkey, 'C') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->encryptkey, 'C', crypto->out_cipher->keysize / 8); + if (rc < 0) { goto error; } - if (generate_one_key(k_string, crypto, crypto->decryptkey, 'D') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->decryptkey, 'D', crypto->in_cipher->keysize / 8); + if (rc < 0) { goto error; } } else { - if (generate_one_key(k_string, crypto, crypto->decryptkey, 'C') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->decryptkey, 'C', crypto->in_cipher->keysize / 8); + if (rc < 0) { goto error; } - if (generate_one_key(k_string, crypto, crypto->encryptkey, 'D') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->encryptkey, 'D', crypto->out_cipher->keysize / 8); + if (rc < 0) { goto error; } } - /* 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; - ctx = ssh_mac_ctx_init(crypto->mac_type); - if (ctx == NULL) { - goto error; - } - ssh_mac_update(ctx, k_string, ssh_string_len(k_string) + 4); - ssh_mac_update(ctx, crypto->secret_hash, - crypto->digest_len); - ssh_mac_update(ctx, crypto->encryptkey, crypto->digest_len); - ssh_mac_final(crypto->encryptkey + crypto->digest_len, ctx); - } - - if (crypto->in_cipher->keysize > crypto->digest_len * 8) { - crypto->decryptkey = realloc(crypto->decryptkey, crypto->digest_len *2); - if(crypto->decryptkey == NULL) - goto error; - ctx = ssh_mac_ctx_init(crypto->mac_type); - ssh_mac_update(ctx, k_string, ssh_string_len(k_string) + 4); - ssh_mac_update(ctx, crypto->secret_hash, - crypto->digest_len); - ssh_mac_update(ctx, crypto->decryptkey, crypto->digest_len); - ssh_mac_final(crypto->decryptkey + crypto->digest_len, ctx); - } if(session->client) { - if (generate_one_key(k_string, crypto, crypto->encryptMAC, 'E') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->encryptMAC, 'E', hmac_digest_len(crypto->out_hmac)); + if (rc < 0) { goto error; } - if (generate_one_key(k_string, crypto, crypto->decryptMAC, 'F') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->decryptMAC, 'F', hmac_digest_len(crypto->in_hmac)); + if (rc < 0) { goto error; } } else { - if (generate_one_key(k_string, crypto, crypto->decryptMAC, 'E') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->decryptMAC, 'E', hmac_digest_len(crypto->in_hmac)); + if (rc < 0) { goto error; } - if (generate_one_key(k_string, crypto, crypto->encryptMAC, 'F') < 0) { + rc = generate_one_key(k_string, crypto, &crypto->encryptMAC, 'F', hmac_digest_len(crypto->out_hmac)); + if (rc < 0) { goto error; } } #ifdef DEBUG_CRYPTO - ssh_print_hexa("Encrypt IV", crypto->encryptIV, SHA_DIGEST_LEN); - ssh_print_hexa("Decrypt IV", crypto->decryptIV, SHA_DIGEST_LEN); - ssh_print_hexa("Encryption key", crypto->encryptkey, - crypto->out_cipher->keysize); - ssh_print_hexa("Decryption key", crypto->decryptkey, - crypto->in_cipher->keysize); - ssh_print_hexa("Encryption MAC", crypto->encryptMAC, SHA_DIGEST_LEN); - ssh_print_hexa("Decryption MAC", crypto->decryptMAC, 20); + ssh_print_hexa("Encrypt IV", crypto->encryptIV, crypto->digest_len); + ssh_print_hexa("Decrypt IV", crypto->decryptIV, crypto->digest_len); + ssh_print_hexa("Encryption key", crypto->encryptkey, crypto->out_cipher->keysize / 8); + ssh_print_hexa("Decryption key", crypto->decryptkey, crypto->in_cipher->keysize / 8); + ssh_print_hexa("Encryption MAC", crypto->encryptMAC, hmac_digest_len(crypto->out_hmac)); + ssh_print_hexa("Decryption MAC", crypto->decryptMAC, hmac_digest_len(crypto->in_hmac)); #endif rc = 0; diff --git a/libssh/src/ecdh.c b/libssh/src/ecdh.c index 3f065e7e..e6310b4c 100644 --- a/libssh/src/ecdh.c +++ b/libssh/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 @@ -26,6 +26,7 @@ #include "libssh/buffer.h" #include "libssh/ssh2.h" #include "libssh/pki.h" +#include "libssh/bignum.h" #ifdef HAVE_ECDH #include @@ -154,7 +155,7 @@ static int ecdh_build_k(ssh_session session) { return -1; } - BN_bin2bn(buffer, len, session->next_crypto->k); + bignum_bin2bn(buffer, len, session->next_crypto->k); free(buffer); EC_KEY_free(session->next_crypto->ecdh_privkey); @@ -285,12 +286,6 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ session->next_crypto->ecdh_privkey = ecdh_key; session->next_crypto->ecdh_server_pubkey = q_s_string; - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY); - if (rc < 0) { - ssh_set_error_oom(session); - return SSH_ERROR; - } - /* build k and session_id */ rc = ecdh_build_k(session); if (rc < 0) { @@ -310,30 +305,22 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ return SSH_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); - return SSH_ERROR; - } - - /* add ecdh public key */ - rc = buffer_add_ssh_string(session->out_buffer, q_s_string); - if (rc < 0) { - ssh_set_error_oom(session); - return SSH_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"); return SSH_ERROR; } - rc = buffer_add_ssh_string(session->out_buffer, sig_blob); + rc = ssh_buffer_pack(session->out_buffer, + "bSSS", + SSH2_MSG_KEXDH_REPLY, + session->next_crypto->server_pubkey, /* host's pubkey */ + q_s_string, /* ecdh public key */ + sig_blob); /* signature blob */ + ssh_string_free(sig_blob); - if (rc < 0) { + + if (rc != SSH_OK) { ssh_set_error_oom(session); return SSH_ERROR; } diff --git a/libssh/src/ed25519.c b/libssh/src/ed25519.c new file mode 100644 index 00000000..2ae0ef4e --- /dev/null +++ b/libssh/src/ed25519.c @@ -0,0 +1,222 @@ +/* $OpenBSD: ed25519.c,v 1.3 2013/12/09 11:03:45 markus Exp $ */ + +/* + * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange, + * Peter Schwabe, Bo-Yin Yang. + * Copied from supercop-20130419/crypto_sign/ed25519/ref/ed25519.c + */ + +#include "config.h" + +#include "libssh/libcrypto.h" +#include "libssh/wrapper.h" +#include "libssh/ge25519.h" +#include "libssh/sc25519.h" +#include "libssh/ed25519.h" + +/* + * Public Domain, Author: Daniel J. Bernstein + * Copied from nacl-20110221/crypto_verify/32/ref/verify.c + */ + +static int crypto_verify_32(const unsigned char *x,const unsigned char *y) +{ + unsigned int differentbits = 0; +#define F(i) differentbits |= x[i] ^ y[i]; + F(0) + F(1) + F(2) + F(3) + F(4) + F(5) + F(6) + F(7) + F(8) + F(9) + F(10) + F(11) + F(12) + F(13) + F(14) + F(15) + F(16) + F(17) + F(18) + F(19) + F(20) + F(21) + F(22) + F(23) + F(24) + F(25) + F(26) + F(27) + F(28) + F(29) + F(30) + F(31) + + return (1 & ((differentbits - 1) >> 8)) - 1; +} + +static void get_hram(unsigned char *hram, + const unsigned char *sm, + const unsigned char *pk, + unsigned char *playground, + unsigned long long smlen) +{ + unsigned long long i; + SHA512CTX ctx; + for (i = 0;i < 32;++i) playground[i] = sm[i]; + for (i = 32;i < 64;++i) playground[i] = pk[i-32]; + for (i = 64;i < smlen;++i) playground[i] = sm[i]; + + ctx = sha512_init(); + sha512_update(ctx, playground, smlen); + sha512_final(hram, ctx); +} + + +int crypto_sign_ed25519_keypair(unsigned char *pk, + unsigned char *sk) +{ + sc25519 scsk; + ge25519 gepk; + SHA512CTX ctx; + unsigned char extsk[64]; + int i; + int rc; + + rc = ssh_get_random(sk, 32, 0); + if (rc < 0){ + return -1; + } + + ctx = sha512_init(); + sha512_update(ctx, sk, 32); + sha512_final(extsk, ctx); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; + + sc25519_from32bytes(&scsk,extsk); + + ge25519_scalarmult_base(&gepk, &scsk); + ge25519_pack(pk, &gepk); + for(i=0;i<32;i++) { + sk[32 + i] = pk[i]; + } + + return 0; +} + +int crypto_sign_ed25519(unsigned char *sm, + unsigned long long *smlen, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *sk) +{ + sc25519 sck, scs, scsk; + ge25519 ger; + SHA512CTX ctx; + unsigned char r[32]; + unsigned char s[32]; + unsigned char extsk[64]; + unsigned long long i; + unsigned char hmg[SHA512_DIGEST_LEN]; + unsigned char hram[SHA512_DIGEST_LEN]; + + ctx = sha512_init(); + sha512_update(ctx, sk, 32); + sha512_final(extsk, ctx); + + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; + + *smlen = mlen + 64; + for (i = 0;i < mlen; i++) { + sm[64 + i] = m[i]; + } + for (i = 0;i < 32; i++) { + sm[32 + i] = extsk[32+i]; + } + + /* Generate k as h(extsk[32],...,extsk[63],m) */ + ctx = sha512_init(); + sha512_update(ctx, sm + 32, mlen + 32); + sha512_final(hmg, ctx); + + /* Computation of R */ + sc25519_from64bytes(&sck, hmg); + ge25519_scalarmult_base(&ger, &sck); + ge25519_pack(r, &ger); + + /* Computation of s */ + for (i = 0; i < 32; i++) { + sm[i] = r[i]; + } + + get_hram(hram, sm, sk+32, sm, mlen+64); + + sc25519_from64bytes(&scs, hram); + sc25519_from32bytes(&scsk, extsk); + sc25519_mul(&scs, &scs, &scsk); + + sc25519_add(&scs, &scs, &sck); + + sc25519_to32bytes(s,&scs); /* cat s */ + for (i = 0;i < 32; i++) { + sm[32 + i] = s[i]; + } + + return 0; +} + +int crypto_sign_ed25519_open(unsigned char *m, + unsigned long long *mlen, + const unsigned char *sm, + unsigned long long smlen, + const unsigned char *pk) +{ + unsigned int i; + int ret; + unsigned char t2[32]; + ge25519 get1, get2; + sc25519 schram, scs; + unsigned char hram[SHA512_DIGEST_LEN]; + + *mlen = (unsigned long long) -1; + if (smlen < 64) return -1; + + if (ge25519_unpackneg_vartime(&get1, pk)) { + return -1; + } + + get_hram(hram,sm,pk,m,smlen); + + sc25519_from64bytes(&schram, hram); + + sc25519_from32bytes(&scs, sm+32); + + ge25519_double_scalarmult_vartime(&get2, + &get1, + &schram, + &ge25519_base, + &scs); + ge25519_pack(t2, &get2); + + ret = crypto_verify_32(sm, t2); + if (ret != 0) { + for (i = 0; i < smlen - 64; i++) { + m[i] = sm[i + 64]; + } + *mlen = smlen-64; + } else { + for (i = 0; i < smlen - 64; i++) { + m[i] = 0; + } + } + + return ret; +} diff --git a/libssh/src/error.c b/libssh/src/error.c index fbe0e787..bd755c4f 100644 --- a/libssh/src/error.c +++ b/libssh/src/error.c @@ -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 diff --git a/libssh/src/fe25519.c b/libssh/src/fe25519.c new file mode 100644 index 00000000..0cedd89d --- /dev/null +++ b/libssh/src/fe25519.c @@ -0,0 +1,416 @@ +/* + * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange, + * Peter Schwabe, Bo-Yin Yang. + * Copied from supercop-20130419/crypto_sign/ed25519/ref/fe25519.c + */ + +#define WINDOWSIZE 1 /* Should be 1,2, or 4 */ +#define WINDOWMASK ((1<>= 31; /* 1: yes; 0: no */ + return x; +} + +static uint32_t ge(uint32_t a,uint32_t b) /* 16-bit inputs */ +{ + unsigned int x = a; + + x -= (unsigned int) b; /* 0..65535: yes; 4294901761..4294967295: no */ + x >>= 31; /* 0: yes; 1: no */ + x ^= 1; /* 1: yes; 0: no */ + + return x; +} + +static uint32_t times19(uint32_t a) +{ + return (a << 4) + (a << 1) + a; +} + +static uint32_t times38(uint32_t a) +{ + return (a << 5) + (a << 2) + (a << 1); +} + +static void reduce_add_sub(fe25519 *r) +{ + uint32_t t; + int i,rep; + + for(rep = 0; rep < 4; rep++) { + t = r->v[31] >> 7; + r->v[31] &= 127; + t = times19(t); + r->v[0] += t; + for(i = 0; i < 31; i++) { + t = r->v[i] >> 8; + r->v[i+1] += t; + r->v[i] &= 255; + } + } +} + +static void reduce_mul(fe25519 *r) +{ + uint32_t t; + int i,rep; + + for(rep = 0; rep < 2; rep++) { + t = r->v[31] >> 7; + r->v[31] &= 127; + t = times19(t); + r->v[0] += t; + for(i = 0; i < 31; i++) { + t = r->v[i] >> 8; + r->v[i+1] += t; + r->v[i] &= 255; + } + } +} + +/* reduction modulo 2^255-19 */ +void fe25519_freeze(fe25519 *r) +{ + int i; + uint32_t m = equal(r->v[31],127); + + for (i = 30; i > 0; i--) { + m &= equal(r->v[i],255); + } + m &= ge(r->v[0],237); + + m = -m; + + r->v[31] -= m&127; + for (i = 30; i > 0; i--) { + r->v[i] -= m&255; + } + r->v[0] -= m&237; +} + +void fe25519_unpack(fe25519 *r, const unsigned char x[32]) +{ + int i; + + for (i = 0;i < 32; i++) { + r->v[i] = x[i]; + } + + r->v[31] &= 127; +} + +/* Assumes input x being reduced below 2^255 */ +void fe25519_pack(unsigned char r[32], const fe25519 *x) +{ + int i; + + fe25519 y = *x; + fe25519_freeze(&y); + + for (i = 0; i < 32; i++) { + r[i] = y.v[i]; + } +} + +int fe25519_iszero(const fe25519 *x) +{ + int i; + int r; + + fe25519 t = *x; + fe25519_freeze(&t); + + r = equal(t.v[0],0); + for (i = 1; i < 32; i++) { + r &= equal(t.v[i],0); + } + + return r; +} + +int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y) +{ + int i; + + fe25519 t1 = *x; + fe25519 t2 = *y; + fe25519_freeze(&t1); + fe25519_freeze(&t2); + + for (i = 0; i < 32; i++) { + if(t1.v[i] != t2.v[i]) { + return 0; + } + } + + return 1; +} + +void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b) +{ + int i; + uint32_t mask = b; + + mask = -mask; + + for (i = 0; i < 32; i++) { + r->v[i] ^= mask & (x->v[i] ^ r->v[i]); + } +} + +unsigned char fe25519_getparity(const fe25519 *x) +{ + fe25519 t = *x; + fe25519_freeze(&t); + + return t.v[0] & 1; +} + +void fe25519_setone(fe25519 *r) +{ + int i; + + r->v[0] = 1; + for (i = 1; i < 32; i++) { + r->v[i]=0; + } +} + +void fe25519_setzero(fe25519 *r) +{ + int i; + + for (i = 0; i < 32; i++) { + r->v[i]=0; + } +} + +void fe25519_neg(fe25519 *r, const fe25519 *x) +{ + fe25519 t; + int i; + + for (i = 0; i < 32; i++) { + t.v[i]=x->v[i]; + } + + fe25519_setzero(r); + fe25519_sub(r, r, &t); +} + +void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y) +{ + int i; + + for (i = 0; i < 32; i++) { + r->v[i] = x->v[i] + y->v[i]; + } + + reduce_add_sub(r); +} + +void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y) +{ + int i; + uint32_t t[32]; + + t[0] = x->v[0] + 0x1da; + t[31] = x->v[31] + 0xfe; + + for (i = 1; i < 31; i++) { + t[i] = x->v[i] + 0x1fe; + } + + for (i = 0; i < 32; i++) { + r->v[i] = t[i] - y->v[i]; + } + + reduce_add_sub(r); +} + +void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y) +{ + int i,j; + uint32_t t[63]; + + for (i = 0; i < 63; i++) { + t[i] = 0; + } + + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + t[i+j] += x->v[i] * y->v[j]; + } + } + + for (i = 32; i < 63; i++) { + r->v[i-32] = t[i-32] + times38(t[i]); + } + r->v[31] = t[31]; /* result now in r[0]...r[31] */ + + reduce_mul(r); +} + +void fe25519_square(fe25519 *r, const fe25519 *x) +{ + fe25519_mul(r, x, x); +} + +void fe25519_invert(fe25519 *r, const fe25519 *x) +{ + fe25519 z2; + fe25519 z9; + fe25519 z11; + fe25519 z2_5_0; + fe25519 z2_10_0; + fe25519 z2_20_0; + fe25519 z2_50_0; + fe25519 z2_100_0; + fe25519 t0; + fe25519 t1; + int i; + + /* 2 */ fe25519_square(&z2, x); + /* 4 */ fe25519_square(&t1, &z2); + /* 8 */ fe25519_square(&t0, &t1); + /* 9 */ fe25519_mul(&z9, &t0, x); + /* 11 */ fe25519_mul(&z11, &z9, &z2); + /* 22 */ fe25519_square(&t0, &z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0, &t0, &z9); + + /* 2^6 - 2^1 */ fe25519_square(&t0, &z2_5_0); + /* 2^7 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^8 - 2^3 */ fe25519_square(&t0, &t1); + /* 2^9 - 2^4 */ fe25519_square(&t1, &t0); + /* 2^10 - 2^5 */ fe25519_square(&t0, &t1); + /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0, &t0, &z2_5_0); + + /* 2^11 - 2^1 */ fe25519_square(&t0, &z2_10_0); + /* 2^12 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0, &t1, &z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(&t0, &z2_20_0); + /* 2^22 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1,&t0); + } + /* 2^40 - 2^0 */ fe25519_mul(&t0, &t1, &z2_20_0); + + /* 2^41 - 2^1 */ fe25519_square(&t1, &t0); + /* 2^42 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^50 - 2^10 */ for (i = 2; i < 10;i += 2) { + fe25519_square(&t1, &t0); + fe25519_square(&t0, &t1); + } + /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t0,&z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(&t0, &z2_50_0); + /* 2^52 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1,&t0); + } + /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0, &t1, &z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(&t1, &z2_100_0); + /* 2^102 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { + fe25519_square(&t1, &t0); + fe25519_square(&t0,&t1); + } + /* 2^200 - 2^0 */ fe25519_mul(&t1, &t0, &z2_100_0); + + /* 2^201 - 2^1 */ fe25519_square(&t0, &t1); + /* 2^202 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1,&t0); + } + /* 2^250 - 2^0 */ fe25519_mul(&t0, &t1, &z2_50_0); + + /* 2^251 - 2^1 */ fe25519_square(&t1, &t0); + /* 2^252 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^253 - 2^3 */ fe25519_square(&t1, &t0); + /* 2^254 - 2^4 */ fe25519_square(&t0, &t1); + /* 2^255 - 2^5 */ fe25519_square(&t1, &t0); + /* 2^255 - 21 */ fe25519_mul(r, &t1, &z11); +} + +void fe25519_pow2523(fe25519 *r, const fe25519 *x) +{ + fe25519 z2; + fe25519 z9; + fe25519 z11; + fe25519 z2_5_0; + fe25519 z2_10_0; + fe25519 z2_20_0; + fe25519 z2_50_0; + fe25519 z2_100_0; + fe25519 t; + int i; + + /* 2 */ fe25519_square(&z2, x); + /* 4 */ fe25519_square(&t, &z2); + /* 8 */ fe25519_square(&t, &t); + /* 9 */ fe25519_mul(&z9, &t, x); + /* 11 */ fe25519_mul(&z11, &z9, &z2); + /* 22 */ fe25519_square(&t, &z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0, &t, &z9); + + /* 2^6 - 2^1 */ fe25519_square(&t, &z2_5_0); + /* 2^10 - 2^5 */ for (i = 1; i < 5; i++) { + fe25519_square(&t,&t); + } + /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0, &t, &z2_5_0); + + /* 2^11 - 2^1 */ fe25519_square(&t, &z2_10_0); + /* 2^20 - 2^10 */ for (i = 1; i < 10; i++) { + fe25519_square(&t, &t); + } + /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0, &t, &z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(&t, &z2_20_0); + /* 2^40 - 2^20 */ for (i = 1; i < 20; i++) { + fe25519_square(&t,&t); + } + /* 2^40 - 2^0 */ fe25519_mul(&t, &t, &z2_20_0); + + /* 2^41 - 2^1 */ fe25519_square(&t, &t); + /* 2^50 - 2^10 */ for (i = 1; i < 10; i++) { + fe25519_square(&t,&t); + } + /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0, &t, &z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(&t, &z2_50_0); + /* 2^100 - 2^50 */ for (i = 1; i < 50; i++) { + fe25519_square(&t, &t); + } + /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0, &t, &z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(&t, &z2_100_0); + /* 2^200 - 2^100 */ for (i = 1; i < 100; i++) { + fe25519_square(&t, &t); + } + /* 2^200 - 2^0 */ fe25519_mul(&t, &t, &z2_100_0); + + /* 2^201 - 2^1 */ fe25519_square(&t, &t); + /* 2^250 - 2^50 */ for (i = 1; i < 50; i++) { + fe25519_square(&t, &t); + } + /* 2^250 - 2^0 */ fe25519_mul(&t, &t, &z2_50_0); + + /* 2^251 - 2^1 */ fe25519_square(&t, &t); + /* 2^252 - 2^2 */ fe25519_square(&t, &t); + /* 2^252 - 3 */ fe25519_mul(r, &t, x); +} diff --git a/libssh/src/ge25519.c b/libssh/src/ge25519.c new file mode 100644 index 00000000..20a33d1e --- /dev/null +++ b/libssh/src/ge25519.c @@ -0,0 +1,367 @@ +/* $OpenBSD: ge25519.c,v 1.3 2013/12/09 11:03:45 markus Exp $ */ + +/* + * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange, + * Peter Schwabe, Bo-Yin Yang. + * Copied from supercop-20130419/crypto_sign/ed25519/ref/ge25519.c + */ + +#include "libssh/fe25519.h" +#include "libssh/sc25519.h" +#include "libssh/ge25519.h" + +/* + * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2 + * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555 + * Base point: (15112221349535400772501151409588531511454012693041857206046113283949847762202,46316835694926478169428394003475163141307993866256225615783033603165251855960); + */ + +/* d */ +static const fe25519 ge25519_ecd = { + {0xA3, 0x78, 0x59, 0x13, 0xCA, 0x4D, 0xEB, 0x75, + 0xAB, 0xD8, 0x41, 0x41, 0x4D, 0x0A, 0x70, 0x00, + 0x98, 0xE8, 0x79, 0x77, 0x79, 0x40, 0xC7, 0x8C, + 0x73, 0xFE, 0x6F, 0x2B, 0xEE, 0x6C, 0x03, 0x52} +}; + +/* 2*d */ +static const fe25519 ge25519_ec2d = { + {0x59, 0xF1, 0xB2, 0x26, 0x94, 0x9B, 0xD6, 0xEB, + 0x56, 0xB1, 0x83, 0x82, 0x9A, 0x14, 0xE0, 0x00, + 0x30, 0xD1, 0xF3, 0xEE, 0xF2, 0x80, 0x8E, 0x19, + 0xE7, 0xFC, 0xDF, 0x56, 0xDC, 0xD9, 0x06, 0x24} +}; + +/* sqrt(-1) */ +static const fe25519 ge25519_sqrtm1 = { + {0xB0, 0xA0, 0x0E, 0x4A, 0x27, 0x1B, 0xEE, 0xC4, + 0x78, 0xE4, 0x2F, 0xAD, 0x06, 0x18, 0x43, 0x2F, + 0xA7, 0xD7, 0xFB, 0x3D, 0x99, 0x00, 0x4D, 0x2B, + 0x0B, 0xDF, 0xC1, 0x4F, 0x80, 0x24, 0x83, 0x2B} +}; + +#define ge25519_p3 ge25519 + +typedef struct { + fe25519 x; + fe25519 z; + fe25519 y; + fe25519 t; +} ge25519_p1p1; + +typedef struct { + fe25519 x; + fe25519 y; + fe25519 z; +} ge25519_p2; + +typedef struct { + fe25519 x; + fe25519 y; +} ge25519_aff; + + +/* Packed coordinates of the base point */ +const ge25519 ge25519_base = { + {{0x1A, 0xD5, 0x25, 0x8F, 0x60, 0x2D, 0x56, 0xC9, + 0xB2, 0xA7, 0x25, 0x95, 0x60, 0xC7, 0x2C, 0x69, + 0x5C, 0xDC, 0xD6, 0xFD, 0x31, 0xE2, 0xA4, 0xC0, + 0xFE, 0x53, 0x6E, 0xCD, 0xD3, 0x36, 0x69, 0x21}}, + {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0xA3, 0xDD, 0xB7, 0xA5, 0xB3, 0x8A, 0xDE, 0x6D, + 0xF5, 0x52, 0x51, 0x77, 0x80, 0x9F, 0xF0, 0x20, + 0x7D, 0xE3, 0xAB, 0x64, 0x8E, 0x4E, 0xEA, 0x66, + 0x65, 0x76, 0x8B, 0xD7, 0x0F, 0x5F, 0x87, 0x67}} +}; + +/* Multiples of the base point in affine representation */ +static const ge25519_aff ge25519_base_multiples_affine[425] = { +#include "ge25519_base.data" +}; + +static void p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p) +{ + fe25519_mul(&r->x, &p->x, &p->t); + fe25519_mul(&r->y, &p->y, &p->z); + fe25519_mul(&r->z, &p->z, &p->t); +} + +static void p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p) +{ + p1p1_to_p2((ge25519_p2 *)r, p); + fe25519_mul(&r->t, &p->x, &p->y); +} + +static void ge25519_mixadd2(ge25519_p3 *r, const ge25519_aff *q) +{ + fe25519 a,b,t1,t2,c,d,e,f,g,h,qt; + fe25519_mul(&qt, &q->x, &q->y); + fe25519_sub(&a, &r->y, &r->x); /* A = (Y1-X1)*(Y2-X2) */ + fe25519_add(&b, &r->y, &r->x); /* B = (Y1+X1)*(Y2+X2) */ + fe25519_sub(&t1, &q->y, &q->x); + fe25519_add(&t2, &q->y, &q->x); + fe25519_mul(&a, &a, &t1); + fe25519_mul(&b, &b, &t2); + fe25519_sub(&e, &b, &a); /* E = B-A */ + fe25519_add(&h, &b, &a); /* H = B+A */ + fe25519_mul(&c, &r->t, &qt); /* C = T1*k*T2 */ + fe25519_mul(&c, &c, &ge25519_ec2d); + fe25519_add(&d, &r->z, &r->z); /* D = Z1*2 */ + fe25519_sub(&f, &d, &c); /* F = D-C */ + fe25519_add(&g, &d, &c); /* G = D+C */ + fe25519_mul(&r->x, &e, &f); + fe25519_mul(&r->y, &h, &g); + fe25519_mul(&r->z, &g, &f); + fe25519_mul(&r->t, &e, &h); +} + +static void add_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_p3 *q) +{ + fe25519 a, b, c, d, t; + + fe25519_sub(&a, &p->y, &p->x); /* A = (Y1-X1)*(Y2-X2) */ + fe25519_sub(&t, &q->y, &q->x); + fe25519_mul(&a, &a, &t); + fe25519_add(&b, &p->x, &p->y); /* B = (Y1+X1)*(Y2+X2) */ + fe25519_add(&t, &q->x, &q->y); + fe25519_mul(&b, &b, &t); + fe25519_mul(&c, &p->t, &q->t); /* C = T1*k*T2 */ + fe25519_mul(&c, &c, &ge25519_ec2d); + fe25519_mul(&d, &p->z, &q->z); /* D = Z1*2*Z2 */ + fe25519_add(&d, &d, &d); + fe25519_sub(&r->x, &b, &a); /* E = B-A */ + fe25519_sub(&r->t, &d, &c); /* F = D-C */ + fe25519_add(&r->z, &d, &c); /* G = D+C */ + fe25519_add(&r->y, &b, &a); /* H = B+A */ +} + +/* See http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd */ +static void dbl_p1p1(ge25519_p1p1 *r, const ge25519_p2 *p) +{ + fe25519 a,b,c,d; + fe25519_square(&a, &p->x); + fe25519_square(&b, &p->y); + fe25519_square(&c, &p->z); + fe25519_add(&c, &c, &c); + fe25519_neg(&d, &a); + + fe25519_add(&r->x, &p->x, &p->y); + fe25519_square(&r->x, &r->x); + fe25519_sub(&r->x, &r->x, &a); + fe25519_sub(&r->x, &r->x, &b); + fe25519_add(&r->z, &d, &b); + fe25519_sub(&r->t, &r->z, &c); + fe25519_sub(&r->y, &d, &b); +} + +/* Constant-time version of: if(b) r = p */ +static void cmov_aff(ge25519_aff *r, const ge25519_aff *p, unsigned char b) +{ + fe25519_cmov(&r->x, &p->x, b); + fe25519_cmov(&r->y, &p->y, b); +} + +static unsigned char equal(signed char b,signed char c) +{ + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + uint32_t y = x; /* 0: yes; 1..255: no */ + + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + + return y; +} + +static unsigned char negative(signed char b) +{ + unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + + x >>= 63; /* 1: yes; 0: no */ + + return x; +} + +static void choose_t(ge25519_aff *t, unsigned long long pos, signed char b) +{ + /* constant time */ + fe25519 v; + + *t = ge25519_base_multiples_affine[5 * pos + 0]; + + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 1], + equal(b,1) | equal(b,-1)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 2], + equal(b,2) | equal(b,-2)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 3], + equal(b,3) | equal(b,-3)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 4], + equal(b,-4)); + + fe25519_neg(&v, &t->x); + fe25519_cmov(&t->x, &v, negative(b)); +} + +static void setneutral(ge25519 *r) +{ + fe25519_setzero(&r->x); + fe25519_setone(&r->y); + fe25519_setone(&r->z); + fe25519_setzero(&r->t); +} + +/* ******************************************************************** + * EXPORTED FUNCTIONS + ******************************************************************** */ + +/* return 0 on success, -1 otherwise */ +int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p[32]) +{ + unsigned char par; + + fe25519 t, chk, num, den, den2, den4, den6; + fe25519_setone(&r->z); + par = p[31] >> 7; + fe25519_unpack(&r->y, p); + fe25519_square(&num, &r->y); /* x = y^2 */ + fe25519_mul(&den, &num, &ge25519_ecd); /* den = dy^2 */ + fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */ + fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + fe25519_square(&den2, &den); + fe25519_square(&den4, &den2); + fe25519_mul(&den6, &den4, &den2); + fe25519_mul(&t, &den6, &num); + fe25519_mul(&t, &t, &den); + + fe25519_pow2523(&t, &t); + /* 2. computation of r->x = t * num * den^3 */ + fe25519_mul(&t, &t, &num); + fe25519_mul(&t, &t, &den); + fe25519_mul(&t, &t, &den); + fe25519_mul(&r->x, &t, &den); + + /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */ + fe25519_square(&chk, &r->x); + fe25519_mul(&chk, &chk, &den); + if (!fe25519_iseq_vartime(&chk, &num)) { + fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1); + } + + /* 4. Now we have one of the two square roots, except if input was not a square */ + fe25519_square(&chk, &r->x); + fe25519_mul(&chk, &chk, &den); + if (!fe25519_iseq_vartime(&chk, &num)) { + return -1; + } + + /* 5. Choose the desired square root according to parity: */ + if(fe25519_getparity(&r->x) != (1-par)) { + fe25519_neg(&r->x, &r->x); + } + + fe25519_mul(&r->t, &r->x, &r->y); + + return 0; +} + +void ge25519_pack(unsigned char r[32], const ge25519_p3 *p) +{ + fe25519 tx, ty, zi; + + fe25519_invert(&zi, &p->z); + fe25519_mul(&tx, &p->x, &zi); + fe25519_mul(&ty, &p->y, &zi); + fe25519_pack(r, &ty); + + r[31] ^= fe25519_getparity(&tx) << 7; +} + +int ge25519_isneutral_vartime(const ge25519_p3 *p) +{ + int ret = 1; + + if (!fe25519_iszero(&p->x)) { + ret = 0; + } + + if (!fe25519_iseq_vartime(&p->y, &p->z)) { + ret = 0; + } + + return ret; +} + +/* computes [s1]p1 + [s2]p2 */ +void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const ge25519_p3 *p2, const sc25519 *s2) +{ + ge25519_p1p1 tp1p1; + ge25519_p3 pre[16]; + unsigned char b[127]; + int i; + + /* precomputation s2 s1 */ + setneutral(pre); /* 00 00 */ + pre[1] = *p1; /* 00 01 */ + dbl_p1p1(&tp1p1,(ge25519_p2 *)p1); p1p1_to_p3( &pre[2], &tp1p1); /* 00 10 */ + add_p1p1(&tp1p1,&pre[1], &pre[2]); p1p1_to_p3( &pre[3], &tp1p1); /* 00 11 */ + pre[4] = *p2; /* 01 00 */ + add_p1p1(&tp1p1,&pre[1], &pre[4]); p1p1_to_p3( &pre[5], &tp1p1); /* 01 01 */ + add_p1p1(&tp1p1,&pre[2], &pre[4]); p1p1_to_p3( &pre[6], &tp1p1); /* 01 10 */ + add_p1p1(&tp1p1,&pre[3], &pre[4]); p1p1_to_p3( &pre[7], &tp1p1); /* 01 11 */ + dbl_p1p1(&tp1p1,(ge25519_p2 *)p2); p1p1_to_p3( &pre[8], &tp1p1); /* 10 00 */ + add_p1p1(&tp1p1,&pre[1], &pre[8]); p1p1_to_p3( &pre[9], &tp1p1); /* 10 01 */ + dbl_p1p1(&tp1p1,(ge25519_p2 *)&pre[5]); p1p1_to_p3(&pre[10], &tp1p1); /* 10 10 */ + add_p1p1(&tp1p1,&pre[3], &pre[8]); p1p1_to_p3(&pre[11], &tp1p1); /* 10 11 */ + add_p1p1(&tp1p1,&pre[4], &pre[8]); p1p1_to_p3(&pre[12], &tp1p1); /* 11 00 */ + add_p1p1(&tp1p1,&pre[1],&pre[12]); p1p1_to_p3(&pre[13], &tp1p1); /* 11 01 */ + add_p1p1(&tp1p1,&pre[2],&pre[12]); p1p1_to_p3(&pre[14], &tp1p1); /* 11 10 */ + add_p1p1(&tp1p1,&pre[3],&pre[12]); p1p1_to_p3(&pre[15], &tp1p1); /* 11 11 */ + + sc25519_2interleave2(b,s1,s2); + + /* scalar multiplication */ + *r = pre[b[126]]; + + for (i = 125; i >= 0; i--) { + dbl_p1p1(&tp1p1, (ge25519_p2 *)r); + p1p1_to_p2((ge25519_p2 *) r, &tp1p1); + dbl_p1p1(&tp1p1, (ge25519_p2 *)r); + if(b[i] != 0) { + p1p1_to_p3(r, &tp1p1); + add_p1p1(&tp1p1, r, &pre[b[i]]); + } + if (i != 0) { + p1p1_to_p2((ge25519_p2 *)r, &tp1p1); + } else { + p1p1_to_p3(r, &tp1p1); + } + } +} + +void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s) +{ + signed char b[85]; + int i; + ge25519_aff t; + + sc25519_window3(b,s); + + choose_t((ge25519_aff *)r, 0, b[0]); + fe25519_setone(&r->z); + fe25519_mul(&r->t, &r->x, &r->y); + for (i = 1; i < 85; i++) { + choose_t(&t, (unsigned long long) i, b[i]); + ge25519_mixadd2(r, &t); + } +} diff --git a/libssh/src/ge25519_base.data b/libssh/src/ge25519_base.data new file mode 100644 index 00000000..66fb1b61 --- /dev/null +++ b/libssh/src/ge25519_base.data @@ -0,0 +1,858 @@ +/* $OpenBSD: ge25519_base.data,v 1.3 2013/12/09 11:03:45 markus Exp $ */ + +/* + * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange, + * Peter Schwabe, Bo-Yin Yang. + * Copied from supercop-20130419/crypto_sign/ed25519/ref/ge25519_base.data + */ + +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21}} , + {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}}, +{{{0x0e, 0xce, 0x43, 0x28, 0x4e, 0xa1, 0xc5, 0x83, 0x5f, 0xa4, 0xd7, 0x15, 0x45, 0x8e, 0x0d, 0x08, 0xac, 0xe7, 0x33, 0x18, 0x7d, 0x3b, 0x04, 0x3d, 0x6c, 0x04, 0x5a, 0x9f, 0x4c, 0x38, 0xab, 0x36}} , + {{0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0x0e, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22}}}, +{{{0x5c, 0xe2, 0xf8, 0xd3, 0x5f, 0x48, 0x62, 0xac, 0x86, 0x48, 0x62, 0x81, 0x19, 0x98, 0x43, 0x63, 0x3a, 0xc8, 0xda, 0x3e, 0x74, 0xae, 0xf4, 0x1f, 0x49, 0x8f, 0x92, 0x22, 0x4a, 0x9c, 0xae, 0x67}} , + {{0xd4, 0xb4, 0xf5, 0x78, 0x48, 0x68, 0xc3, 0x02, 0x04, 0x03, 0x24, 0x67, 0x17, 0xec, 0x16, 0x9f, 0xf7, 0x9e, 0x26, 0x60, 0x8e, 0xa1, 0x26, 0xa1, 0xab, 0x69, 0xee, 0x77, 0xd1, 0xb1, 0x67, 0x12}}}, +{{{0x70, 0xf8, 0xc9, 0xc4, 0x57, 0xa6, 0x3a, 0x49, 0x47, 0x15, 0xce, 0x93, 0xc1, 0x9e, 0x73, 0x1a, 0xf9, 0x20, 0x35, 0x7a, 0xb8, 0xd4, 0x25, 0x83, 0x46, 0xf1, 0xcf, 0x56, 0xdb, 0xa8, 0x3d, 0x20}} , + {{0x2f, 0x11, 0x32, 0xca, 0x61, 0xab, 0x38, 0xdf, 0xf0, 0x0f, 0x2f, 0xea, 0x32, 0x28, 0xf2, 0x4c, 0x6c, 0x71, 0xd5, 0x80, 0x85, 0xb8, 0x0e, 0x47, 0xe1, 0x95, 0x15, 0xcb, 0x27, 0xe8, 0xd0, 0x47}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xc8, 0x84, 0xa5, 0x08, 0xbc, 0xfd, 0x87, 0x3b, 0x99, 0x8b, 0x69, 0x80, 0x7b, 0xc6, 0x3a, 0xeb, 0x93, 0xcf, 0x4e, 0xf8, 0x5c, 0x2d, 0x86, 0x42, 0xb6, 0x71, 0xd7, 0x97, 0x5f, 0xe1, 0x42, 0x67}} , + {{0xb4, 0xb9, 0x37, 0xfc, 0xa9, 0x5b, 0x2f, 0x1e, 0x93, 0xe4, 0x1e, 0x62, 0xfc, 0x3c, 0x78, 0x81, 0x8f, 0xf3, 0x8a, 0x66, 0x09, 0x6f, 0xad, 0x6e, 0x79, 0x73, 0xe5, 0xc9, 0x00, 0x06, 0xd3, 0x21}}}, +{{{0xf8, 0xf9, 0x28, 0x6c, 0x6d, 0x59, 0xb2, 0x59, 0x74, 0x23, 0xbf, 0xe7, 0x33, 0x8d, 0x57, 0x09, 0x91, 0x9c, 0x24, 0x08, 0x15, 0x2b, 0xe2, 0xb8, 0xee, 0x3a, 0xe5, 0x27, 0x06, 0x86, 0xa4, 0x23}} , + {{0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70}}}, +{{{0x81, 0x6b, 0x88, 0xe8, 0x1e, 0xc7, 0x77, 0x96, 0x0e, 0xa1, 0xa9, 0x52, 0xe0, 0xd8, 0x0e, 0x61, 0x9e, 0x79, 0x2d, 0x95, 0x9c, 0x8d, 0x96, 0xe0, 0x06, 0x40, 0x5d, 0x87, 0x28, 0x5f, 0x98, 0x70}} , + {{0xf1, 0x79, 0x7b, 0xed, 0x4f, 0x44, 0xb2, 0xe7, 0x08, 0x0d, 0xc2, 0x08, 0x12, 0xd2, 0x9f, 0xdf, 0xcd, 0x93, 0x20, 0x8a, 0xcf, 0x33, 0xca, 0x6d, 0x89, 0xb9, 0x77, 0xc8, 0x93, 0x1b, 0x4e, 0x60}}}, +{{{0x26, 0x4f, 0x7e, 0x97, 0xf6, 0x40, 0xdd, 0x4f, 0xfc, 0x52, 0x78, 0xf9, 0x90, 0x31, 0x03, 0xe6, 0x7d, 0x56, 0x39, 0x0b, 0x1d, 0x56, 0x82, 0x85, 0xf9, 0x1a, 0x42, 0x17, 0x69, 0x6c, 0xcf, 0x39}} , + {{0x69, 0xd2, 0x06, 0x3a, 0x4f, 0x39, 0x2d, 0xf9, 0x38, 0x40, 0x8c, 0x4c, 0xe7, 0x05, 0x12, 0xb4, 0x78, 0x8b, 0xf8, 0xc0, 0xec, 0x93, 0xde, 0x7a, 0x6b, 0xce, 0x2c, 0xe1, 0x0e, 0xa9, 0x34, 0x44}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x0b, 0xa4, 0x3c, 0xb0, 0x0f, 0x7a, 0x51, 0xf1, 0x78, 0xd6, 0xd9, 0x6a, 0xfd, 0x46, 0xe8, 0xb8, 0xa8, 0x79, 0x1d, 0x87, 0xf9, 0x90, 0xf2, 0x9c, 0x13, 0x29, 0xf8, 0x0b, 0x20, 0x64, 0xfa, 0x05}} , + {{0x26, 0x09, 0xda, 0x17, 0xaf, 0x95, 0xd6, 0xfb, 0x6a, 0x19, 0x0d, 0x6e, 0x5e, 0x12, 0xf1, 0x99, 0x4c, 0xaa, 0xa8, 0x6f, 0x79, 0x86, 0xf4, 0x72, 0x28, 0x00, 0x26, 0xf9, 0xea, 0x9e, 0x19, 0x3d}}}, +{{{0x87, 0xdd, 0xcf, 0xf0, 0x5b, 0x49, 0xa2, 0x5d, 0x40, 0x7a, 0x23, 0x26, 0xa4, 0x7a, 0x83, 0x8a, 0xb7, 0x8b, 0xd2, 0x1a, 0xbf, 0xea, 0x02, 0x24, 0x08, 0x5f, 0x7b, 0xa9, 0xb1, 0xbe, 0x9d, 0x37}} , + {{0xfc, 0x86, 0x4b, 0x08, 0xee, 0xe7, 0xa0, 0xfd, 0x21, 0x45, 0x09, 0x34, 0xc1, 0x61, 0x32, 0x23, 0xfc, 0x9b, 0x55, 0x48, 0x53, 0x99, 0xf7, 0x63, 0xd0, 0x99, 0xce, 0x01, 0xe0, 0x9f, 0xeb, 0x28}}}, +{{{0x47, 0xfc, 0xab, 0x5a, 0x17, 0xf0, 0x85, 0x56, 0x3a, 0x30, 0x86, 0x20, 0x28, 0x4b, 0x8e, 0x44, 0x74, 0x3a, 0x6e, 0x02, 0xf1, 0x32, 0x8f, 0x9f, 0x3f, 0x08, 0x35, 0xe9, 0xca, 0x16, 0x5f, 0x6e}} , + {{0x1c, 0x59, 0x1c, 0x65, 0x5d, 0x34, 0xa4, 0x09, 0xcd, 0x13, 0x9c, 0x70, 0x7d, 0xb1, 0x2a, 0xc5, 0x88, 0xaf, 0x0b, 0x60, 0xc7, 0x9f, 0x34, 0x8d, 0xd6, 0xb7, 0x7f, 0xea, 0x78, 0x65, 0x8d, 0x77}}}, +{{{0x56, 0xa5, 0xc2, 0x0c, 0xdd, 0xbc, 0xb8, 0x20, 0x6d, 0x57, 0x61, 0xb5, 0xfb, 0x78, 0xb5, 0xd4, 0x49, 0x54, 0x90, 0x26, 0xc1, 0xcb, 0xe9, 0xe6, 0xbf, 0xec, 0x1d, 0x4e, 0xed, 0x07, 0x7e, 0x5e}} , + {{0xc7, 0xf6, 0x6c, 0x56, 0x31, 0x20, 0x14, 0x0e, 0xa8, 0xd9, 0x27, 0xc1, 0x9a, 0x3d, 0x1b, 0x7d, 0x0e, 0x26, 0xd3, 0x81, 0xaa, 0xeb, 0xf5, 0x6b, 0x79, 0x02, 0xf1, 0x51, 0x5c, 0x75, 0x55, 0x0f}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x0a, 0x34, 0xcd, 0x82, 0x3c, 0x33, 0x09, 0x54, 0xd2, 0x61, 0x39, 0x30, 0x9b, 0xfd, 0xef, 0x21, 0x26, 0xd4, 0x70, 0xfa, 0xee, 0xf9, 0x31, 0x33, 0x73, 0x84, 0xd0, 0xb3, 0x81, 0xbf, 0xec, 0x2e}} , + {{0xe8, 0x93, 0x8b, 0x00, 0x64, 0xf7, 0x9c, 0xb8, 0x74, 0xe0, 0xe6, 0x49, 0x48, 0x4d, 0x4d, 0x48, 0xb6, 0x19, 0xa1, 0x40, 0xb7, 0xd9, 0x32, 0x41, 0x7c, 0x82, 0x37, 0xa1, 0x2d, 0xdc, 0xd2, 0x54}}}, +{{{0x68, 0x2b, 0x4a, 0x5b, 0xd5, 0xc7, 0x51, 0x91, 0x1d, 0xe1, 0x2a, 0x4b, 0xc4, 0x47, 0xf1, 0xbc, 0x7a, 0xb3, 0xcb, 0xc8, 0xb6, 0x7c, 0xac, 0x90, 0x05, 0xfd, 0xf3, 0xf9, 0x52, 0x3a, 0x11, 0x6b}} , + {{0x3d, 0xc1, 0x27, 0xf3, 0x59, 0x43, 0x95, 0x90, 0xc5, 0x96, 0x79, 0xf5, 0xf4, 0x95, 0x65, 0x29, 0x06, 0x9c, 0x51, 0x05, 0x18, 0xda, 0xb8, 0x2e, 0x79, 0x7e, 0x69, 0x59, 0x71, 0x01, 0xeb, 0x1a}}}, +{{{0x15, 0x06, 0x49, 0xb6, 0x8a, 0x3c, 0xea, 0x2f, 0x34, 0x20, 0x14, 0xc3, 0xaa, 0xd6, 0xaf, 0x2c, 0x3e, 0xbd, 0x65, 0x20, 0xe2, 0x4d, 0x4b, 0x3b, 0xeb, 0x9f, 0x4a, 0xc3, 0xad, 0xa4, 0x3b, 0x60}} , + {{0xbc, 0x58, 0xe6, 0xc0, 0x95, 0x2a, 0x2a, 0x81, 0x9a, 0x7a, 0xf3, 0xd2, 0x06, 0xbe, 0x48, 0xbc, 0x0c, 0xc5, 0x46, 0xe0, 0x6a, 0xd4, 0xac, 0x0f, 0xd9, 0xcc, 0x82, 0x34, 0x2c, 0xaf, 0xdb, 0x1f}}}, +{{{0xf7, 0x17, 0x13, 0xbd, 0xfb, 0xbc, 0xd2, 0xec, 0x45, 0xb3, 0x15, 0x31, 0xe9, 0xaf, 0x82, 0x84, 0x3d, 0x28, 0xc6, 0xfc, 0x11, 0xf5, 0x41, 0xb5, 0x8b, 0xd3, 0x12, 0x76, 0x52, 0xe7, 0x1a, 0x3c}} , + {{0x4e, 0x36, 0x11, 0x07, 0xa2, 0x15, 0x20, 0x51, 0xc4, 0x2a, 0xc3, 0x62, 0x8b, 0x5e, 0x7f, 0xa6, 0x0f, 0xf9, 0x45, 0x85, 0x6c, 0x11, 0x86, 0xb7, 0x7e, 0xe5, 0xd7, 0xf9, 0xc3, 0x91, 0x1c, 0x05}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xea, 0xd6, 0xde, 0x29, 0x3a, 0x00, 0xb9, 0x02, 0x59, 0xcb, 0x26, 0xc4, 0xba, 0x99, 0xb1, 0x97, 0x2f, 0x8e, 0x00, 0x92, 0x26, 0x4f, 0x52, 0xeb, 0x47, 0x1b, 0x89, 0x8b, 0x24, 0xc0, 0x13, 0x7d}} , + {{0xd5, 0x20, 0x5b, 0x80, 0xa6, 0x80, 0x20, 0x95, 0xc3, 0xe9, 0x9f, 0x8e, 0x87, 0x9e, 0x1e, 0x9e, 0x7a, 0xc7, 0xcc, 0x75, 0x6c, 0xa5, 0xf1, 0x91, 0x1a, 0xa8, 0x01, 0x2c, 0xab, 0x76, 0xa9, 0x59}}}, +{{{0xde, 0xc9, 0xb1, 0x31, 0x10, 0x16, 0xaa, 0x35, 0x14, 0x6a, 0xd4, 0xb5, 0x34, 0x82, 0x71, 0xd2, 0x4a, 0x5d, 0x9a, 0x1f, 0x53, 0x26, 0x3c, 0xe5, 0x8e, 0x8d, 0x33, 0x7f, 0xff, 0xa9, 0xd5, 0x17}} , + {{0x89, 0xaf, 0xf6, 0xa4, 0x64, 0xd5, 0x10, 0xe0, 0x1d, 0xad, 0xef, 0x44, 0xbd, 0xda, 0x83, 0xac, 0x7a, 0xa8, 0xf0, 0x1c, 0x07, 0xf9, 0xc3, 0x43, 0x6c, 0x3f, 0xb7, 0xd3, 0x87, 0x22, 0x02, 0x73}}}, +{{{0x64, 0x1d, 0x49, 0x13, 0x2f, 0x71, 0xec, 0x69, 0x87, 0xd0, 0x42, 0xee, 0x13, 0xec, 0xe3, 0xed, 0x56, 0x7b, 0xbf, 0xbd, 0x8c, 0x2f, 0x7d, 0x7b, 0x9d, 0x28, 0xec, 0x8e, 0x76, 0x2f, 0x6f, 0x08}} , + {{0x22, 0xf5, 0x5f, 0x4d, 0x15, 0xef, 0xfc, 0x4e, 0x57, 0x03, 0x36, 0x89, 0xf0, 0xeb, 0x5b, 0x91, 0xd6, 0xe2, 0xca, 0x01, 0xa5, 0xee, 0x52, 0xec, 0xa0, 0x3c, 0x8f, 0x33, 0x90, 0x5a, 0x94, 0x72}}}, +{{{0x8a, 0x4b, 0xe7, 0x38, 0xbc, 0xda, 0xc2, 0xb0, 0x85, 0xe1, 0x4a, 0xfe, 0x2d, 0x44, 0x84, 0xcb, 0x20, 0x6b, 0x2d, 0xbf, 0x11, 0x9c, 0xd7, 0xbe, 0xd3, 0x3e, 0x5f, 0xbf, 0x68, 0xbc, 0xa8, 0x07}} , + {{0x01, 0x89, 0x28, 0x22, 0x6a, 0x78, 0xaa, 0x29, 0x03, 0xc8, 0x74, 0x95, 0x03, 0x3e, 0xdc, 0xbd, 0x07, 0x13, 0xa8, 0xa2, 0x20, 0x2d, 0xb3, 0x18, 0x70, 0x42, 0xfd, 0x7a, 0xc4, 0xd7, 0x49, 0x72}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x02, 0xff, 0x32, 0x2b, 0x5c, 0x93, 0x54, 0x32, 0xe8, 0x57, 0x54, 0x1a, 0x8b, 0x33, 0x60, 0x65, 0xd3, 0x67, 0xa4, 0xc1, 0x26, 0xc4, 0xa4, 0x34, 0x1f, 0x9b, 0xa7, 0xa9, 0xf4, 0xd9, 0x4f, 0x5b}} , + {{0x46, 0x8d, 0xb0, 0x33, 0x54, 0x26, 0x5b, 0x68, 0xdf, 0xbb, 0xc5, 0xec, 0xc2, 0xf9, 0x3c, 0x5a, 0x37, 0xc1, 0x8e, 0x27, 0x47, 0xaa, 0x49, 0x5a, 0xf8, 0xfb, 0x68, 0x04, 0x23, 0xd1, 0xeb, 0x40}}}, +{{{0x65, 0xa5, 0x11, 0x84, 0x8a, 0x67, 0x9d, 0x9e, 0xd1, 0x44, 0x68, 0x7a, 0x34, 0xe1, 0x9f, 0xa3, 0x54, 0xcd, 0x07, 0xca, 0x79, 0x1f, 0x54, 0x2f, 0x13, 0x70, 0x4e, 0xee, 0xa2, 0xfa, 0xe7, 0x5d}} , + {{0x36, 0xec, 0x54, 0xf8, 0xce, 0xe4, 0x85, 0xdf, 0xf6, 0x6f, 0x1d, 0x90, 0x08, 0xbc, 0xe8, 0xc0, 0x92, 0x2d, 0x43, 0x6b, 0x92, 0xa9, 0x8e, 0xab, 0x0a, 0x2e, 0x1c, 0x1e, 0x64, 0x23, 0x9f, 0x2c}}}, +{{{0xa7, 0xd6, 0x2e, 0xd5, 0xcc, 0xd4, 0xcb, 0x5a, 0x3b, 0xa7, 0xf9, 0x46, 0x03, 0x1d, 0xad, 0x2b, 0x34, 0x31, 0x90, 0x00, 0x46, 0x08, 0x82, 0x14, 0xc4, 0xe0, 0x9c, 0xf0, 0xe3, 0x55, 0x43, 0x31}} , + {{0x60, 0xd6, 0xdd, 0x78, 0xe6, 0xd4, 0x22, 0x42, 0x1f, 0x00, 0xf9, 0xb1, 0x6a, 0x63, 0xe2, 0x92, 0x59, 0xd1, 0x1a, 0xb7, 0x00, 0x54, 0x29, 0xc9, 0xc1, 0xf6, 0x6f, 0x7a, 0xc5, 0x3c, 0x5f, 0x65}}}, +{{{0x27, 0x4f, 0xd0, 0x72, 0xb1, 0x11, 0x14, 0x27, 0x15, 0x94, 0x48, 0x81, 0x7e, 0x74, 0xd8, 0x32, 0xd5, 0xd1, 0x11, 0x28, 0x60, 0x63, 0x36, 0x32, 0x37, 0xb5, 0x13, 0x1c, 0xa0, 0x37, 0xe3, 0x74}} , + {{0xf1, 0x25, 0x4e, 0x11, 0x96, 0x67, 0xe6, 0x1c, 0xc2, 0xb2, 0x53, 0xe2, 0xda, 0x85, 0xee, 0xb2, 0x9f, 0x59, 0xf3, 0xba, 0xbd, 0xfa, 0xcf, 0x6e, 0xf9, 0xda, 0xa4, 0xb3, 0x02, 0x8f, 0x64, 0x08}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x34, 0x94, 0xf2, 0x64, 0x54, 0x47, 0x37, 0x07, 0x40, 0x8a, 0x20, 0xba, 0x4a, 0x55, 0xd7, 0x3f, 0x47, 0xba, 0x25, 0x23, 0x14, 0xb0, 0x2c, 0xe8, 0x55, 0xa8, 0xa6, 0xef, 0x51, 0xbd, 0x6f, 0x6a}} , + {{0x71, 0xd6, 0x16, 0x76, 0xb2, 0x06, 0xea, 0x79, 0xf5, 0xc4, 0xc3, 0x52, 0x7e, 0x61, 0xd1, 0xe1, 0xad, 0x70, 0x78, 0x1d, 0x16, 0x11, 0xf8, 0x7c, 0x2b, 0xfc, 0x55, 0x9f, 0x52, 0xf8, 0xf5, 0x16}}}, +{{{0x34, 0x96, 0x9a, 0xf6, 0xc5, 0xe0, 0x14, 0x03, 0x24, 0x0e, 0x4c, 0xad, 0x9e, 0x9a, 0x70, 0x23, 0x96, 0xb2, 0xf1, 0x2e, 0x9d, 0xc3, 0x32, 0x9b, 0x54, 0xa5, 0x73, 0xde, 0x88, 0xb1, 0x3e, 0x24}} , + {{0xf6, 0xe2, 0x4c, 0x1f, 0x5b, 0xb2, 0xaf, 0x82, 0xa5, 0xcf, 0x81, 0x10, 0x04, 0xef, 0xdb, 0xa2, 0xcc, 0x24, 0xb2, 0x7e, 0x0b, 0x7a, 0xeb, 0x01, 0xd8, 0x52, 0xf4, 0x51, 0x89, 0x29, 0x79, 0x37}}}, +{{{0x74, 0xde, 0x12, 0xf3, 0x68, 0xb7, 0x66, 0xc3, 0xee, 0x68, 0xdc, 0x81, 0xb5, 0x55, 0x99, 0xab, 0xd9, 0x28, 0x63, 0x6d, 0x8b, 0x40, 0x69, 0x75, 0x6c, 0xcd, 0x5c, 0x2a, 0x7e, 0x32, 0x7b, 0x29}} , + {{0x02, 0xcc, 0x22, 0x74, 0x4d, 0x19, 0x07, 0xc0, 0xda, 0xb5, 0x76, 0x51, 0x2a, 0xaa, 0xa6, 0x0a, 0x5f, 0x26, 0xd4, 0xbc, 0xaf, 0x48, 0x88, 0x7f, 0x02, 0xbc, 0xf2, 0xe1, 0xcf, 0xe9, 0xdd, 0x15}}}, +{{{0xed, 0xb5, 0x9a, 0x8c, 0x9a, 0xdd, 0x27, 0xf4, 0x7f, 0x47, 0xd9, 0x52, 0xa7, 0xcd, 0x65, 0xa5, 0x31, 0x22, 0xed, 0xa6, 0x63, 0x5b, 0x80, 0x4a, 0xad, 0x4d, 0xed, 0xbf, 0xee, 0x49, 0xb3, 0x06}} , + {{0xf8, 0x64, 0x8b, 0x60, 0x90, 0xe9, 0xde, 0x44, 0x77, 0xb9, 0x07, 0x36, 0x32, 0xc2, 0x50, 0xf5, 0x65, 0xdf, 0x48, 0x4c, 0x37, 0xaa, 0x68, 0xab, 0x9a, 0x1f, 0x3e, 0xff, 0x89, 0x92, 0xa0, 0x07}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x7d, 0x4f, 0x9c, 0x19, 0xc0, 0x4a, 0x31, 0xec, 0xf9, 0xaa, 0xeb, 0xb2, 0x16, 0x9c, 0xa3, 0x66, 0x5f, 0xd1, 0xd4, 0xed, 0xb8, 0x92, 0x1c, 0xab, 0xda, 0xea, 0xd9, 0x57, 0xdf, 0x4c, 0x2a, 0x48}} , + {{0x4b, 0xb0, 0x4e, 0x6e, 0x11, 0x3b, 0x51, 0xbd, 0x6a, 0xfd, 0xe4, 0x25, 0xa5, 0x5f, 0x11, 0x3f, 0x98, 0x92, 0x51, 0x14, 0xc6, 0x5f, 0x3c, 0x0b, 0xa8, 0xf7, 0xc2, 0x81, 0x43, 0xde, 0x91, 0x73}}}, +{{{0x3c, 0x8f, 0x9f, 0x33, 0x2a, 0x1f, 0x43, 0x33, 0x8f, 0x68, 0xff, 0x1f, 0x3d, 0x73, 0x6b, 0xbf, 0x68, 0xcc, 0x7d, 0x13, 0x6c, 0x24, 0x4b, 0xcc, 0x4d, 0x24, 0x0d, 0xfe, 0xde, 0x86, 0xad, 0x3b}} , + {{0x79, 0x51, 0x81, 0x01, 0xdc, 0x73, 0x53, 0xe0, 0x6e, 0x9b, 0xea, 0x68, 0x3f, 0x5c, 0x14, 0x84, 0x53, 0x8d, 0x4b, 0xc0, 0x9f, 0x9f, 0x89, 0x2b, 0x8c, 0xba, 0x86, 0xfa, 0xf2, 0xcd, 0xe3, 0x2d}}}, +{{{0x06, 0xf9, 0x29, 0x5a, 0xdb, 0x3d, 0x84, 0x52, 0xab, 0xcc, 0x6b, 0x60, 0x9d, 0xb7, 0x4a, 0x0e, 0x36, 0x63, 0x91, 0xad, 0xa0, 0x95, 0xb0, 0x97, 0x89, 0x4e, 0xcf, 0x7d, 0x3c, 0xe5, 0x7c, 0x28}} , + {{0x2e, 0x69, 0x98, 0xfd, 0xc6, 0xbd, 0xcc, 0xca, 0xdf, 0x9a, 0x44, 0x7e, 0x9d, 0xca, 0x89, 0x6d, 0xbf, 0x27, 0xc2, 0xf8, 0xcd, 0x46, 0x00, 0x2b, 0xb5, 0x58, 0x4e, 0xb7, 0x89, 0x09, 0xe9, 0x2d}}}, +{{{0x54, 0xbe, 0x75, 0xcb, 0x05, 0xb0, 0x54, 0xb7, 0xe7, 0x26, 0x86, 0x4a, 0xfc, 0x19, 0xcf, 0x27, 0x46, 0xd4, 0x22, 0x96, 0x5a, 0x11, 0xe8, 0xd5, 0x1b, 0xed, 0x71, 0xc5, 0x5d, 0xc8, 0xaf, 0x45}} , + {{0x40, 0x7b, 0x77, 0x57, 0x49, 0x9e, 0x80, 0x39, 0x23, 0xee, 0x81, 0x0b, 0x22, 0xcf, 0xdb, 0x7a, 0x2f, 0x14, 0xb8, 0x57, 0x8f, 0xa1, 0x39, 0x1e, 0x77, 0xfc, 0x0b, 0xa6, 0xbf, 0x8a, 0x0c, 0x6c}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x77, 0x3a, 0xd4, 0xd8, 0x27, 0xcf, 0xe8, 0xa1, 0x72, 0x9d, 0xca, 0xdd, 0x0d, 0x96, 0xda, 0x79, 0xed, 0x56, 0x42, 0x15, 0x60, 0xc7, 0x1c, 0x6b, 0x26, 0x30, 0xf6, 0x6a, 0x95, 0x67, 0xf3, 0x0a}} , + {{0xc5, 0x08, 0xa4, 0x2b, 0x2f, 0xbd, 0x31, 0x81, 0x2a, 0xa6, 0xb6, 0xe4, 0x00, 0x91, 0xda, 0x3d, 0xb2, 0xb0, 0x96, 0xce, 0x8a, 0xd2, 0x8d, 0x70, 0xb3, 0xd3, 0x34, 0x01, 0x90, 0x8d, 0x10, 0x21}}}, +{{{0x33, 0x0d, 0xe7, 0xba, 0x4f, 0x07, 0xdf, 0x8d, 0xea, 0x7d, 0xa0, 0xc5, 0xd6, 0xb1, 0xb0, 0xe5, 0x57, 0x1b, 0x5b, 0xf5, 0x45, 0x13, 0x14, 0x64, 0x5a, 0xeb, 0x5c, 0xfc, 0x54, 0x01, 0x76, 0x2b}} , + {{0x02, 0x0c, 0xc2, 0xaf, 0x96, 0x36, 0xfe, 0x4a, 0xe2, 0x54, 0x20, 0x6a, 0xeb, 0xb2, 0x9f, 0x62, 0xd7, 0xce, 0xa2, 0x3f, 0x20, 0x11, 0x34, 0x37, 0xe0, 0x42, 0xed, 0x6f, 0xf9, 0x1a, 0xc8, 0x7d}}}, +{{{0xd8, 0xb9, 0x11, 0xe8, 0x36, 0x3f, 0x42, 0xc1, 0xca, 0xdc, 0xd3, 0xf1, 0xc8, 0x23, 0x3d, 0x4f, 0x51, 0x7b, 0x9d, 0x8d, 0xd8, 0xe4, 0xa0, 0xaa, 0xf3, 0x04, 0xd6, 0x11, 0x93, 0xc8, 0x35, 0x45}} , + {{0x61, 0x36, 0xd6, 0x08, 0x90, 0xbf, 0xa7, 0x7a, 0x97, 0x6c, 0x0f, 0x84, 0xd5, 0x33, 0x2d, 0x37, 0xc9, 0x6a, 0x80, 0x90, 0x3d, 0x0a, 0xa2, 0xaa, 0xe1, 0xb8, 0x84, 0xba, 0x61, 0x36, 0xdd, 0x69}}}, +{{{0x6b, 0xdb, 0x5b, 0x9c, 0xc6, 0x92, 0xbc, 0x23, 0xaf, 0xc5, 0xb8, 0x75, 0xf8, 0x42, 0xfa, 0xd6, 0xb6, 0x84, 0x94, 0x63, 0x98, 0x93, 0x48, 0x78, 0x38, 0xcd, 0xbb, 0x18, 0x34, 0xc3, 0xdb, 0x67}} , + {{0x96, 0xf3, 0x3a, 0x09, 0x56, 0xb0, 0x6f, 0x7c, 0x51, 0x1e, 0x1b, 0x39, 0x48, 0xea, 0xc9, 0x0c, 0x25, 0xa2, 0x7a, 0xca, 0xe7, 0x92, 0xfc, 0x59, 0x30, 0xa3, 0x89, 0x85, 0xdf, 0x6f, 0x43, 0x38}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x79, 0x84, 0x44, 0x19, 0xbd, 0xe9, 0x54, 0xc4, 0xc0, 0x6e, 0x2a, 0xa8, 0xa8, 0x9b, 0x43, 0xd5, 0x71, 0x22, 0x5f, 0xdc, 0x01, 0xfa, 0xdf, 0xb3, 0xb8, 0x47, 0x4b, 0x0a, 0xa5, 0x44, 0xea, 0x29}} , + {{0x05, 0x90, 0x50, 0xaf, 0x63, 0x5f, 0x9d, 0x9e, 0xe1, 0x9d, 0x38, 0x97, 0x1f, 0x6c, 0xac, 0x30, 0x46, 0xb2, 0x6a, 0x19, 0xd1, 0x4b, 0xdb, 0xbb, 0x8c, 0xda, 0x2e, 0xab, 0xc8, 0x5a, 0x77, 0x6c}}}, +{{{0x2b, 0xbe, 0xaf, 0xa1, 0x6d, 0x2f, 0x0b, 0xb1, 0x8f, 0xe3, 0xe0, 0x38, 0xcd, 0x0b, 0x41, 0x1b, 0x4a, 0x15, 0x07, 0xf3, 0x6f, 0xdc, 0xb8, 0xe9, 0xde, 0xb2, 0xa3, 0x40, 0x01, 0xa6, 0x45, 0x1e}} , + {{0x76, 0x0a, 0xda, 0x8d, 0x2c, 0x07, 0x3f, 0x89, 0x7d, 0x04, 0xad, 0x43, 0x50, 0x6e, 0xd2, 0x47, 0xcb, 0x8a, 0xe6, 0x85, 0x1a, 0x24, 0xf3, 0xd2, 0x60, 0xfd, 0xdf, 0x73, 0xa4, 0x0d, 0x73, 0x0e}}}, +{{{0xfd, 0x67, 0x6b, 0x71, 0x9b, 0x81, 0x53, 0x39, 0x39, 0xf4, 0xb8, 0xd5, 0xc3, 0x30, 0x9b, 0x3b, 0x7c, 0xa3, 0xf0, 0xd0, 0x84, 0x21, 0xd6, 0xbf, 0xb7, 0x4c, 0x87, 0x13, 0x45, 0x2d, 0xa7, 0x55}} , + {{0x5d, 0x04, 0xb3, 0x40, 0x28, 0x95, 0x2d, 0x30, 0x83, 0xec, 0x5e, 0xe4, 0xff, 0x75, 0xfe, 0x79, 0x26, 0x9d, 0x1d, 0x36, 0xcd, 0x0a, 0x15, 0xd2, 0x24, 0x14, 0x77, 0x71, 0xd7, 0x8a, 0x1b, 0x04}}}, +{{{0x5d, 0x93, 0xc9, 0xbe, 0xaa, 0x90, 0xcd, 0x9b, 0xfb, 0x73, 0x7e, 0xb0, 0x64, 0x98, 0x57, 0x44, 0x42, 0x41, 0xb1, 0xaf, 0xea, 0xc1, 0xc3, 0x22, 0xff, 0x60, 0x46, 0xcb, 0x61, 0x81, 0x70, 0x61}} , + {{0x0d, 0x82, 0xb9, 0xfe, 0x21, 0xcd, 0xc4, 0xf5, 0x98, 0x0c, 0x4e, 0x72, 0xee, 0x87, 0x49, 0xf8, 0xa1, 0x95, 0xdf, 0x8f, 0x2d, 0xbd, 0x21, 0x06, 0x7c, 0x15, 0xe8, 0x12, 0x6d, 0x93, 0xd6, 0x38}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x91, 0xf7, 0x51, 0xd9, 0xef, 0x7d, 0x42, 0x01, 0x13, 0xe9, 0xb8, 0x7f, 0xa6, 0x49, 0x17, 0x64, 0x21, 0x80, 0x83, 0x2c, 0x63, 0x4c, 0x60, 0x09, 0x59, 0x91, 0x92, 0x77, 0x39, 0x51, 0xf4, 0x48}} , + {{0x60, 0xd5, 0x22, 0x83, 0x08, 0x2f, 0xff, 0x99, 0x3e, 0x69, 0x6d, 0x88, 0xda, 0xe7, 0x5b, 0x52, 0x26, 0x31, 0x2a, 0xe5, 0x89, 0xde, 0x68, 0x90, 0xb6, 0x22, 0x5a, 0xbd, 0xd3, 0x85, 0x53, 0x31}}}, +{{{0xd8, 0xce, 0xdc, 0xf9, 0x3c, 0x4b, 0xa2, 0x1d, 0x2c, 0x2f, 0x36, 0xbe, 0x7a, 0xfc, 0xcd, 0xbc, 0xdc, 0xf9, 0x30, 0xbd, 0xff, 0x05, 0xc7, 0xe4, 0x8e, 0x17, 0x62, 0xf8, 0x4d, 0xa0, 0x56, 0x79}} , + {{0x82, 0xe7, 0xf6, 0xba, 0x53, 0x84, 0x0a, 0xa3, 0x34, 0xff, 0x3c, 0xa3, 0x6a, 0xa1, 0x37, 0xea, 0xdd, 0xb6, 0x95, 0xb3, 0x78, 0x19, 0x76, 0x1e, 0x55, 0x2f, 0x77, 0x2e, 0x7f, 0xc1, 0xea, 0x5e}}}, +{{{0x83, 0xe1, 0x6e, 0xa9, 0x07, 0x33, 0x3e, 0x83, 0xff, 0xcb, 0x1c, 0x9f, 0xb1, 0xa3, 0xb4, 0xc9, 0xe1, 0x07, 0x97, 0xff, 0xf8, 0x23, 0x8f, 0xce, 0x40, 0xfd, 0x2e, 0x5e, 0xdb, 0x16, 0x43, 0x2d}} , + {{0xba, 0x38, 0x02, 0xf7, 0x81, 0x43, 0x83, 0xa3, 0x20, 0x4f, 0x01, 0x3b, 0x8a, 0x04, 0x38, 0x31, 0xc6, 0x0f, 0xc8, 0xdf, 0xd7, 0xfa, 0x2f, 0x88, 0x3f, 0xfc, 0x0c, 0x76, 0xc4, 0xa6, 0x45, 0x72}}}, +{{{0xbb, 0x0c, 0xbc, 0x6a, 0xa4, 0x97, 0x17, 0x93, 0x2d, 0x6f, 0xde, 0x72, 0x10, 0x1c, 0x08, 0x2c, 0x0f, 0x80, 0x32, 0x68, 0x27, 0xd4, 0xab, 0xdd, 0xc5, 0x58, 0x61, 0x13, 0x6d, 0x11, 0x1e, 0x4d}} , + {{0x1a, 0xb9, 0xc9, 0x10, 0xfb, 0x1e, 0x4e, 0xf4, 0x84, 0x4b, 0x8a, 0x5e, 0x7b, 0x4b, 0xe8, 0x43, 0x8c, 0x8f, 0x00, 0xb5, 0x54, 0x13, 0xc5, 0x5c, 0xb6, 0x35, 0x4e, 0x9d, 0xe4, 0x5b, 0x41, 0x6d}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x15, 0x7d, 0x12, 0x48, 0x82, 0x14, 0x42, 0xcd, 0x32, 0xd4, 0x4b, 0xc1, 0x72, 0x61, 0x2a, 0x8c, 0xec, 0xe2, 0xf8, 0x24, 0x45, 0x94, 0xe3, 0xbe, 0xdd, 0x67, 0xa8, 0x77, 0x5a, 0xae, 0x5b, 0x4b}} , + {{0xcb, 0x77, 0x9a, 0x20, 0xde, 0xb8, 0x23, 0xd9, 0xa0, 0x0f, 0x8c, 0x7b, 0xa5, 0xcb, 0xae, 0xb6, 0xec, 0x42, 0x67, 0x0e, 0x58, 0xa4, 0x75, 0x98, 0x21, 0x71, 0x84, 0xb3, 0xe0, 0x76, 0x94, 0x73}}}, +{{{0xdf, 0xfc, 0x69, 0x28, 0x23, 0x3f, 0x5b, 0xf8, 0x3b, 0x24, 0x37, 0xf3, 0x1d, 0xd5, 0x22, 0x6b, 0xd0, 0x98, 0xa8, 0x6c, 0xcf, 0xff, 0x06, 0xe1, 0x13, 0xdf, 0xb9, 0xc1, 0x0c, 0xa9, 0xbf, 0x33}} , + {{0xd9, 0x81, 0xda, 0xb2, 0x4f, 0x82, 0x9d, 0x43, 0x81, 0x09, 0xf1, 0xd2, 0x01, 0xef, 0xac, 0xf4, 0x2d, 0x7d, 0x01, 0x09, 0xf1, 0xff, 0xa5, 0x9f, 0xe5, 0xca, 0x27, 0x63, 0xdb, 0x20, 0xb1, 0x53}}}, +{{{0x67, 0x02, 0xe8, 0xad, 0xa9, 0x34, 0xd4, 0xf0, 0x15, 0x81, 0xaa, 0xc7, 0x4d, 0x87, 0x94, 0xea, 0x75, 0xe7, 0x4c, 0x94, 0x04, 0x0e, 0x69, 0x87, 0xe7, 0x51, 0x91, 0x10, 0x03, 0xc7, 0xbe, 0x56}} , + {{0x32, 0xfb, 0x86, 0xec, 0x33, 0x6b, 0x2e, 0x51, 0x2b, 0xc8, 0xfa, 0x6c, 0x70, 0x47, 0x7e, 0xce, 0x05, 0x0c, 0x71, 0xf3, 0xb4, 0x56, 0xa6, 0xdc, 0xcc, 0x78, 0x07, 0x75, 0xd0, 0xdd, 0xb2, 0x6a}}}, +{{{0xc6, 0xef, 0xb9, 0xc0, 0x2b, 0x22, 0x08, 0x1e, 0x71, 0x70, 0xb3, 0x35, 0x9c, 0x7a, 0x01, 0x92, 0x44, 0x9a, 0xf6, 0xb0, 0x58, 0x95, 0xc1, 0x9b, 0x02, 0xed, 0x2d, 0x7c, 0x34, 0x29, 0x49, 0x44}} , + {{0x45, 0x62, 0x1d, 0x2e, 0xff, 0x2a, 0x1c, 0x21, 0xa4, 0x25, 0x7b, 0x0d, 0x8c, 0x15, 0x39, 0xfc, 0x8f, 0x7c, 0xa5, 0x7d, 0x1e, 0x25, 0xa3, 0x45, 0xd6, 0xab, 0xbd, 0xcb, 0xc5, 0x5e, 0x78, 0x77}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xd0, 0xd3, 0x42, 0xed, 0x1d, 0x00, 0x3c, 0x15, 0x2c, 0x9c, 0x77, 0x81, 0xd2, 0x73, 0xd1, 0x06, 0xd5, 0xc4, 0x7f, 0x94, 0xbb, 0x92, 0x2d, 0x2c, 0x4b, 0x45, 0x4b, 0xe9, 0x2a, 0x89, 0x6b, 0x2b}} , + {{0xd2, 0x0c, 0x88, 0xc5, 0x48, 0x4d, 0xea, 0x0d, 0x4a, 0xc9, 0x52, 0x6a, 0x61, 0x79, 0xe9, 0x76, 0xf3, 0x85, 0x52, 0x5c, 0x1b, 0x2c, 0xe1, 0xd6, 0xc4, 0x0f, 0x18, 0x0e, 0x4e, 0xf6, 0x1c, 0x7f}}}, +{{{0xb4, 0x04, 0x2e, 0x42, 0xcb, 0x1f, 0x2b, 0x11, 0x51, 0x7b, 0x08, 0xac, 0xaa, 0x3e, 0x9e, 0x52, 0x60, 0xb7, 0xc2, 0x61, 0x57, 0x8c, 0x84, 0xd5, 0x18, 0xa6, 0x19, 0xfc, 0xb7, 0x75, 0x91, 0x1b}} , + {{0xe8, 0x68, 0xca, 0x44, 0xc8, 0x38, 0x38, 0xcc, 0x53, 0x0a, 0x32, 0x35, 0xcc, 0x52, 0xcb, 0x0e, 0xf7, 0xc5, 0xe7, 0xec, 0x3d, 0x85, 0xcc, 0x58, 0xe2, 0x17, 0x47, 0xff, 0x9f, 0xa5, 0x30, 0x17}}}, +{{{0xe3, 0xae, 0xc8, 0xc1, 0x71, 0x75, 0x31, 0x00, 0x37, 0x41, 0x5c, 0x0e, 0x39, 0xda, 0x73, 0xa0, 0xc7, 0x97, 0x36, 0x6c, 0x5b, 0xf2, 0xee, 0x64, 0x0a, 0x3d, 0x89, 0x1e, 0x1d, 0x49, 0x8c, 0x37}} , + {{0x4c, 0xe6, 0xb0, 0xc1, 0xa5, 0x2a, 0x82, 0x09, 0x08, 0xad, 0x79, 0x9c, 0x56, 0xf6, 0xf9, 0xc1, 0xd7, 0x7c, 0x39, 0x7f, 0x93, 0xca, 0x11, 0x55, 0xbf, 0x07, 0x1b, 0x82, 0x29, 0x69, 0x95, 0x5c}}}, +{{{0x87, 0xee, 0xa6, 0x56, 0x9e, 0xc2, 0x9a, 0x56, 0x24, 0x42, 0x85, 0x4d, 0x98, 0x31, 0x1e, 0x60, 0x4d, 0x87, 0x85, 0x04, 0xae, 0x46, 0x12, 0xf9, 0x8e, 0x7f, 0xe4, 0x7f, 0xf6, 0x1c, 0x37, 0x01}} , + {{0x73, 0x4c, 0xb6, 0xc5, 0xc4, 0xe9, 0x6c, 0x85, 0x48, 0x4a, 0x5a, 0xac, 0xd9, 0x1f, 0x43, 0xf8, 0x62, 0x5b, 0xee, 0x98, 0x2a, 0x33, 0x8e, 0x79, 0xce, 0x61, 0x06, 0x35, 0xd8, 0xd7, 0xca, 0x71}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x72, 0xd3, 0xae, 0xa6, 0xca, 0x8f, 0xcd, 0xcc, 0x78, 0x8e, 0x19, 0x4d, 0xa7, 0xd2, 0x27, 0xe9, 0xa4, 0x3c, 0x16, 0x5b, 0x84, 0x80, 0xf9, 0xd0, 0xcc, 0x6a, 0x1e, 0xca, 0x1e, 0x67, 0xbd, 0x63}} , + {{0x7b, 0x6e, 0x2a, 0xd2, 0x87, 0x48, 0xff, 0xa1, 0xca, 0xe9, 0x15, 0x85, 0xdc, 0xdb, 0x2c, 0x39, 0x12, 0x91, 0xa9, 0x20, 0xaa, 0x4f, 0x29, 0xf4, 0x15, 0x7a, 0xd2, 0xf5, 0x32, 0xcc, 0x60, 0x04}}}, +{{{0xe5, 0x10, 0x47, 0x3b, 0xfa, 0x90, 0xfc, 0x30, 0xb5, 0xea, 0x6f, 0x56, 0x8f, 0xfb, 0x0e, 0xa7, 0x3b, 0xc8, 0xb2, 0xff, 0x02, 0x7a, 0x33, 0x94, 0x93, 0x2a, 0x03, 0xe0, 0x96, 0x3a, 0x6c, 0x0f}} , + {{0x5a, 0x63, 0x67, 0xe1, 0x9b, 0x47, 0x78, 0x9f, 0x38, 0x79, 0xac, 0x97, 0x66, 0x1d, 0x5e, 0x51, 0xee, 0x24, 0x42, 0xe8, 0x58, 0x4b, 0x8a, 0x03, 0x75, 0x86, 0x37, 0x86, 0xe2, 0x97, 0x4e, 0x3d}}}, +{{{0x3f, 0x75, 0x8e, 0xb4, 0xff, 0xd8, 0xdd, 0xd6, 0x37, 0x57, 0x9d, 0x6d, 0x3b, 0xbd, 0xd5, 0x60, 0x88, 0x65, 0x9a, 0xb9, 0x4a, 0x68, 0x84, 0xa2, 0x67, 0xdd, 0x17, 0x25, 0x97, 0x04, 0x8b, 0x5e}} , + {{0xbb, 0x40, 0x5e, 0xbc, 0x16, 0x92, 0x05, 0xc4, 0xc0, 0x4e, 0x72, 0x90, 0x0e, 0xab, 0xcf, 0x8a, 0xed, 0xef, 0xb9, 0x2d, 0x3b, 0xf8, 0x43, 0x5b, 0xba, 0x2d, 0xeb, 0x2f, 0x52, 0xd2, 0xd1, 0x5a}}}, +{{{0x40, 0xb4, 0xab, 0xe6, 0xad, 0x9f, 0x46, 0x69, 0x4a, 0xb3, 0x8e, 0xaa, 0xea, 0x9c, 0x8a, 0x20, 0x16, 0x5d, 0x8c, 0x13, 0xbd, 0xf6, 0x1d, 0xc5, 0x24, 0xbd, 0x90, 0x2a, 0x1c, 0xc7, 0x13, 0x3b}} , + {{0x54, 0xdc, 0x16, 0x0d, 0x18, 0xbe, 0x35, 0x64, 0x61, 0x52, 0x02, 0x80, 0xaf, 0x05, 0xf7, 0xa6, 0x42, 0xd3, 0x8f, 0x2e, 0x79, 0x26, 0xa8, 0xbb, 0xb2, 0x17, 0x48, 0xb2, 0x7a, 0x0a, 0x89, 0x14}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x20, 0xa8, 0x88, 0xe3, 0x91, 0xc0, 0x6e, 0xbb, 0x8a, 0x27, 0x82, 0x51, 0x83, 0xb2, 0x28, 0xa9, 0x83, 0xeb, 0xa6, 0xa9, 0x4d, 0x17, 0x59, 0x22, 0x54, 0x00, 0x50, 0x45, 0xcb, 0x48, 0x4b, 0x18}} , + {{0x33, 0x7c, 0xe7, 0x26, 0xba, 0x4d, 0x32, 0xfe, 0x53, 0xf4, 0xfa, 0x83, 0xe3, 0xa5, 0x79, 0x66, 0x73, 0xef, 0x80, 0x23, 0x68, 0xc2, 0x60, 0xdd, 0xa9, 0x33, 0xdc, 0x03, 0x7a, 0xe0, 0xe0, 0x3e}}}, +{{{0x34, 0x5c, 0x13, 0xfb, 0xc0, 0xe3, 0x78, 0x2b, 0x54, 0x58, 0x22, 0x9b, 0x76, 0x81, 0x7f, 0x93, 0x9c, 0x25, 0x3c, 0xd2, 0xe9, 0x96, 0x21, 0x26, 0x08, 0xf5, 0xed, 0x95, 0x11, 0xae, 0x04, 0x5a}} , + {{0xb9, 0xe8, 0xc5, 0x12, 0x97, 0x1f, 0x83, 0xfe, 0x3e, 0x94, 0x99, 0xd4, 0x2d, 0xf9, 0x52, 0x59, 0x5c, 0x82, 0xa6, 0xf0, 0x75, 0x7e, 0xe8, 0xec, 0xcc, 0xac, 0x18, 0x21, 0x09, 0x67, 0x66, 0x67}}}, +{{{0xb3, 0x40, 0x29, 0xd1, 0xcb, 0x1b, 0x08, 0x9e, 0x9c, 0xb7, 0x53, 0xb9, 0x3b, 0x71, 0x08, 0x95, 0x12, 0x1a, 0x58, 0xaf, 0x7e, 0x82, 0x52, 0x43, 0x4f, 0x11, 0x39, 0xf4, 0x93, 0x1a, 0x26, 0x05}} , + {{0x6e, 0x44, 0xa3, 0xf9, 0x64, 0xaf, 0xe7, 0x6d, 0x7d, 0xdf, 0x1e, 0xac, 0x04, 0xea, 0x3b, 0x5f, 0x9b, 0xe8, 0x24, 0x9d, 0x0e, 0xe5, 0x2e, 0x3e, 0xdf, 0xa9, 0xf7, 0xd4, 0x50, 0x71, 0xf0, 0x78}}}, +{{{0x3e, 0xa8, 0x38, 0xc2, 0x57, 0x56, 0x42, 0x9a, 0xb1, 0xe2, 0xf8, 0x45, 0xaa, 0x11, 0x48, 0x5f, 0x17, 0xc4, 0x54, 0x27, 0xdc, 0x5d, 0xaa, 0xdd, 0x41, 0xbc, 0xdf, 0x81, 0xb9, 0x53, 0xee, 0x52}} , + {{0xc3, 0xf1, 0xa7, 0x6d, 0xb3, 0x5f, 0x92, 0x6f, 0xcc, 0x91, 0xb8, 0x95, 0x05, 0xdf, 0x3c, 0x64, 0x57, 0x39, 0x61, 0x51, 0xad, 0x8c, 0x38, 0x7b, 0xc8, 0xde, 0x00, 0x34, 0xbe, 0xa1, 0xb0, 0x7e}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x25, 0x24, 0x1d, 0x8a, 0x67, 0x20, 0xee, 0x42, 0xeb, 0x38, 0xed, 0x0b, 0x8b, 0xcd, 0x46, 0x9d, 0x5e, 0x6b, 0x1e, 0x24, 0x9d, 0x12, 0x05, 0x1a, 0xcc, 0x05, 0x4e, 0x92, 0x38, 0xe1, 0x1f, 0x50}} , + {{0x4e, 0xee, 0x1c, 0x91, 0xe6, 0x11, 0xbd, 0x8e, 0x55, 0x1a, 0x18, 0x75, 0x66, 0xaf, 0x4d, 0x7b, 0x0f, 0xae, 0x6d, 0x85, 0xca, 0x82, 0x58, 0x21, 0x9c, 0x18, 0xe0, 0xed, 0xec, 0x22, 0x80, 0x2f}}}, +{{{0x68, 0x3b, 0x0a, 0x39, 0x1d, 0x6a, 0x15, 0x57, 0xfc, 0xf0, 0x63, 0x54, 0xdb, 0x39, 0xdb, 0xe8, 0x5c, 0x64, 0xff, 0xa0, 0x09, 0x4f, 0x3b, 0xb7, 0x32, 0x60, 0x99, 0x94, 0xfd, 0x94, 0x82, 0x2d}} , + {{0x24, 0xf6, 0x5a, 0x44, 0xf1, 0x55, 0x2c, 0xdb, 0xea, 0x7c, 0x84, 0x7c, 0x01, 0xac, 0xe3, 0xfd, 0xc9, 0x27, 0xc1, 0x5a, 0xb9, 0xde, 0x4f, 0x5a, 0x90, 0xdd, 0xc6, 0x67, 0xaa, 0x6f, 0x8a, 0x3a}}}, +{{{0x78, 0x52, 0x87, 0xc9, 0x97, 0x63, 0xb1, 0xdd, 0x54, 0x5f, 0xc1, 0xf8, 0xf1, 0x06, 0xa6, 0xa8, 0xa3, 0x88, 0x82, 0xd4, 0xcb, 0xa6, 0x19, 0xdd, 0xd1, 0x11, 0x87, 0x08, 0x17, 0x4c, 0x37, 0x2a}} , + {{0xa1, 0x0c, 0xf3, 0x08, 0x43, 0xd9, 0x24, 0x1e, 0x83, 0xa7, 0xdf, 0x91, 0xca, 0xbd, 0x69, 0x47, 0x8d, 0x1b, 0xe2, 0xb9, 0x4e, 0xb5, 0xe1, 0x76, 0xb3, 0x1c, 0x93, 0x03, 0xce, 0x5f, 0xb3, 0x5a}}}, +{{{0x1d, 0xda, 0xe4, 0x61, 0x03, 0x50, 0xa9, 0x8b, 0x68, 0x18, 0xef, 0xb2, 0x1c, 0x84, 0x3b, 0xa2, 0x44, 0x95, 0xa3, 0x04, 0x3b, 0xd6, 0x99, 0x00, 0xaf, 0x76, 0x42, 0x67, 0x02, 0x7d, 0x85, 0x56}} , + {{0xce, 0x72, 0x0e, 0x29, 0x84, 0xb2, 0x7d, 0xd2, 0x45, 0xbe, 0x57, 0x06, 0xed, 0x7f, 0xcf, 0xed, 0xcd, 0xef, 0x19, 0xd6, 0xbc, 0x15, 0x79, 0x64, 0xd2, 0x18, 0xe3, 0x20, 0x67, 0x3a, 0x54, 0x0b}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x52, 0xfd, 0x04, 0xc5, 0xfb, 0x99, 0xe7, 0xe8, 0xfb, 0x8c, 0xe1, 0x42, 0x03, 0xef, 0x9d, 0xd9, 0x9e, 0x4d, 0xf7, 0x80, 0xcf, 0x2e, 0xcc, 0x9b, 0x45, 0xc9, 0x7b, 0x7a, 0xbc, 0x37, 0xa8, 0x52}} , + {{0x96, 0x11, 0x41, 0x8a, 0x47, 0x91, 0xfe, 0xb6, 0xda, 0x7a, 0x54, 0x63, 0xd1, 0x14, 0x35, 0x05, 0x86, 0x8c, 0xa9, 0x36, 0x3f, 0xf2, 0x85, 0x54, 0x4e, 0x92, 0xd8, 0x85, 0x01, 0x46, 0xd6, 0x50}}}, +{{{0x53, 0xcd, 0xf3, 0x86, 0x40, 0xe6, 0x39, 0x42, 0x95, 0xd6, 0xcb, 0x45, 0x1a, 0x20, 0xc8, 0x45, 0x4b, 0x32, 0x69, 0x04, 0xb1, 0xaf, 0x20, 0x46, 0xc7, 0x6b, 0x23, 0x5b, 0x69, 0xee, 0x30, 0x3f}} , + {{0x70, 0x83, 0x47, 0xc0, 0xdb, 0x55, 0x08, 0xa8, 0x7b, 0x18, 0x6d, 0xf5, 0x04, 0x5a, 0x20, 0x0c, 0x4a, 0x8c, 0x60, 0xae, 0xae, 0x0f, 0x64, 0x55, 0x55, 0x2e, 0xd5, 0x1d, 0x53, 0x31, 0x42, 0x41}}}, +{{{0xca, 0xfc, 0x88, 0x6b, 0x96, 0x78, 0x0a, 0x8b, 0x83, 0xdc, 0xbc, 0xaf, 0x40, 0xb6, 0x8d, 0x7f, 0xef, 0xb4, 0xd1, 0x3f, 0xcc, 0xa2, 0x74, 0xc9, 0xc2, 0x92, 0x55, 0x00, 0xab, 0xdb, 0xbf, 0x4f}} , + {{0x93, 0x1c, 0x06, 0x2d, 0x66, 0x65, 0x02, 0xa4, 0x97, 0x18, 0xfd, 0x00, 0xe7, 0xab, 0x03, 0xec, 0xce, 0xc1, 0xbf, 0x37, 0xf8, 0x13, 0x53, 0xa5, 0xe5, 0x0c, 0x3a, 0xa8, 0x55, 0xb9, 0xff, 0x68}}}, +{{{0xe4, 0xe6, 0x6d, 0x30, 0x7d, 0x30, 0x35, 0xc2, 0x78, 0x87, 0xf9, 0xfc, 0x6b, 0x5a, 0xc3, 0xb7, 0x65, 0xd8, 0x2e, 0xc7, 0xa5, 0x0c, 0xc6, 0xdc, 0x12, 0xaa, 0xd6, 0x4f, 0xc5, 0x38, 0xbc, 0x0e}} , + {{0xe2, 0x3c, 0x76, 0x86, 0x38, 0xf2, 0x7b, 0x2c, 0x16, 0x78, 0x8d, 0xf5, 0xa4, 0x15, 0xda, 0xdb, 0x26, 0x85, 0xa0, 0x56, 0xdd, 0x1d, 0xe3, 0xb3, 0xfd, 0x40, 0xef, 0xf2, 0xd9, 0xa1, 0xb3, 0x04}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xdb, 0x49, 0x0e, 0xe6, 0x58, 0x10, 0x7a, 0x52, 0xda, 0xb5, 0x7d, 0x37, 0x6a, 0x3e, 0xa1, 0x78, 0xce, 0xc7, 0x1c, 0x24, 0x23, 0xdb, 0x7d, 0xfb, 0x8c, 0x8d, 0xdc, 0x30, 0x67, 0x69, 0x75, 0x3b}} , + {{0xa9, 0xea, 0x6d, 0x16, 0x16, 0x60, 0xf4, 0x60, 0x87, 0x19, 0x44, 0x8c, 0x4a, 0x8b, 0x3e, 0xfb, 0x16, 0x00, 0x00, 0x54, 0xa6, 0x9e, 0x9f, 0xef, 0xcf, 0xd9, 0xd2, 0x4c, 0x74, 0x31, 0xd0, 0x34}}}, +{{{0xa4, 0xeb, 0x04, 0xa4, 0x8c, 0x8f, 0x71, 0x27, 0x95, 0x85, 0x5d, 0x55, 0x4b, 0xb1, 0x26, 0x26, 0xc8, 0xae, 0x6a, 0x7d, 0xa2, 0x21, 0xca, 0xce, 0x38, 0xab, 0x0f, 0xd0, 0xd5, 0x2b, 0x6b, 0x00}} , + {{0xe5, 0x67, 0x0c, 0xf1, 0x3a, 0x9a, 0xea, 0x09, 0x39, 0xef, 0xd1, 0x30, 0xbc, 0x33, 0xba, 0xb1, 0x6a, 0xc5, 0x27, 0x08, 0x7f, 0x54, 0x80, 0x3d, 0xab, 0xf6, 0x15, 0x7a, 0xc2, 0x40, 0x73, 0x72}}}, +{{{0x84, 0x56, 0x82, 0xb6, 0x12, 0x70, 0x7f, 0xf7, 0xf0, 0xbd, 0x5b, 0xa9, 0xd5, 0xc5, 0x5f, 0x59, 0xbf, 0x7f, 0xb3, 0x55, 0x22, 0x02, 0xc9, 0x44, 0x55, 0x87, 0x8f, 0x96, 0x98, 0x64, 0x6d, 0x15}} , + {{0xb0, 0x8b, 0xaa, 0x1e, 0xec, 0xc7, 0xa5, 0x8f, 0x1f, 0x92, 0x04, 0xc6, 0x05, 0xf6, 0xdf, 0xa1, 0xcc, 0x1f, 0x81, 0xf5, 0x0e, 0x9c, 0x57, 0xdc, 0xe3, 0xbb, 0x06, 0x87, 0x1e, 0xfe, 0x23, 0x6c}}}, +{{{0xd8, 0x2b, 0x5b, 0x16, 0xea, 0x20, 0xf1, 0xd3, 0x68, 0x8f, 0xae, 0x5b, 0xd0, 0xa9, 0x1a, 0x19, 0xa8, 0x36, 0xfb, 0x2b, 0x57, 0x88, 0x7d, 0x90, 0xd5, 0xa6, 0xf3, 0xdc, 0x38, 0x89, 0x4e, 0x1f}} , + {{0xcc, 0x19, 0xda, 0x9b, 0x3b, 0x43, 0x48, 0x21, 0x2e, 0x23, 0x4d, 0x3d, 0xae, 0xf8, 0x8c, 0xfc, 0xdd, 0xa6, 0x74, 0x37, 0x65, 0xca, 0xee, 0x1a, 0x19, 0x8e, 0x9f, 0x64, 0x6f, 0x0c, 0x8b, 0x5a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x25, 0xb9, 0xc2, 0xf0, 0x72, 0xb8, 0x15, 0x16, 0xcc, 0x8d, 0x3c, 0x6f, 0x25, 0xed, 0xf4, 0x46, 0x2e, 0x0c, 0x60, 0x0f, 0xe2, 0x84, 0x34, 0x55, 0x89, 0x59, 0x34, 0x1b, 0xf5, 0x8d, 0xfe, 0x08}} , + {{0xf8, 0xab, 0x93, 0xbc, 0x44, 0xba, 0x1b, 0x75, 0x4b, 0x49, 0x6f, 0xd0, 0x54, 0x2e, 0x63, 0xba, 0xb5, 0xea, 0xed, 0x32, 0x14, 0xc9, 0x94, 0xd8, 0xc5, 0xce, 0xf4, 0x10, 0x68, 0xe0, 0x38, 0x27}}}, +{{{0x74, 0x1c, 0x14, 0x9b, 0xd4, 0x64, 0x61, 0x71, 0x5a, 0xb6, 0x21, 0x33, 0x4f, 0xf7, 0x8e, 0xba, 0xa5, 0x48, 0x9a, 0xc7, 0xfa, 0x9a, 0xf0, 0xb4, 0x62, 0xad, 0xf2, 0x5e, 0xcc, 0x03, 0x24, 0x1a}} , + {{0xf5, 0x76, 0xfd, 0xe4, 0xaf, 0xb9, 0x03, 0x59, 0xce, 0x63, 0xd2, 0x3b, 0x1f, 0xcd, 0x21, 0x0c, 0xad, 0x44, 0xa5, 0x97, 0xac, 0x80, 0x11, 0x02, 0x9b, 0x0c, 0xe5, 0x8b, 0xcd, 0xfb, 0x79, 0x77}}}, +{{{0x15, 0xbe, 0x9a, 0x0d, 0xba, 0x38, 0x72, 0x20, 0x8a, 0xf5, 0xbe, 0x59, 0x93, 0x79, 0xb7, 0xf6, 0x6a, 0x0c, 0x38, 0x27, 0x1a, 0x60, 0xf4, 0x86, 0x3b, 0xab, 0x5a, 0x00, 0xa0, 0xce, 0x21, 0x7d}} , + {{0x6c, 0xba, 0x14, 0xc5, 0xea, 0x12, 0x9e, 0x2e, 0x82, 0x63, 0xce, 0x9b, 0x4a, 0xe7, 0x1d, 0xec, 0xf1, 0x2e, 0x51, 0x1c, 0xf4, 0xd0, 0x69, 0x15, 0x42, 0x9d, 0xa3, 0x3f, 0x0e, 0xbf, 0xe9, 0x5c}}}, +{{{0xe4, 0x0d, 0xf4, 0xbd, 0xee, 0x31, 0x10, 0xed, 0xcb, 0x12, 0x86, 0xad, 0xd4, 0x2f, 0x90, 0x37, 0x32, 0xc3, 0x0b, 0x73, 0xec, 0x97, 0x85, 0xa4, 0x01, 0x1c, 0x76, 0x35, 0xfe, 0x75, 0xdd, 0x71}} , + {{0x11, 0xa4, 0x88, 0x9f, 0x3e, 0x53, 0x69, 0x3b, 0x1b, 0xe0, 0xf7, 0xba, 0x9b, 0xad, 0x4e, 0x81, 0x5f, 0xb5, 0x5c, 0xae, 0xbe, 0x67, 0x86, 0x37, 0x34, 0x8e, 0x07, 0x32, 0x45, 0x4a, 0x67, 0x39}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x90, 0x70, 0x58, 0x20, 0x03, 0x1e, 0x67, 0xb2, 0xc8, 0x9b, 0x58, 0xc5, 0xb1, 0xeb, 0x2d, 0x4a, 0xde, 0x82, 0x8c, 0xf2, 0xd2, 0x14, 0xb8, 0x70, 0x61, 0x4e, 0x73, 0xd6, 0x0b, 0x6b, 0x0d, 0x30}} , + {{0x81, 0xfc, 0x55, 0x5c, 0xbf, 0xa7, 0xc4, 0xbd, 0xe2, 0xf0, 0x4b, 0x8f, 0xe9, 0x7d, 0x99, 0xfa, 0xd3, 0xab, 0xbc, 0xc7, 0x83, 0x2b, 0x04, 0x7f, 0x0c, 0x19, 0x43, 0x03, 0x3d, 0x07, 0xca, 0x40}}}, +{{{0xf9, 0xc8, 0xbe, 0x8c, 0x16, 0x81, 0x39, 0x96, 0xf6, 0x17, 0x58, 0xc8, 0x30, 0x58, 0xfb, 0xc2, 0x03, 0x45, 0xd2, 0x52, 0x76, 0xe0, 0x6a, 0x26, 0x28, 0x5c, 0x88, 0x59, 0x6a, 0x5a, 0x54, 0x42}} , + {{0x07, 0xb5, 0x2e, 0x2c, 0x67, 0x15, 0x9b, 0xfb, 0x83, 0x69, 0x1e, 0x0f, 0xda, 0xd6, 0x29, 0xb1, 0x60, 0xe0, 0xb2, 0xba, 0x69, 0xa2, 0x9e, 0xbd, 0xbd, 0xe0, 0x1c, 0xbd, 0xcd, 0x06, 0x64, 0x70}}}, +{{{0x41, 0xfa, 0x8c, 0xe1, 0x89, 0x8f, 0x27, 0xc8, 0x25, 0x8f, 0x6f, 0x5f, 0x55, 0xf8, 0xde, 0x95, 0x6d, 0x2f, 0x75, 0x16, 0x2b, 0x4e, 0x44, 0xfd, 0x86, 0x6e, 0xe9, 0x70, 0x39, 0x76, 0x97, 0x7e}} , + {{0x17, 0x62, 0x6b, 0x14, 0xa1, 0x7c, 0xd0, 0x79, 0x6e, 0xd8, 0x8a, 0xa5, 0x6d, 0x8c, 0x93, 0xd2, 0x3f, 0xec, 0x44, 0x8d, 0x6e, 0x91, 0x01, 0x8c, 0x8f, 0xee, 0x01, 0x8f, 0xc0, 0xb4, 0x85, 0x0e}}}, +{{{0x02, 0x3a, 0x70, 0x41, 0xe4, 0x11, 0x57, 0x23, 0xac, 0xe6, 0xfc, 0x54, 0x7e, 0xcd, 0xd7, 0x22, 0xcb, 0x76, 0x9f, 0x20, 0xce, 0xa0, 0x73, 0x76, 0x51, 0x3b, 0xa4, 0xf8, 0xe3, 0x62, 0x12, 0x6c}} , + {{0x7f, 0x00, 0x9c, 0x26, 0x0d, 0x6f, 0x48, 0x7f, 0x3a, 0x01, 0xed, 0xc5, 0x96, 0xb0, 0x1f, 0x4f, 0xa8, 0x02, 0x62, 0x27, 0x8a, 0x50, 0x8d, 0x9a, 0x8b, 0x52, 0x0f, 0x1e, 0xcf, 0x41, 0x38, 0x19}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xf5, 0x6c, 0xd4, 0x2f, 0x0f, 0x69, 0x0f, 0x87, 0x3f, 0x61, 0x65, 0x1e, 0x35, 0x34, 0x85, 0xba, 0x02, 0x30, 0xac, 0x25, 0x3d, 0xe2, 0x62, 0xf1, 0xcc, 0xe9, 0x1b, 0xc2, 0xef, 0x6a, 0x42, 0x57}} , + {{0x34, 0x1f, 0x2e, 0xac, 0xd1, 0xc7, 0x04, 0x52, 0x32, 0x66, 0xb2, 0x33, 0x73, 0x21, 0x34, 0x54, 0xf7, 0x71, 0xed, 0x06, 0xb0, 0xff, 0xa6, 0x59, 0x6f, 0x8a, 0x4e, 0xfb, 0x02, 0xb0, 0x45, 0x6b}}}, +{{{0xf5, 0x48, 0x0b, 0x03, 0xc5, 0x22, 0x7d, 0x80, 0x08, 0x53, 0xfe, 0x32, 0xb1, 0xa1, 0x8a, 0x74, 0x6f, 0xbd, 0x3f, 0x85, 0xf4, 0xcf, 0xf5, 0x60, 0xaf, 0x41, 0x7e, 0x3e, 0x46, 0xa3, 0x5a, 0x20}} , + {{0xaa, 0x35, 0x87, 0x44, 0x63, 0x66, 0x97, 0xf8, 0x6e, 0x55, 0x0c, 0x04, 0x3e, 0x35, 0x50, 0xbf, 0x93, 0x69, 0xd2, 0x8b, 0x05, 0x55, 0x99, 0xbe, 0xe2, 0x53, 0x61, 0xec, 0xe8, 0x08, 0x0b, 0x32}}}, +{{{0xb3, 0x10, 0x45, 0x02, 0x69, 0x59, 0x2e, 0x97, 0xd9, 0x64, 0xf8, 0xdb, 0x25, 0x80, 0xdc, 0xc4, 0xd5, 0x62, 0x3c, 0xed, 0x65, 0x91, 0xad, 0xd1, 0x57, 0x81, 0x94, 0xaa, 0xa1, 0x29, 0xfc, 0x68}} , + {{0xdd, 0xb5, 0x7d, 0xab, 0x5a, 0x21, 0x41, 0x53, 0xbb, 0x17, 0x79, 0x0d, 0xd1, 0xa8, 0x0c, 0x0c, 0x20, 0x88, 0x09, 0xe9, 0x84, 0xe8, 0x25, 0x11, 0x67, 0x7a, 0x8b, 0x1a, 0xe4, 0x5d, 0xe1, 0x5d}}}, +{{{0x37, 0xea, 0xfe, 0x65, 0x3b, 0x25, 0xe8, 0xe1, 0xc2, 0xc5, 0x02, 0xa4, 0xbe, 0x98, 0x0a, 0x2b, 0x61, 0xc1, 0x9b, 0xe2, 0xd5, 0x92, 0xe6, 0x9e, 0x7d, 0x1f, 0xca, 0x43, 0x88, 0x8b, 0x2c, 0x59}} , + {{0xe0, 0xb5, 0x00, 0x1d, 0x2a, 0x6f, 0xaf, 0x79, 0x86, 0x2f, 0xa6, 0x5a, 0x93, 0xd1, 0xfe, 0xae, 0x3a, 0xee, 0xdb, 0x7c, 0x61, 0xbe, 0x7c, 0x01, 0xf9, 0xfe, 0x52, 0xdc, 0xd8, 0x52, 0xa3, 0x42}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x22, 0xaf, 0x13, 0x37, 0xbd, 0x37, 0x71, 0xac, 0x04, 0x46, 0x63, 0xac, 0xa4, 0x77, 0xed, 0x25, 0x38, 0xe0, 0x15, 0xa8, 0x64, 0x00, 0x0d, 0xce, 0x51, 0x01, 0xa9, 0xbc, 0x0f, 0x03, 0x1c, 0x04}} , + {{0x89, 0xf9, 0x80, 0x07, 0xcf, 0x3f, 0xb3, 0xe9, 0xe7, 0x45, 0x44, 0x3d, 0x2a, 0x7c, 0xe9, 0xe4, 0x16, 0x5c, 0x5e, 0x65, 0x1c, 0xc7, 0x7d, 0xc6, 0x7a, 0xfb, 0x43, 0xee, 0x25, 0x76, 0x46, 0x72}}}, +{{{0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e, 0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, 0x96, 0x8a, 0xa0, 0xb4, 0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62}} , + {{0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba, 0x08, 0xb6, 0x10, 0x54, 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd, 0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03}}}, +{{{0x51, 0x16, 0x50, 0x7c, 0xd5, 0x5d, 0xf6, 0x99, 0xe8, 0x77, 0x72, 0x4e, 0xfa, 0x62, 0xcb, 0x76, 0x75, 0x0c, 0xe2, 0x71, 0x98, 0x92, 0xd5, 0xfa, 0x45, 0xdf, 0x5c, 0x6f, 0x1e, 0x9e, 0x28, 0x69}} , + {{0x0d, 0xac, 0x66, 0x6d, 0xc3, 0x8b, 0xba, 0x16, 0xb5, 0xe2, 0xa0, 0x0d, 0x0c, 0xbd, 0xa4, 0x8e, 0x18, 0x6c, 0xf2, 0xdc, 0xf9, 0xdc, 0x4a, 0x86, 0x25, 0x95, 0x14, 0xcb, 0xd8, 0x1a, 0x04, 0x0f}}}, +{{{0x97, 0xa5, 0xdb, 0x8b, 0x2d, 0xaa, 0x42, 0x11, 0x09, 0xf2, 0x93, 0xbb, 0xd9, 0x06, 0x84, 0x4e, 0x11, 0xa8, 0xa0, 0x25, 0x2b, 0xa6, 0x5f, 0xae, 0xc4, 0xb4, 0x4c, 0xc8, 0xab, 0xc7, 0x3b, 0x02}} , + {{0xee, 0xc9, 0x29, 0x0f, 0xdf, 0x11, 0x85, 0xed, 0xce, 0x0d, 0x62, 0x2c, 0x8f, 0x4b, 0xf9, 0x04, 0xe9, 0x06, 0x72, 0x1d, 0x37, 0x20, 0x50, 0xc9, 0x14, 0xeb, 0xec, 0x39, 0xa7, 0x97, 0x2b, 0x4d}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x69, 0xd1, 0x39, 0xbd, 0xfb, 0x33, 0xbe, 0xc4, 0xf0, 0x5c, 0xef, 0xf0, 0x56, 0x68, 0xfc, 0x97, 0x47, 0xc8, 0x72, 0xb6, 0x53, 0xa4, 0x0a, 0x98, 0xa5, 0xb4, 0x37, 0x71, 0xcf, 0x66, 0x50, 0x6d}} , + {{0x17, 0xa4, 0x19, 0x52, 0x11, 0x47, 0xb3, 0x5c, 0x5b, 0xa9, 0x2e, 0x22, 0xb4, 0x00, 0x52, 0xf9, 0x57, 0x18, 0xb8, 0xbe, 0x5a, 0xe3, 0xab, 0x83, 0xc8, 0x87, 0x0a, 0x2a, 0xd8, 0x8c, 0xbb, 0x54}}}, +{{{0xa9, 0x62, 0x93, 0x85, 0xbe, 0xe8, 0x73, 0x4a, 0x0e, 0xb0, 0xb5, 0x2d, 0x94, 0x50, 0xaa, 0xd3, 0xb2, 0xea, 0x9d, 0x62, 0x76, 0x3b, 0x07, 0x34, 0x4e, 0x2d, 0x70, 0xc8, 0x9a, 0x15, 0x66, 0x6b}} , + {{0xc5, 0x96, 0xca, 0xc8, 0x22, 0x1a, 0xee, 0x5f, 0xe7, 0x31, 0x60, 0x22, 0x83, 0x08, 0x63, 0xce, 0xb9, 0x32, 0x44, 0x58, 0x5d, 0x3a, 0x9b, 0xe4, 0x04, 0xd5, 0xef, 0x38, 0xef, 0x4b, 0xdd, 0x19}}}, +{{{0x4d, 0xc2, 0x17, 0x75, 0xa1, 0x68, 0xcd, 0xc3, 0xc6, 0x03, 0x44, 0xe3, 0x78, 0x09, 0x91, 0x47, 0x3f, 0x0f, 0xe4, 0x92, 0x58, 0xfa, 0x7d, 0x1f, 0x20, 0x94, 0x58, 0x5e, 0xbc, 0x19, 0x02, 0x6f}} , + {{0x20, 0xd6, 0xd8, 0x91, 0x54, 0xa7, 0xf3, 0x20, 0x4b, 0x34, 0x06, 0xfa, 0x30, 0xc8, 0x6f, 0x14, 0x10, 0x65, 0x74, 0x13, 0x4e, 0xf0, 0x69, 0x26, 0xce, 0xcf, 0x90, 0xf4, 0xd0, 0xc5, 0xc8, 0x64}}}, +{{{0x26, 0xa2, 0x50, 0x02, 0x24, 0x72, 0xf1, 0xf0, 0x4e, 0x2d, 0x93, 0xd5, 0x08, 0xe7, 0xae, 0x38, 0xf7, 0x18, 0xa5, 0x32, 0x34, 0xc2, 0xf0, 0xa6, 0xec, 0xb9, 0x61, 0x7b, 0x64, 0x99, 0xac, 0x71}} , + {{0x25, 0xcf, 0x74, 0x55, 0x1b, 0xaa, 0xa9, 0x38, 0x41, 0x40, 0xd5, 0x95, 0x95, 0xab, 0x1c, 0x5e, 0xbc, 0x41, 0x7e, 0x14, 0x30, 0xbe, 0x13, 0x89, 0xf4, 0xe5, 0xeb, 0x28, 0xc0, 0xc2, 0x96, 0x3a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x2b, 0x77, 0x45, 0xec, 0x67, 0x76, 0x32, 0x4c, 0xb9, 0xdf, 0x25, 0x32, 0x6b, 0xcb, 0xe7, 0x14, 0x61, 0x43, 0xee, 0xba, 0x9b, 0x71, 0xef, 0xd2, 0x48, 0x65, 0xbb, 0x1b, 0x8a, 0x13, 0x1b, 0x22}} , + {{0x84, 0xad, 0x0c, 0x18, 0x38, 0x5a, 0xba, 0xd0, 0x98, 0x59, 0xbf, 0x37, 0xb0, 0x4f, 0x97, 0x60, 0x20, 0xb3, 0x9b, 0x97, 0xf6, 0x08, 0x6c, 0xa4, 0xff, 0xfb, 0xb7, 0xfa, 0x95, 0xb2, 0x51, 0x79}}}, +{{{0x28, 0x5c, 0x3f, 0xdb, 0x6b, 0x18, 0x3b, 0x5c, 0xd1, 0x04, 0x28, 0xde, 0x85, 0x52, 0x31, 0xb5, 0xbb, 0xf6, 0xa9, 0xed, 0xbe, 0x28, 0x4f, 0xb3, 0x7e, 0x05, 0x6a, 0xdb, 0x95, 0x0d, 0x1b, 0x1c}} , + {{0xd5, 0xc5, 0xc3, 0x9a, 0x0a, 0xd0, 0x31, 0x3e, 0x07, 0x36, 0x8e, 0xc0, 0x8a, 0x62, 0xb1, 0xca, 0xd6, 0x0e, 0x1e, 0x9d, 0xef, 0xab, 0x98, 0x4d, 0xbb, 0x6c, 0x05, 0xe0, 0xe4, 0x5d, 0xbd, 0x57}}}, +{{{0xcc, 0x21, 0x27, 0xce, 0xfd, 0xa9, 0x94, 0x8e, 0xe1, 0xab, 0x49, 0xe0, 0x46, 0x26, 0xa1, 0xa8, 0x8c, 0xa1, 0x99, 0x1d, 0xb4, 0x27, 0x6d, 0x2d, 0xc8, 0x39, 0x30, 0x5e, 0x37, 0x52, 0xc4, 0x6e}} , + {{0xa9, 0x85, 0xf4, 0xe7, 0xb0, 0x15, 0x33, 0x84, 0x1b, 0x14, 0x1a, 0x02, 0xd9, 0x3b, 0xad, 0x0f, 0x43, 0x6c, 0xea, 0x3e, 0x0f, 0x7e, 0xda, 0xdd, 0x6b, 0x4c, 0x7f, 0x6e, 0xd4, 0x6b, 0xbf, 0x0f}}}, +{{{0x47, 0x9f, 0x7c, 0x56, 0x7c, 0x43, 0x91, 0x1c, 0xbb, 0x4e, 0x72, 0x3e, 0x64, 0xab, 0xa0, 0xa0, 0xdf, 0xb4, 0xd8, 0x87, 0x3a, 0xbd, 0xa8, 0x48, 0xc9, 0xb8, 0xef, 0x2e, 0xad, 0x6f, 0x84, 0x4f}} , + {{0x2d, 0x2d, 0xf0, 0x1b, 0x7e, 0x2a, 0x6c, 0xf8, 0xa9, 0x6a, 0xe1, 0xf0, 0x99, 0xa1, 0x67, 0x9a, 0xd4, 0x13, 0xca, 0xca, 0xba, 0x27, 0x92, 0xaa, 0xa1, 0x5d, 0x50, 0xde, 0xcc, 0x40, 0x26, 0x0a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x9f, 0x3e, 0xf2, 0xb2, 0x90, 0xce, 0xdb, 0x64, 0x3e, 0x03, 0xdd, 0x37, 0x36, 0x54, 0x70, 0x76, 0x24, 0xb5, 0x69, 0x03, 0xfc, 0xa0, 0x2b, 0x74, 0xb2, 0x05, 0x0e, 0xcc, 0xd8, 0x1f, 0x6a, 0x1f}} , + {{0x19, 0x5e, 0x60, 0x69, 0x58, 0x86, 0xa0, 0x31, 0xbd, 0x32, 0xe9, 0x2c, 0x5c, 0xd2, 0x85, 0xba, 0x40, 0x64, 0xa8, 0x74, 0xf8, 0x0e, 0x1c, 0xb3, 0xa9, 0x69, 0xe8, 0x1e, 0x40, 0x64, 0x99, 0x77}}}, +{{{0x6c, 0x32, 0x4f, 0xfd, 0xbb, 0x5c, 0xbb, 0x8d, 0x64, 0x66, 0x4a, 0x71, 0x1f, 0x79, 0xa3, 0xad, 0x8d, 0xf9, 0xd4, 0xec, 0xcf, 0x67, 0x70, 0xfa, 0x05, 0x4a, 0x0f, 0x6e, 0xaf, 0x87, 0x0a, 0x6f}} , + {{0xc6, 0x36, 0x6e, 0x6c, 0x8c, 0x24, 0x09, 0x60, 0xbe, 0x26, 0xd2, 0x4c, 0x5e, 0x17, 0xca, 0x5f, 0x1d, 0xcc, 0x87, 0xe8, 0x42, 0x6a, 0xcb, 0xcb, 0x7d, 0x92, 0x05, 0x35, 0x81, 0x13, 0x60, 0x6b}}}, +{{{0xf4, 0x15, 0xcd, 0x0f, 0x0a, 0xaf, 0x4e, 0x6b, 0x51, 0xfd, 0x14, 0xc4, 0x2e, 0x13, 0x86, 0x74, 0x44, 0xcb, 0x66, 0x6b, 0xb6, 0x9d, 0x74, 0x56, 0x32, 0xac, 0x8d, 0x8e, 0x8c, 0x8c, 0x8c, 0x39}} , + {{0xca, 0x59, 0x74, 0x1a, 0x11, 0xef, 0x6d, 0xf7, 0x39, 0x5c, 0x3b, 0x1f, 0xfa, 0xe3, 0x40, 0x41, 0x23, 0x9e, 0xf6, 0xd1, 0x21, 0xa2, 0xbf, 0xad, 0x65, 0x42, 0x6b, 0x59, 0x8a, 0xe8, 0xc5, 0x7f}}}, +{{{0x64, 0x05, 0x7a, 0x84, 0x4a, 0x13, 0xc3, 0xf6, 0xb0, 0x6e, 0x9a, 0x6b, 0x53, 0x6b, 0x32, 0xda, 0xd9, 0x74, 0x75, 0xc4, 0xba, 0x64, 0x3d, 0x3b, 0x08, 0xdd, 0x10, 0x46, 0xef, 0xc7, 0x90, 0x1f}} , + {{0x7b, 0x2f, 0x3a, 0xce, 0xc8, 0xa1, 0x79, 0x3c, 0x30, 0x12, 0x44, 0x28, 0xf6, 0xbc, 0xff, 0xfd, 0xf4, 0xc0, 0x97, 0xb0, 0xcc, 0xc3, 0x13, 0x7a, 0xb9, 0x9a, 0x16, 0xe4, 0xcb, 0x4c, 0x34, 0x63}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x07, 0x4e, 0xd3, 0x2d, 0x09, 0x33, 0x0e, 0xd2, 0x0d, 0xbe, 0x3e, 0xe7, 0xe4, 0xaa, 0xb7, 0x00, 0x8b, 0xe8, 0xad, 0xaa, 0x7a, 0x8d, 0x34, 0x28, 0xa9, 0x81, 0x94, 0xc5, 0xe7, 0x42, 0xac, 0x47}} , + {{0x24, 0x89, 0x7a, 0x8f, 0xb5, 0x9b, 0xf0, 0xc2, 0x03, 0x64, 0xd0, 0x1e, 0xf5, 0xa4, 0xb2, 0xf3, 0x74, 0xe9, 0x1a, 0x16, 0xfd, 0xcb, 0x15, 0xea, 0xeb, 0x10, 0x6c, 0x35, 0xd1, 0xc1, 0xa6, 0x28}}}, +{{{0xcc, 0xd5, 0x39, 0xfc, 0xa5, 0xa4, 0xad, 0x32, 0x15, 0xce, 0x19, 0xe8, 0x34, 0x2b, 0x1c, 0x60, 0x91, 0xfc, 0x05, 0xa9, 0xb3, 0xdc, 0x80, 0x29, 0xc4, 0x20, 0x79, 0x06, 0x39, 0xc0, 0xe2, 0x22}} , + {{0xbb, 0xa8, 0xe1, 0x89, 0x70, 0x57, 0x18, 0x54, 0x3c, 0xf6, 0x0d, 0x82, 0x12, 0x05, 0x87, 0x96, 0x06, 0x39, 0xe3, 0xf8, 0xb3, 0x95, 0xe5, 0xd7, 0x26, 0xbf, 0x09, 0x5a, 0x94, 0xf9, 0x1c, 0x63}}}, +{{{0x2b, 0x8c, 0x2d, 0x9a, 0x8b, 0x84, 0xf2, 0x56, 0xfb, 0xad, 0x2e, 0x7f, 0xb7, 0xfc, 0x30, 0xe1, 0x35, 0x89, 0xba, 0x4d, 0xa8, 0x6d, 0xce, 0x8c, 0x8b, 0x30, 0xe0, 0xda, 0x29, 0x18, 0x11, 0x17}} , + {{0x19, 0xa6, 0x5a, 0x65, 0x93, 0xc3, 0xb5, 0x31, 0x22, 0x4f, 0xf3, 0xf6, 0x0f, 0xeb, 0x28, 0xc3, 0x7c, 0xeb, 0xce, 0x86, 0xec, 0x67, 0x76, 0x6e, 0x35, 0x45, 0x7b, 0xd8, 0x6b, 0x92, 0x01, 0x65}}}, +{{{0x3d, 0xd5, 0x9a, 0x64, 0x73, 0x36, 0xb1, 0xd6, 0x86, 0x98, 0x42, 0x3f, 0x8a, 0xf1, 0xc7, 0xf5, 0x42, 0xa8, 0x9c, 0x52, 0xa8, 0xdc, 0xf9, 0x24, 0x3f, 0x4a, 0xa1, 0xa4, 0x5b, 0xe8, 0x62, 0x1a}} , + {{0xc5, 0xbd, 0xc8, 0x14, 0xd5, 0x0d, 0xeb, 0xe1, 0xa5, 0xe6, 0x83, 0x11, 0x09, 0x00, 0x1d, 0x55, 0x83, 0x51, 0x7e, 0x75, 0x00, 0x81, 0xb9, 0xcb, 0xd8, 0xc5, 0xe5, 0xa1, 0xd9, 0x17, 0x6d, 0x1f}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xea, 0xf9, 0xe4, 0xe9, 0xe1, 0x52, 0x3f, 0x51, 0x19, 0x0d, 0xdd, 0xd9, 0x9d, 0x93, 0x31, 0x87, 0x23, 0x09, 0xd5, 0x83, 0xeb, 0x92, 0x09, 0x76, 0x6e, 0xe3, 0xf8, 0xc0, 0xa2, 0x66, 0xb5, 0x36}} , + {{0x3a, 0xbb, 0x39, 0xed, 0x32, 0x02, 0xe7, 0x43, 0x7a, 0x38, 0x14, 0x84, 0xe3, 0x44, 0xd2, 0x5e, 0x94, 0xdd, 0x78, 0x89, 0x55, 0x4c, 0x73, 0x9e, 0xe1, 0xe4, 0x3e, 0x43, 0xd0, 0x4a, 0xde, 0x1b}}}, +{{{0xb2, 0xe7, 0x8f, 0xe3, 0xa3, 0xc5, 0xcb, 0x72, 0xee, 0x79, 0x41, 0xf8, 0xdf, 0xee, 0x65, 0xc5, 0x45, 0x77, 0x27, 0x3c, 0xbd, 0x58, 0xd3, 0x75, 0xe2, 0x04, 0x4b, 0xbb, 0x65, 0xf3, 0xc8, 0x0f}} , + {{0x24, 0x7b, 0x93, 0x34, 0xb5, 0xe2, 0x74, 0x48, 0xcd, 0xa0, 0x0b, 0x92, 0x97, 0x66, 0x39, 0xf4, 0xb0, 0xe2, 0x5d, 0x39, 0x6a, 0x5b, 0x45, 0x17, 0x78, 0x1e, 0xdb, 0x91, 0x81, 0x1c, 0xf9, 0x16}}}, +{{{0x16, 0xdf, 0xd1, 0x5a, 0xd5, 0xe9, 0x4e, 0x58, 0x95, 0x93, 0x5f, 0x51, 0x09, 0xc3, 0x2a, 0xc9, 0xd4, 0x55, 0x48, 0x79, 0xa4, 0xa3, 0xb2, 0xc3, 0x62, 0xaa, 0x8c, 0xe8, 0xad, 0x47, 0x39, 0x1b}} , + {{0x46, 0xda, 0x9e, 0x51, 0x3a, 0xe6, 0xd1, 0xa6, 0xbb, 0x4d, 0x7b, 0x08, 0xbe, 0x8c, 0xd5, 0xf3, 0x3f, 0xfd, 0xf7, 0x44, 0x80, 0x2d, 0x53, 0x4b, 0xd0, 0x87, 0x68, 0xc1, 0xb5, 0xd8, 0xf7, 0x07}}}, +{{{0xf4, 0x10, 0x46, 0xbe, 0xb7, 0xd2, 0xd1, 0xce, 0x5e, 0x76, 0xa2, 0xd7, 0x03, 0xdc, 0xe4, 0x81, 0x5a, 0xf6, 0x3c, 0xde, 0xae, 0x7a, 0x9d, 0x21, 0x34, 0xa5, 0xf6, 0xa9, 0x73, 0xe2, 0x8d, 0x60}} , + {{0xfa, 0x44, 0x71, 0xf6, 0x41, 0xd8, 0xc6, 0x58, 0x13, 0x37, 0xeb, 0x84, 0x0f, 0x96, 0xc7, 0xdc, 0xc8, 0xa9, 0x7a, 0x83, 0xb2, 0x2f, 0x31, 0xb1, 0x1a, 0xd8, 0x98, 0x3f, 0x11, 0xd0, 0x31, 0x3b}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x81, 0xd5, 0x34, 0x16, 0x01, 0xa3, 0x93, 0xea, 0x52, 0x94, 0xec, 0x93, 0xb7, 0x81, 0x11, 0x2d, 0x58, 0xf9, 0xb5, 0x0a, 0xaa, 0x4f, 0xf6, 0x2e, 0x3f, 0x36, 0xbf, 0x33, 0x5a, 0xe7, 0xd1, 0x08}} , + {{0x1a, 0xcf, 0x42, 0xae, 0xcc, 0xb5, 0x77, 0x39, 0xc4, 0x5b, 0x5b, 0xd0, 0x26, 0x59, 0x27, 0xd0, 0x55, 0x71, 0x12, 0x9d, 0x88, 0x3d, 0x9c, 0xea, 0x41, 0x6a, 0xf0, 0x50, 0x93, 0x93, 0xdd, 0x47}}}, +{{{0x6f, 0xc9, 0x51, 0x6d, 0x1c, 0xaa, 0xf5, 0xa5, 0x90, 0x3f, 0x14, 0xe2, 0x6e, 0x8e, 0x64, 0xfd, 0xac, 0xe0, 0x4e, 0x22, 0xe5, 0xc1, 0xbc, 0x29, 0x0a, 0x6a, 0x9e, 0xa1, 0x60, 0xcb, 0x2f, 0x0b}} , + {{0xdc, 0x39, 0x32, 0xf3, 0xa1, 0x44, 0xe9, 0xc5, 0xc3, 0x78, 0xfb, 0x95, 0x47, 0x34, 0x35, 0x34, 0xe8, 0x25, 0xde, 0x93, 0xc6, 0xb4, 0x76, 0x6d, 0x86, 0x13, 0xc6, 0xe9, 0x68, 0xb5, 0x01, 0x63}}}, +{{{0x1f, 0x9a, 0x52, 0x64, 0x97, 0xd9, 0x1c, 0x08, 0x51, 0x6f, 0x26, 0x9d, 0xaa, 0x93, 0x33, 0x43, 0xfa, 0x77, 0xe9, 0x62, 0x9b, 0x5d, 0x18, 0x75, 0xeb, 0x78, 0xf7, 0x87, 0x8f, 0x41, 0xb4, 0x4d}} , + {{0x13, 0xa8, 0x82, 0x3e, 0xe9, 0x13, 0xad, 0xeb, 0x01, 0xca, 0xcf, 0xda, 0xcd, 0xf7, 0x6c, 0xc7, 0x7a, 0xdc, 0x1e, 0x6e, 0xc8, 0x4e, 0x55, 0x62, 0x80, 0xea, 0x78, 0x0c, 0x86, 0xb9, 0x40, 0x51}}}, +{{{0x27, 0xae, 0xd3, 0x0d, 0x4c, 0x8f, 0x34, 0xea, 0x7d, 0x3c, 0xe5, 0x8a, 0xcf, 0x5b, 0x92, 0xd8, 0x30, 0x16, 0xb4, 0xa3, 0x75, 0xff, 0xeb, 0x27, 0xc8, 0x5c, 0x6c, 0xc2, 0xee, 0x6c, 0x21, 0x0b}} , + {{0xc3, 0xba, 0x12, 0x53, 0x2a, 0xaa, 0x77, 0xad, 0x19, 0x78, 0x55, 0x8a, 0x2e, 0x60, 0x87, 0xc2, 0x6e, 0x91, 0x38, 0x91, 0x3f, 0x7a, 0xc5, 0x24, 0x8f, 0x51, 0xc5, 0xde, 0xb0, 0x53, 0x30, 0x56}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x02, 0xfe, 0x54, 0x12, 0x18, 0xca, 0x7d, 0xa5, 0x68, 0x43, 0xa3, 0x6d, 0x14, 0x2a, 0x6a, 0xa5, 0x8e, 0x32, 0xe7, 0x63, 0x4f, 0xe3, 0xc6, 0x44, 0x3e, 0xab, 0x63, 0xca, 0x17, 0x86, 0x74, 0x3f}} , + {{0x1e, 0x64, 0xc1, 0x7d, 0x52, 0xdc, 0x13, 0x5a, 0xa1, 0x9c, 0x4e, 0xee, 0x99, 0x28, 0xbb, 0x4c, 0xee, 0xac, 0xa9, 0x1b, 0x89, 0xa2, 0x38, 0x39, 0x7b, 0xc4, 0x0f, 0x42, 0xe6, 0x89, 0xed, 0x0f}}}, +{{{0xf3, 0x3c, 0x8c, 0x80, 0x83, 0x10, 0x8a, 0x37, 0x50, 0x9c, 0xb4, 0xdf, 0x3f, 0x8c, 0xf7, 0x23, 0x07, 0xd6, 0xff, 0xa0, 0x82, 0x6c, 0x75, 0x3b, 0xe4, 0xb5, 0xbb, 0xe4, 0xe6, 0x50, 0xf0, 0x08}} , + {{0x62, 0xee, 0x75, 0x48, 0x92, 0x33, 0xf2, 0xf4, 0xad, 0x15, 0x7a, 0xa1, 0x01, 0x46, 0xa9, 0x32, 0x06, 0x88, 0xb6, 0x36, 0x47, 0x35, 0xb9, 0xb4, 0x42, 0x85, 0x76, 0xf0, 0x48, 0x00, 0x90, 0x38}}}, +{{{0x51, 0x15, 0x9d, 0xc3, 0x95, 0xd1, 0x39, 0xbb, 0x64, 0x9d, 0x15, 0x81, 0xc1, 0x68, 0xd0, 0xb6, 0xa4, 0x2c, 0x7d, 0x5e, 0x02, 0x39, 0x00, 0xe0, 0x3b, 0xa4, 0xcc, 0xca, 0x1d, 0x81, 0x24, 0x10}} , + {{0xe7, 0x29, 0xf9, 0x37, 0xd9, 0x46, 0x5a, 0xcd, 0x70, 0xfe, 0x4d, 0x5b, 0xbf, 0xa5, 0xcf, 0x91, 0xf4, 0xef, 0xee, 0x8a, 0x29, 0xd0, 0xe7, 0xc4, 0x25, 0x92, 0x8a, 0xff, 0x36, 0xfc, 0xe4, 0x49}}}, +{{{0xbd, 0x00, 0xb9, 0x04, 0x7d, 0x35, 0xfc, 0xeb, 0xd0, 0x0b, 0x05, 0x32, 0x52, 0x7a, 0x89, 0x24, 0x75, 0x50, 0xe1, 0x63, 0x02, 0x82, 0x8e, 0xe7, 0x85, 0x0c, 0xf2, 0x56, 0x44, 0x37, 0x83, 0x25}} , + {{0x8f, 0xa1, 0xce, 0xcb, 0x60, 0xda, 0x12, 0x02, 0x1e, 0x29, 0x39, 0x2a, 0x03, 0xb7, 0xeb, 0x77, 0x40, 0xea, 0xc9, 0x2b, 0x2c, 0xd5, 0x7d, 0x7e, 0x2c, 0xc7, 0x5a, 0xfd, 0xff, 0xc4, 0xd1, 0x62}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x1d, 0x88, 0x98, 0x5b, 0x4e, 0xfc, 0x41, 0x24, 0x05, 0xe6, 0x50, 0x2b, 0xae, 0x96, 0x51, 0xd9, 0x6b, 0x72, 0xb2, 0x33, 0x42, 0x98, 0x68, 0xbb, 0x10, 0x5a, 0x7a, 0x8c, 0x9d, 0x07, 0xb4, 0x05}} , + {{0x2f, 0x61, 0x9f, 0xd7, 0xa8, 0x3f, 0x83, 0x8c, 0x10, 0x69, 0x90, 0xe6, 0xcf, 0xd2, 0x63, 0xa3, 0xe4, 0x54, 0x7e, 0xe5, 0x69, 0x13, 0x1c, 0x90, 0x57, 0xaa, 0xe9, 0x53, 0x22, 0x43, 0x29, 0x23}}}, +{{{0xe5, 0x1c, 0xf8, 0x0a, 0xfd, 0x2d, 0x7e, 0xf5, 0xf5, 0x70, 0x7d, 0x41, 0x6b, 0x11, 0xfe, 0xbe, 0x99, 0xd1, 0x55, 0x29, 0x31, 0xbf, 0xc0, 0x97, 0x6c, 0xd5, 0x35, 0xcc, 0x5e, 0x8b, 0xd9, 0x69}} , + {{0x8e, 0x4e, 0x9f, 0x25, 0xf8, 0x81, 0x54, 0x2d, 0x0e, 0xd5, 0x54, 0x81, 0x9b, 0xa6, 0x92, 0xce, 0x4b, 0xe9, 0x8f, 0x24, 0x3b, 0xca, 0xe0, 0x44, 0xab, 0x36, 0xfe, 0xfb, 0x87, 0xd4, 0x26, 0x3e}}}, +{{{0x0f, 0x93, 0x9c, 0x11, 0xe7, 0xdb, 0xf1, 0xf0, 0x85, 0x43, 0x28, 0x15, 0x37, 0xdd, 0xde, 0x27, 0xdf, 0xad, 0x3e, 0x49, 0x4f, 0xe0, 0x5b, 0xf6, 0x80, 0x59, 0x15, 0x3c, 0x85, 0xb7, 0x3e, 0x12}} , + {{0xf5, 0xff, 0xcc, 0xf0, 0xb4, 0x12, 0x03, 0x5f, 0xc9, 0x84, 0xcb, 0x1d, 0x17, 0xe0, 0xbc, 0xcc, 0x03, 0x62, 0xa9, 0x8b, 0x94, 0xa6, 0xaa, 0x18, 0xcb, 0x27, 0x8d, 0x49, 0xa6, 0x17, 0x15, 0x07}}}, +{{{0xd9, 0xb6, 0xd4, 0x9d, 0xd4, 0x6a, 0xaf, 0x70, 0x07, 0x2c, 0x10, 0x9e, 0xbd, 0x11, 0xad, 0xe4, 0x26, 0x33, 0x70, 0x92, 0x78, 0x1c, 0x74, 0x9f, 0x75, 0x60, 0x56, 0xf4, 0x39, 0xa8, 0xa8, 0x62}} , + {{0x3b, 0xbf, 0x55, 0x35, 0x61, 0x8b, 0x44, 0x97, 0xe8, 0x3a, 0x55, 0xc1, 0xc8, 0x3b, 0xfd, 0x95, 0x29, 0x11, 0x60, 0x96, 0x1e, 0xcb, 0x11, 0x9d, 0xc2, 0x03, 0x8a, 0x1b, 0xc6, 0xd6, 0x45, 0x3d}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x7e, 0x0e, 0x50, 0xb2, 0xcc, 0x0d, 0x6b, 0xa6, 0x71, 0x5b, 0x42, 0xed, 0xbd, 0xaf, 0xac, 0xf0, 0xfc, 0x12, 0xa2, 0x3f, 0x4e, 0xda, 0xe8, 0x11, 0xf3, 0x23, 0xe1, 0x04, 0x62, 0x03, 0x1c, 0x4e}} , + {{0xc8, 0xb1, 0x1b, 0x6f, 0x73, 0x61, 0x3d, 0x27, 0x0d, 0x7d, 0x7a, 0x25, 0x5f, 0x73, 0x0e, 0x2f, 0x93, 0xf6, 0x24, 0xd8, 0x4f, 0x90, 0xac, 0xa2, 0x62, 0x0a, 0xf0, 0x61, 0xd9, 0x08, 0x59, 0x6a}}}, +{{{0x6f, 0x2d, 0x55, 0xf8, 0x2f, 0x8e, 0xf0, 0x18, 0x3b, 0xea, 0xdd, 0x26, 0x72, 0xd1, 0xf5, 0xfe, 0xe5, 0xb8, 0xe6, 0xd3, 0x10, 0x48, 0x46, 0x49, 0x3a, 0x9f, 0x5e, 0x45, 0x6b, 0x90, 0xe8, 0x7f}} , + {{0xd3, 0x76, 0x69, 0x33, 0x7b, 0xb9, 0x40, 0x70, 0xee, 0xa6, 0x29, 0x6b, 0xdd, 0xd0, 0x5d, 0x8d, 0xc1, 0x3e, 0x4a, 0xea, 0x37, 0xb1, 0x03, 0x02, 0x03, 0x35, 0xf1, 0x28, 0x9d, 0xff, 0x00, 0x13}}}, +{{{0x7a, 0xdb, 0x12, 0xd2, 0x8a, 0x82, 0x03, 0x1b, 0x1e, 0xaf, 0xf9, 0x4b, 0x9c, 0xbe, 0xae, 0x7c, 0xe4, 0x94, 0x2a, 0x23, 0xb3, 0x62, 0x86, 0xe7, 0xfd, 0x23, 0xaa, 0x99, 0xbd, 0x2b, 0x11, 0x6c}} , + {{0x8d, 0xa6, 0xd5, 0xac, 0x9d, 0xcc, 0x68, 0x75, 0x7f, 0xc3, 0x4d, 0x4b, 0xdd, 0x6c, 0xbb, 0x11, 0x5a, 0x60, 0xe5, 0xbd, 0x7d, 0x27, 0x8b, 0xda, 0xb4, 0x95, 0xf6, 0x03, 0x27, 0xa4, 0x92, 0x3f}}}, +{{{0x22, 0xd6, 0xb5, 0x17, 0x84, 0xbf, 0x12, 0xcc, 0x23, 0x14, 0x4a, 0xdf, 0x14, 0x31, 0xbc, 0xa1, 0xac, 0x6e, 0xab, 0xfa, 0x57, 0x11, 0x53, 0xb3, 0x27, 0xe6, 0xf9, 0x47, 0x33, 0x44, 0x34, 0x1e}} , + {{0x79, 0xfc, 0xa6, 0xb4, 0x0b, 0x35, 0x20, 0xc9, 0x4d, 0x22, 0x84, 0xc4, 0xa9, 0x20, 0xec, 0x89, 0x94, 0xba, 0x66, 0x56, 0x48, 0xb9, 0x87, 0x7f, 0xca, 0x1e, 0x06, 0xed, 0xa5, 0x55, 0x59, 0x29}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x56, 0xe1, 0xf5, 0xf1, 0xd5, 0xab, 0xa8, 0x2b, 0xae, 0x89, 0xf3, 0xcf, 0x56, 0x9f, 0xf2, 0x4b, 0x31, 0xbc, 0x18, 0xa9, 0x06, 0x5b, 0xbe, 0xb4, 0x61, 0xf8, 0xb2, 0x06, 0x9c, 0x81, 0xab, 0x4c}} , + {{0x1f, 0x68, 0x76, 0x01, 0x16, 0x38, 0x2b, 0x0f, 0x77, 0x97, 0x92, 0x67, 0x4e, 0x86, 0x6a, 0x8b, 0xe5, 0xe8, 0x0c, 0xf7, 0x36, 0x39, 0xb5, 0x33, 0xe6, 0xcf, 0x5e, 0xbd, 0x18, 0xfb, 0x10, 0x1f}}}, +{{{0x83, 0xf0, 0x0d, 0x63, 0xef, 0x53, 0x6b, 0xb5, 0x6b, 0xf9, 0x83, 0xcf, 0xde, 0x04, 0x22, 0x9b, 0x2c, 0x0a, 0xe0, 0xa5, 0xd8, 0xc7, 0x9c, 0xa5, 0xa3, 0xf6, 0x6f, 0xcf, 0x90, 0x6b, 0x68, 0x7c}} , + {{0x33, 0x15, 0xd7, 0x7f, 0x1a, 0xd5, 0x21, 0x58, 0xc4, 0x18, 0xa5, 0xf0, 0xcc, 0x73, 0xa8, 0xfd, 0xfa, 0x18, 0xd1, 0x03, 0x91, 0x8d, 0x52, 0xd2, 0xa3, 0xa4, 0xd3, 0xb1, 0xea, 0x1d, 0x0f, 0x00}}}, +{{{0xcc, 0x48, 0x83, 0x90, 0xe5, 0xfd, 0x3f, 0x84, 0xaa, 0xf9, 0x8b, 0x82, 0x59, 0x24, 0x34, 0x68, 0x4f, 0x1c, 0x23, 0xd9, 0xcc, 0x71, 0xe1, 0x7f, 0x8c, 0xaf, 0xf1, 0xee, 0x00, 0xb6, 0xa0, 0x77}} , + {{0xf5, 0x1a, 0x61, 0xf7, 0x37, 0x9d, 0x00, 0xf4, 0xf2, 0x69, 0x6f, 0x4b, 0x01, 0x85, 0x19, 0x45, 0x4d, 0x7f, 0x02, 0x7c, 0x6a, 0x05, 0x47, 0x6c, 0x1f, 0x81, 0x20, 0xd4, 0xe8, 0x50, 0x27, 0x72}}}, +{{{0x2c, 0x3a, 0xe5, 0xad, 0xf4, 0xdd, 0x2d, 0xf7, 0x5c, 0x44, 0xb5, 0x5b, 0x21, 0xa3, 0x89, 0x5f, 0x96, 0x45, 0xca, 0x4d, 0xa4, 0x21, 0x99, 0x70, 0xda, 0xc4, 0xc4, 0xa0, 0xe5, 0xf4, 0xec, 0x0a}} , + {{0x07, 0x68, 0x21, 0x65, 0xe9, 0x08, 0xa0, 0x0b, 0x6a, 0x4a, 0xba, 0xb5, 0x80, 0xaf, 0xd0, 0x1b, 0xc5, 0xf5, 0x4b, 0x73, 0x50, 0x60, 0x2d, 0x71, 0x69, 0x61, 0x0e, 0xc0, 0x20, 0x40, 0x30, 0x19}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xd0, 0x75, 0x57, 0x3b, 0xeb, 0x5c, 0x14, 0x56, 0x50, 0xc9, 0x4f, 0xb8, 0xb8, 0x1e, 0xa3, 0xf4, 0xab, 0xf5, 0xa9, 0x20, 0x15, 0x94, 0x82, 0xda, 0x96, 0x1c, 0x9b, 0x59, 0x8c, 0xff, 0xf4, 0x51}} , + {{0xc1, 0x3a, 0x86, 0xd7, 0xb0, 0x06, 0x84, 0x7f, 0x1b, 0xbd, 0xd4, 0x07, 0x78, 0x80, 0x2e, 0xb1, 0xb4, 0xee, 0x52, 0x38, 0xee, 0x9a, 0xf9, 0xf6, 0xf3, 0x41, 0x6e, 0xd4, 0x88, 0x95, 0xac, 0x35}}}, +{{{0x41, 0x97, 0xbf, 0x71, 0x6a, 0x9b, 0x72, 0xec, 0xf3, 0xf8, 0x6b, 0xe6, 0x0e, 0x6c, 0x69, 0xa5, 0x2f, 0x68, 0x52, 0xd8, 0x61, 0x81, 0xc0, 0x63, 0x3f, 0xa6, 0x3c, 0x13, 0x90, 0xe6, 0x8d, 0x56}} , + {{0xe8, 0x39, 0x30, 0x77, 0x23, 0xb1, 0xfd, 0x1b, 0x3d, 0x3e, 0x74, 0x4d, 0x7f, 0xae, 0x5b, 0x3a, 0xb4, 0x65, 0x0e, 0x3a, 0x43, 0xdc, 0xdc, 0x41, 0x47, 0xe6, 0xe8, 0x92, 0x09, 0x22, 0x48, 0x4c}}}, +{{{0x85, 0x57, 0x9f, 0xb5, 0xc8, 0x06, 0xb2, 0x9f, 0x47, 0x3f, 0xf0, 0xfa, 0xe6, 0xa9, 0xb1, 0x9b, 0x6f, 0x96, 0x7d, 0xf9, 0xa4, 0x65, 0x09, 0x75, 0x32, 0xa6, 0x6c, 0x7f, 0x47, 0x4b, 0x2f, 0x4f}} , + {{0x34, 0xe9, 0x59, 0x93, 0x9d, 0x26, 0x80, 0x54, 0xf2, 0xcc, 0x3c, 0xc2, 0x25, 0x85, 0xe3, 0x6a, 0xc1, 0x62, 0x04, 0xa7, 0x08, 0x32, 0x6d, 0xa1, 0x39, 0x84, 0x8a, 0x3b, 0x87, 0x5f, 0x11, 0x13}}}, +{{{0xda, 0x03, 0x34, 0x66, 0xc4, 0x0c, 0x73, 0x6e, 0xbc, 0x24, 0xb5, 0xf9, 0x70, 0x81, 0x52, 0xe9, 0xf4, 0x7c, 0x23, 0xdd, 0x9f, 0xb8, 0x46, 0xef, 0x1d, 0x22, 0x55, 0x7d, 0x71, 0xc4, 0x42, 0x33}} , + {{0xc5, 0x37, 0x69, 0x5b, 0xa8, 0xc6, 0x9d, 0xa4, 0xfc, 0x61, 0x6e, 0x68, 0x46, 0xea, 0xd7, 0x1c, 0x67, 0xd2, 0x7d, 0xfa, 0xf1, 0xcc, 0x54, 0x8d, 0x36, 0x35, 0xc9, 0x00, 0xdf, 0x6c, 0x67, 0x50}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x9a, 0x4d, 0x42, 0x29, 0x5d, 0xa4, 0x6b, 0x6f, 0xa8, 0x8a, 0x4d, 0x91, 0x7b, 0xd2, 0xdf, 0x36, 0xef, 0x01, 0x22, 0xc5, 0xcc, 0x8d, 0xeb, 0x58, 0x3d, 0xb3, 0x50, 0xfc, 0x8b, 0x97, 0x96, 0x33}} , + {{0x93, 0x33, 0x07, 0xc8, 0x4a, 0xca, 0xd0, 0xb1, 0xab, 0xbd, 0xdd, 0xa7, 0x7c, 0xac, 0x3e, 0x45, 0xcb, 0xcc, 0x07, 0x91, 0xbf, 0x35, 0x9d, 0xcb, 0x7d, 0x12, 0x3c, 0x11, 0x59, 0x13, 0xcf, 0x5c}}}, +{{{0x45, 0xb8, 0x41, 0xd7, 0xab, 0x07, 0x15, 0x00, 0x8e, 0xce, 0xdf, 0xb2, 0x43, 0x5c, 0x01, 0xdc, 0xf4, 0x01, 0x51, 0x95, 0x10, 0x5a, 0xf6, 0x24, 0x24, 0xa0, 0x19, 0x3a, 0x09, 0x2a, 0xaa, 0x3f}} , + {{0xdc, 0x8e, 0xeb, 0xc6, 0xbf, 0xdd, 0x11, 0x7b, 0xe7, 0x47, 0xe6, 0xce, 0xe7, 0xb6, 0xc5, 0xe8, 0x8a, 0xdc, 0x4b, 0x57, 0x15, 0x3b, 0x66, 0xca, 0x89, 0xa3, 0xfd, 0xac, 0x0d, 0xe1, 0x1d, 0x7a}}}, +{{{0x89, 0xef, 0xbf, 0x03, 0x75, 0xd0, 0x29, 0x50, 0xcb, 0x7d, 0xd6, 0xbe, 0xad, 0x5f, 0x7b, 0x00, 0x32, 0xaa, 0x98, 0xed, 0x3f, 0x8f, 0x92, 0xcb, 0x81, 0x56, 0x01, 0x63, 0x64, 0xa3, 0x38, 0x39}} , + {{0x8b, 0xa4, 0xd6, 0x50, 0xb4, 0xaa, 0x5d, 0x64, 0x64, 0x76, 0x2e, 0xa1, 0xa6, 0xb3, 0xb8, 0x7c, 0x7a, 0x56, 0xf5, 0x5c, 0x4e, 0x84, 0x5c, 0xfb, 0xdd, 0xca, 0x48, 0x8b, 0x48, 0xb9, 0xba, 0x34}}}, +{{{0xc5, 0xe3, 0xe8, 0xae, 0x17, 0x27, 0xe3, 0x64, 0x60, 0x71, 0x47, 0x29, 0x02, 0x0f, 0x92, 0x5d, 0x10, 0x93, 0xc8, 0x0e, 0xa1, 0xed, 0xba, 0xa9, 0x96, 0x1c, 0xc5, 0x76, 0x30, 0xcd, 0xf9, 0x30}} , + {{0x95, 0xb0, 0xbd, 0x8c, 0xbc, 0xa7, 0x4f, 0x7e, 0xfd, 0x4e, 0x3a, 0xbf, 0x5f, 0x04, 0x79, 0x80, 0x2b, 0x5a, 0x9f, 0x4f, 0x68, 0x21, 0x19, 0x71, 0xc6, 0x20, 0x01, 0x42, 0xaa, 0xdf, 0xae, 0x2c}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x90, 0x6e, 0x7e, 0x4b, 0x71, 0x93, 0xc0, 0x72, 0xed, 0xeb, 0x71, 0x24, 0x97, 0x26, 0x9c, 0xfe, 0xcb, 0x3e, 0x59, 0x19, 0xa8, 0x0f, 0x75, 0x7d, 0xbe, 0x18, 0xe6, 0x96, 0x1e, 0x95, 0x70, 0x60}} , + {{0x89, 0x66, 0x3e, 0x1d, 0x4c, 0x5f, 0xfe, 0xc0, 0x04, 0x43, 0xd6, 0x44, 0x19, 0xb5, 0xad, 0xc7, 0x22, 0xdc, 0x71, 0x28, 0x64, 0xde, 0x41, 0x38, 0x27, 0x8f, 0x2c, 0x6b, 0x08, 0xb8, 0xb8, 0x7b}}}, +{{{0x3d, 0x70, 0x27, 0x9d, 0xd9, 0xaf, 0xb1, 0x27, 0xaf, 0xe3, 0x5d, 0x1e, 0x3a, 0x30, 0x54, 0x61, 0x60, 0xe8, 0xc3, 0x26, 0x3a, 0xbc, 0x7e, 0xf5, 0x81, 0xdd, 0x64, 0x01, 0x04, 0xeb, 0xc0, 0x1e}} , + {{0xda, 0x2c, 0xa4, 0xd1, 0xa1, 0xc3, 0x5c, 0x6e, 0x32, 0x07, 0x1f, 0xb8, 0x0e, 0x19, 0x9e, 0x99, 0x29, 0x33, 0x9a, 0xae, 0x7a, 0xed, 0x68, 0x42, 0x69, 0x7c, 0x07, 0xb3, 0x38, 0x2c, 0xf6, 0x3d}}}, +{{{0x64, 0xaa, 0xb5, 0x88, 0x79, 0x65, 0x38, 0x8c, 0x94, 0xd6, 0x62, 0x37, 0x7d, 0x64, 0xcd, 0x3a, 0xeb, 0xff, 0xe8, 0x81, 0x09, 0xc7, 0x6a, 0x50, 0x09, 0x0d, 0x28, 0x03, 0x0d, 0x9a, 0x93, 0x0a}} , + {{0x42, 0xa3, 0xf1, 0xc5, 0xb4, 0x0f, 0xd8, 0xc8, 0x8d, 0x15, 0x31, 0xbd, 0xf8, 0x07, 0x8b, 0xcd, 0x08, 0x8a, 0xfb, 0x18, 0x07, 0xfe, 0x8e, 0x52, 0x86, 0xef, 0xbe, 0xec, 0x49, 0x52, 0x99, 0x08}}}, +{{{0x0f, 0xa9, 0xd5, 0x01, 0xaa, 0x48, 0x4f, 0x28, 0x66, 0x32, 0x1a, 0xba, 0x7c, 0xea, 0x11, 0x80, 0x17, 0x18, 0x9b, 0x56, 0x88, 0x25, 0x06, 0x69, 0x12, 0x2c, 0xea, 0x56, 0x69, 0x41, 0x24, 0x19}} , + {{0xde, 0x21, 0xf0, 0xda, 0x8a, 0xfb, 0xb1, 0xb8, 0xcd, 0xc8, 0x6a, 0x82, 0x19, 0x73, 0xdb, 0xc7, 0xcf, 0x88, 0xeb, 0x96, 0xee, 0x6f, 0xfb, 0x06, 0xd2, 0xcd, 0x7d, 0x7b, 0x12, 0x28, 0x8e, 0x0c}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x93, 0x44, 0x97, 0xce, 0x28, 0xff, 0x3a, 0x40, 0xc4, 0xf5, 0xf6, 0x9b, 0xf4, 0x6b, 0x07, 0x84, 0xfb, 0x98, 0xd8, 0xec, 0x8c, 0x03, 0x57, 0xec, 0x49, 0xed, 0x63, 0xb6, 0xaa, 0xff, 0x98, 0x28}} , + {{0x3d, 0x16, 0x35, 0xf3, 0x46, 0xbc, 0xb3, 0xf4, 0xc6, 0xb6, 0x4f, 0xfa, 0xf4, 0xa0, 0x13, 0xe6, 0x57, 0x45, 0x93, 0xb9, 0xbc, 0xd6, 0x59, 0xe7, 0x77, 0x94, 0x6c, 0xab, 0x96, 0x3b, 0x4f, 0x09}}}, +{{{0x5a, 0xf7, 0x6b, 0x01, 0x12, 0x4f, 0x51, 0xc1, 0x70, 0x84, 0x94, 0x47, 0xb2, 0x01, 0x6c, 0x71, 0xd7, 0xcc, 0x17, 0x66, 0x0f, 0x59, 0x5d, 0x5d, 0x10, 0x01, 0x57, 0x11, 0xf5, 0xdd, 0xe2, 0x34}} , + {{0x26, 0xd9, 0x1f, 0x5c, 0x58, 0xac, 0x8b, 0x03, 0xd2, 0xc3, 0x85, 0x0f, 0x3a, 0xc3, 0x7f, 0x6d, 0x8e, 0x86, 0xcd, 0x52, 0x74, 0x8f, 0x55, 0x77, 0x17, 0xb7, 0x8e, 0xb7, 0x88, 0xea, 0xda, 0x1b}}}, +{{{0xb6, 0xea, 0x0e, 0x40, 0x93, 0x20, 0x79, 0x35, 0x6a, 0x61, 0x84, 0x5a, 0x07, 0x6d, 0xf9, 0x77, 0x6f, 0xed, 0x69, 0x1c, 0x0d, 0x25, 0x76, 0xcc, 0xf0, 0xdb, 0xbb, 0xc5, 0xad, 0xe2, 0x26, 0x57}} , + {{0xcf, 0xe8, 0x0e, 0x6b, 0x96, 0x7d, 0xed, 0x27, 0xd1, 0x3c, 0xa9, 0xd9, 0x50, 0xa9, 0x98, 0x84, 0x5e, 0x86, 0xef, 0xd6, 0xf0, 0xf8, 0x0e, 0x89, 0x05, 0x2f, 0xd9, 0x5f, 0x15, 0x5f, 0x73, 0x79}}}, +{{{0xc8, 0x5c, 0x16, 0xfe, 0xed, 0x9f, 0x26, 0x56, 0xf6, 0x4b, 0x9f, 0xa7, 0x0a, 0x85, 0xfe, 0xa5, 0x8c, 0x87, 0xdd, 0x98, 0xce, 0x4e, 0xc3, 0x58, 0x55, 0xb2, 0x7b, 0x3d, 0xd8, 0x6b, 0xb5, 0x4c}} , + {{0x65, 0x38, 0xa0, 0x15, 0xfa, 0xa7, 0xb4, 0x8f, 0xeb, 0xc4, 0x86, 0x9b, 0x30, 0xa5, 0x5e, 0x4d, 0xea, 0x8a, 0x9a, 0x9f, 0x1a, 0xd8, 0x5b, 0x53, 0x14, 0x19, 0x25, 0x63, 0xb4, 0x6f, 0x1f, 0x5d}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xac, 0x8f, 0xbc, 0x1e, 0x7d, 0x8b, 0x5a, 0x0b, 0x8d, 0xaf, 0x76, 0x2e, 0x71, 0xe3, 0x3b, 0x6f, 0x53, 0x2f, 0x3e, 0x90, 0x95, 0xd4, 0x35, 0x14, 0x4f, 0x8c, 0x3c, 0xce, 0x57, 0x1c, 0x76, 0x49}} , + {{0xa8, 0x50, 0xe1, 0x61, 0x6b, 0x57, 0x35, 0xeb, 0x44, 0x0b, 0x0c, 0x6e, 0xf9, 0x25, 0x80, 0x74, 0xf2, 0x8f, 0x6f, 0x7a, 0x3e, 0x7f, 0x2d, 0xf3, 0x4e, 0x09, 0x65, 0x10, 0x5e, 0x03, 0x25, 0x32}}}, +{{{0xa9, 0x60, 0xdc, 0x0f, 0x64, 0xe5, 0x1d, 0xe2, 0x8d, 0x4f, 0x79, 0x2f, 0x0e, 0x24, 0x02, 0x00, 0x05, 0x77, 0x43, 0x25, 0x3d, 0x6a, 0xc7, 0xb7, 0xbf, 0x04, 0x08, 0x65, 0xf4, 0x39, 0x4b, 0x65}} , + {{0x96, 0x19, 0x12, 0x6b, 0x6a, 0xb7, 0xe3, 0xdc, 0x45, 0x9b, 0xdb, 0xb4, 0xa8, 0xae, 0xdc, 0xa8, 0x14, 0x44, 0x65, 0x62, 0xce, 0x34, 0x9a, 0x84, 0x18, 0x12, 0x01, 0xf1, 0xe2, 0x7b, 0xce, 0x50}}}, +{{{0x41, 0x21, 0x30, 0x53, 0x1b, 0x47, 0x01, 0xb7, 0x18, 0xd8, 0x82, 0x57, 0xbd, 0xa3, 0x60, 0xf0, 0x32, 0xf6, 0x5b, 0xf0, 0x30, 0x88, 0x91, 0x59, 0xfd, 0x90, 0xa2, 0xb9, 0x55, 0x93, 0x21, 0x34}} , + {{0x97, 0x67, 0x9e, 0xeb, 0x6a, 0xf9, 0x6e, 0xd6, 0x73, 0xe8, 0x6b, 0x29, 0xec, 0x63, 0x82, 0x00, 0xa8, 0x99, 0x1c, 0x1d, 0x30, 0xc8, 0x90, 0x52, 0x90, 0xb6, 0x6a, 0x80, 0x4e, 0xff, 0x4b, 0x51}}}, +{{{0x0f, 0x7d, 0x63, 0x8c, 0x6e, 0x5c, 0xde, 0x30, 0xdf, 0x65, 0xfa, 0x2e, 0xb0, 0xa3, 0x25, 0x05, 0x54, 0xbd, 0x25, 0xba, 0x06, 0xae, 0xdf, 0x8b, 0xd9, 0x1b, 0xea, 0x38, 0xb3, 0x05, 0x16, 0x09}} , + {{0xc7, 0x8c, 0xbf, 0x64, 0x28, 0xad, 0xf8, 0xa5, 0x5a, 0x6f, 0xc9, 0xba, 0xd5, 0x7f, 0xd5, 0xd6, 0xbd, 0x66, 0x2f, 0x3d, 0xaa, 0x54, 0xf6, 0xba, 0x32, 0x22, 0x9a, 0x1e, 0x52, 0x05, 0xf4, 0x1d}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xaa, 0x1f, 0xbb, 0xeb, 0xfe, 0xe4, 0x87, 0xfc, 0xb1, 0x2c, 0xb7, 0x88, 0xf4, 0xc6, 0xb9, 0xf5, 0x24, 0x46, 0xf2, 0xa5, 0x9f, 0x8f, 0x8a, 0x93, 0x70, 0x69, 0xd4, 0x56, 0xec, 0xfd, 0x06, 0x46}} , + {{0x4e, 0x66, 0xcf, 0x4e, 0x34, 0xce, 0x0c, 0xd9, 0xa6, 0x50, 0xd6, 0x5e, 0x95, 0xaf, 0xe9, 0x58, 0xfa, 0xee, 0x9b, 0xb8, 0xa5, 0x0f, 0x35, 0xe0, 0x43, 0x82, 0x6d, 0x65, 0xe6, 0xd9, 0x00, 0x0f}}}, +{{{0x7b, 0x75, 0x3a, 0xfc, 0x64, 0xd3, 0x29, 0x7e, 0xdd, 0x49, 0x9a, 0x59, 0x53, 0xbf, 0xb4, 0xa7, 0x52, 0xb3, 0x05, 0xab, 0xc3, 0xaf, 0x16, 0x1a, 0x85, 0x42, 0x32, 0xa2, 0x86, 0xfa, 0x39, 0x43}} , + {{0x0e, 0x4b, 0xa3, 0x63, 0x8a, 0xfe, 0xa5, 0x58, 0xf1, 0x13, 0xbd, 0x9d, 0xaa, 0x7f, 0x76, 0x40, 0x70, 0x81, 0x10, 0x75, 0x99, 0xbb, 0xbe, 0x0b, 0x16, 0xe9, 0xba, 0x62, 0x34, 0xcc, 0x07, 0x6d}}}, +{{{0xc3, 0xf1, 0xc6, 0x93, 0x65, 0xee, 0x0b, 0xbc, 0xea, 0x14, 0xf0, 0xc1, 0xf8, 0x84, 0x89, 0xc2, 0xc9, 0xd7, 0xea, 0x34, 0xca, 0xa7, 0xc4, 0x99, 0xd5, 0x50, 0x69, 0xcb, 0xd6, 0x21, 0x63, 0x7c}} , + {{0x99, 0xeb, 0x7c, 0x31, 0x73, 0x64, 0x67, 0x7f, 0x0c, 0x66, 0xaa, 0x8c, 0x69, 0x91, 0xe2, 0x26, 0xd3, 0x23, 0xe2, 0x76, 0x5d, 0x32, 0x52, 0xdf, 0x5d, 0xc5, 0x8f, 0xb7, 0x7c, 0x84, 0xb3, 0x70}}}, +{{{0xeb, 0x01, 0xc7, 0x36, 0x97, 0x4e, 0xb6, 0xab, 0x5f, 0x0d, 0x2c, 0xba, 0x67, 0x64, 0x55, 0xde, 0xbc, 0xff, 0xa6, 0xec, 0x04, 0xd3, 0x8d, 0x39, 0x56, 0x5e, 0xee, 0xf8, 0xe4, 0x2e, 0x33, 0x62}} , + {{0x65, 0xef, 0xb8, 0x9f, 0xc8, 0x4b, 0xa7, 0xfd, 0x21, 0x49, 0x9b, 0x92, 0x35, 0x82, 0xd6, 0x0a, 0x9b, 0xf2, 0x79, 0xf1, 0x47, 0x2f, 0x6a, 0x7e, 0x9f, 0xcf, 0x18, 0x02, 0x3c, 0xfb, 0x1b, 0x3e}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x2f, 0x8b, 0xc8, 0x40, 0x51, 0xd1, 0xac, 0x1a, 0x0b, 0xe4, 0xa9, 0xa2, 0x42, 0x21, 0x19, 0x2f, 0x7b, 0x97, 0xbf, 0xf7, 0x57, 0x6d, 0x3f, 0x3d, 0x4f, 0x0f, 0xe2, 0xb2, 0x81, 0x00, 0x9e, 0x7b}} , + {{0x8c, 0x85, 0x2b, 0xc4, 0xfc, 0xf1, 0xab, 0xe8, 0x79, 0x22, 0xc4, 0x84, 0x17, 0x3a, 0xfa, 0x86, 0xa6, 0x7d, 0xf9, 0xf3, 0x6f, 0x03, 0x57, 0x20, 0x4d, 0x79, 0xf9, 0x6e, 0x71, 0x54, 0x38, 0x09}}}, +{{{0x40, 0x29, 0x74, 0xa8, 0x2f, 0x5e, 0xf9, 0x79, 0xa4, 0xf3, 0x3e, 0xb9, 0xfd, 0x33, 0x31, 0xac, 0x9a, 0x69, 0x88, 0x1e, 0x77, 0x21, 0x2d, 0xf3, 0x91, 0x52, 0x26, 0x15, 0xb2, 0xa6, 0xcf, 0x7e}} , + {{0xc6, 0x20, 0x47, 0x6c, 0xa4, 0x7d, 0xcb, 0x63, 0xea, 0x5b, 0x03, 0xdf, 0x3e, 0x88, 0x81, 0x6d, 0xce, 0x07, 0x42, 0x18, 0x60, 0x7e, 0x7b, 0x55, 0xfe, 0x6a, 0xf3, 0xda, 0x5c, 0x8b, 0x95, 0x10}}}, +{{{0x62, 0xe4, 0x0d, 0x03, 0xb4, 0xd7, 0xcd, 0xfa, 0xbd, 0x46, 0xdf, 0x93, 0x71, 0x10, 0x2c, 0xa8, 0x3b, 0xb6, 0x09, 0x05, 0x70, 0x84, 0x43, 0x29, 0xa8, 0x59, 0xf5, 0x8e, 0x10, 0xe4, 0xd7, 0x20}} , + {{0x57, 0x82, 0x1c, 0xab, 0xbf, 0x62, 0x70, 0xe8, 0xc4, 0xcf, 0xf0, 0x28, 0x6e, 0x16, 0x3c, 0x08, 0x78, 0x89, 0x85, 0x46, 0x0f, 0xf6, 0x7f, 0xcf, 0xcb, 0x7e, 0xb8, 0x25, 0xe9, 0x5a, 0xfa, 0x03}}}, +{{{0xfb, 0x95, 0x92, 0x63, 0x50, 0xfc, 0x62, 0xf0, 0xa4, 0x5e, 0x8c, 0x18, 0xc2, 0x17, 0x24, 0xb7, 0x78, 0xc2, 0xa9, 0xe7, 0x6a, 0x32, 0xd6, 0x29, 0x85, 0xaf, 0xcb, 0x8d, 0x91, 0x13, 0xda, 0x6b}} , + {{0x36, 0x0a, 0xc2, 0xb6, 0x4b, 0xa5, 0x5d, 0x07, 0x17, 0x41, 0x31, 0x5f, 0x62, 0x46, 0xf8, 0x92, 0xf9, 0x66, 0x48, 0x73, 0xa6, 0x97, 0x0d, 0x7d, 0x88, 0xee, 0x62, 0xb1, 0x03, 0xa8, 0x3f, 0x2c}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x4a, 0xb1, 0x70, 0x8a, 0xa9, 0xe8, 0x63, 0x79, 0x00, 0xe2, 0x25, 0x16, 0xca, 0x4b, 0x0f, 0xa4, 0x66, 0xad, 0x19, 0x9f, 0x88, 0x67, 0x0c, 0x8b, 0xc2, 0x4a, 0x5b, 0x2b, 0x6d, 0x95, 0xaf, 0x19}} , + {{0x8b, 0x9d, 0xb6, 0xcc, 0x60, 0xb4, 0x72, 0x4f, 0x17, 0x69, 0x5a, 0x4a, 0x68, 0x34, 0xab, 0xa1, 0x45, 0x32, 0x3c, 0x83, 0x87, 0x72, 0x30, 0x54, 0x77, 0x68, 0xae, 0xfb, 0xb5, 0x8b, 0x22, 0x5e}}}, +{{{0xf1, 0xb9, 0x87, 0x35, 0xc5, 0xbb, 0xb9, 0xcf, 0xf5, 0xd6, 0xcd, 0xd5, 0x0c, 0x7c, 0x0e, 0xe6, 0x90, 0x34, 0xfb, 0x51, 0x42, 0x1e, 0x6d, 0xac, 0x9a, 0x46, 0xc4, 0x97, 0x29, 0x32, 0xbf, 0x45}} , + {{0x66, 0x9e, 0xc6, 0x24, 0xc0, 0xed, 0xa5, 0x5d, 0x88, 0xd4, 0xf0, 0x73, 0x97, 0x7b, 0xea, 0x7f, 0x42, 0xff, 0x21, 0xa0, 0x9b, 0x2f, 0x9a, 0xfd, 0x53, 0x57, 0x07, 0x84, 0x48, 0x88, 0x9d, 0x52}}}, +{{{0xc6, 0x96, 0x48, 0x34, 0x2a, 0x06, 0xaf, 0x94, 0x3d, 0xf4, 0x1a, 0xcf, 0xf2, 0xc0, 0x21, 0xc2, 0x42, 0x5e, 0xc8, 0x2f, 0x35, 0xa2, 0x3e, 0x29, 0xfa, 0x0c, 0x84, 0xe5, 0x89, 0x72, 0x7c, 0x06}} , + {{0x32, 0x65, 0x03, 0xe5, 0x89, 0xa6, 0x6e, 0xb3, 0x5b, 0x8e, 0xca, 0xeb, 0xfe, 0x22, 0x56, 0x8b, 0x5d, 0x14, 0x4b, 0x4d, 0xf9, 0xbe, 0xb5, 0xf5, 0xe6, 0x5c, 0x7b, 0x8b, 0xf4, 0x13, 0x11, 0x34}}}, +{{{0x07, 0xc6, 0x22, 0x15, 0xe2, 0x9c, 0x60, 0xa2, 0x19, 0xd9, 0x27, 0xae, 0x37, 0x4e, 0xa6, 0xc9, 0x80, 0xa6, 0x91, 0x8f, 0x12, 0x49, 0xe5, 0x00, 0x18, 0x47, 0xd1, 0xd7, 0x28, 0x22, 0x63, 0x39}} , + {{0xe8, 0xe2, 0x00, 0x7e, 0xf2, 0x9e, 0x1e, 0x99, 0x39, 0x95, 0x04, 0xbd, 0x1e, 0x67, 0x7b, 0xb2, 0x26, 0xac, 0xe6, 0xaa, 0xe2, 0x46, 0xd5, 0xe4, 0xe8, 0x86, 0xbd, 0xab, 0x7c, 0x55, 0x59, 0x6f}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x24, 0x64, 0x6e, 0x9b, 0x35, 0x71, 0x78, 0xce, 0x33, 0x03, 0x21, 0x33, 0x36, 0xf1, 0x73, 0x9b, 0xb9, 0x15, 0x8b, 0x2c, 0x69, 0xcf, 0x4d, 0xed, 0x4f, 0x4d, 0x57, 0x14, 0x13, 0x82, 0xa4, 0x4d}} , + {{0x65, 0x6e, 0x0a, 0xa4, 0x59, 0x07, 0x17, 0xf2, 0x6b, 0x4a, 0x1f, 0x6e, 0xf6, 0xb5, 0xbc, 0x62, 0xe4, 0xb6, 0xda, 0xa2, 0x93, 0xbc, 0x29, 0x05, 0xd2, 0xd2, 0x73, 0x46, 0x03, 0x16, 0x40, 0x31}}}, +{{{0x4c, 0x73, 0x6d, 0x15, 0xbd, 0xa1, 0x4d, 0x5c, 0x13, 0x0b, 0x24, 0x06, 0x98, 0x78, 0x1c, 0x5b, 0xeb, 0x1f, 0x18, 0x54, 0x43, 0xd9, 0x55, 0x66, 0xda, 0x29, 0x21, 0xe8, 0xb8, 0x3c, 0x42, 0x22}} , + {{0xb4, 0xcd, 0x08, 0x6f, 0x15, 0x23, 0x1a, 0x0b, 0x22, 0xed, 0xd1, 0xf1, 0xa7, 0xc7, 0x73, 0x45, 0xf3, 0x9e, 0xce, 0x76, 0xb7, 0xf6, 0x39, 0xb6, 0x8e, 0x79, 0xbe, 0xe9, 0x9b, 0xcf, 0x7d, 0x62}}}, +{{{0x92, 0x5b, 0xfc, 0x72, 0xfd, 0xba, 0xf1, 0xfd, 0xa6, 0x7c, 0x95, 0xe3, 0x61, 0x3f, 0xe9, 0x03, 0xd4, 0x2b, 0xd4, 0x20, 0xd9, 0xdb, 0x4d, 0x32, 0x3e, 0xf5, 0x11, 0x64, 0xe3, 0xb4, 0xbe, 0x32}} , + {{0x86, 0x17, 0x90, 0xe7, 0xc9, 0x1f, 0x10, 0xa5, 0x6a, 0x2d, 0x39, 0xd0, 0x3b, 0xc4, 0xa6, 0xe9, 0x59, 0x13, 0xda, 0x1a, 0xe6, 0xa0, 0xb9, 0x3c, 0x50, 0xb8, 0x40, 0x7c, 0x15, 0x36, 0x5a, 0x42}}}, +{{{0xb4, 0x0b, 0x32, 0xab, 0xdc, 0x04, 0x51, 0x55, 0x21, 0x1e, 0x0b, 0x75, 0x99, 0x89, 0x73, 0x35, 0x3a, 0x91, 0x2b, 0xfe, 0xe7, 0x49, 0xea, 0x76, 0xc1, 0xf9, 0x46, 0xb9, 0x53, 0x02, 0x23, 0x04}} , + {{0xfc, 0x5a, 0x1e, 0x1d, 0x74, 0x58, 0x95, 0xa6, 0x8f, 0x7b, 0x97, 0x3e, 0x17, 0x3b, 0x79, 0x2d, 0xa6, 0x57, 0xef, 0x45, 0x02, 0x0b, 0x4d, 0x6e, 0x9e, 0x93, 0x8d, 0x2f, 0xd9, 0x9d, 0xdb, 0x04}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xc0, 0xd7, 0x56, 0x97, 0x58, 0x91, 0xde, 0x09, 0x4f, 0x9f, 0xbe, 0x63, 0xb0, 0x83, 0x86, 0x43, 0x5d, 0xbc, 0xe0, 0xf3, 0xc0, 0x75, 0xbf, 0x8b, 0x8e, 0xaa, 0xf7, 0x8b, 0x64, 0x6e, 0xb0, 0x63}} , + {{0x16, 0xae, 0x8b, 0xe0, 0x9b, 0x24, 0x68, 0x5c, 0x44, 0xc2, 0xd0, 0x08, 0xb7, 0x7b, 0x62, 0xfd, 0x7f, 0xd8, 0xd4, 0xb7, 0x50, 0xfd, 0x2c, 0x1b, 0xbf, 0x41, 0x95, 0xd9, 0x8e, 0xd8, 0x17, 0x1b}}}, +{{{0x86, 0x55, 0x37, 0x8e, 0xc3, 0x38, 0x48, 0x14, 0xb5, 0x97, 0xd2, 0xa7, 0x54, 0x45, 0xf1, 0x35, 0x44, 0x38, 0x9e, 0xf1, 0x1b, 0xb6, 0x34, 0x00, 0x3c, 0x96, 0xee, 0x29, 0x00, 0xea, 0x2c, 0x0b}} , + {{0xea, 0xda, 0x99, 0x9e, 0x19, 0x83, 0x66, 0x6d, 0xe9, 0x76, 0x87, 0x50, 0xd1, 0xfd, 0x3c, 0x60, 0x87, 0xc6, 0x41, 0xd9, 0x8e, 0xdb, 0x5e, 0xde, 0xaa, 0x9a, 0xd3, 0x28, 0xda, 0x95, 0xea, 0x47}}}, +{{{0xd0, 0x80, 0xba, 0x19, 0xae, 0x1d, 0xa9, 0x79, 0xf6, 0x3f, 0xac, 0x5d, 0x6f, 0x96, 0x1f, 0x2a, 0xce, 0x29, 0xb2, 0xff, 0x37, 0xf1, 0x94, 0x8f, 0x0c, 0xb5, 0x28, 0xba, 0x9a, 0x21, 0xf6, 0x66}} , + {{0x02, 0xfb, 0x54, 0xb8, 0x05, 0xf3, 0x81, 0x52, 0x69, 0x34, 0x46, 0x9d, 0x86, 0x76, 0x8f, 0xd7, 0xf8, 0x6a, 0x66, 0xff, 0xe6, 0xa7, 0x90, 0xf7, 0x5e, 0xcd, 0x6a, 0x9b, 0x55, 0xfc, 0x9d, 0x48}}}, +{{{0xbd, 0xaa, 0x13, 0xe6, 0xcd, 0x45, 0x4a, 0xa4, 0x59, 0x0a, 0x64, 0xb1, 0x98, 0xd6, 0x34, 0x13, 0x04, 0xe6, 0x97, 0x94, 0x06, 0xcb, 0xd4, 0x4e, 0xbb, 0x96, 0xcd, 0xd1, 0x57, 0xd1, 0xe3, 0x06}} , + {{0x7a, 0x6c, 0x45, 0x27, 0xc4, 0x93, 0x7f, 0x7d, 0x7c, 0x62, 0x50, 0x38, 0x3a, 0x6b, 0xb5, 0x88, 0xc6, 0xd9, 0xf1, 0x78, 0x19, 0xb9, 0x39, 0x93, 0x3d, 0xc9, 0xe0, 0x9c, 0x3c, 0xce, 0xf5, 0x72}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x24, 0xea, 0x23, 0x7d, 0x56, 0x2c, 0xe2, 0x59, 0x0e, 0x85, 0x60, 0x04, 0x88, 0x5a, 0x74, 0x1e, 0x4b, 0xef, 0x13, 0xda, 0x4c, 0xff, 0x83, 0x45, 0x85, 0x3f, 0x08, 0x95, 0x2c, 0x20, 0x13, 0x1f}} , + {{0x48, 0x5f, 0x27, 0x90, 0x5c, 0x02, 0x42, 0xad, 0x78, 0x47, 0x5c, 0xb5, 0x7e, 0x08, 0x85, 0x00, 0xfa, 0x7f, 0xfd, 0xfd, 0xe7, 0x09, 0x11, 0xf2, 0x7e, 0x1b, 0x38, 0x6c, 0x35, 0x6d, 0x33, 0x66}}}, +{{{0x93, 0x03, 0x36, 0x81, 0xac, 0xe4, 0x20, 0x09, 0x35, 0x4c, 0x45, 0xb2, 0x1e, 0x4c, 0x14, 0x21, 0xe6, 0xe9, 0x8a, 0x7b, 0x8d, 0xfe, 0x1e, 0xc6, 0x3e, 0xc1, 0x35, 0xfa, 0xe7, 0x70, 0x4e, 0x1d}} , + {{0x61, 0x2e, 0xc2, 0xdd, 0x95, 0x57, 0xd1, 0xab, 0x80, 0xe8, 0x63, 0x17, 0xb5, 0x48, 0xe4, 0x8a, 0x11, 0x9e, 0x72, 0xbe, 0x85, 0x8d, 0x51, 0x0a, 0xf2, 0x9f, 0xe0, 0x1c, 0xa9, 0x07, 0x28, 0x7b}}}, +{{{0xbb, 0x71, 0x14, 0x5e, 0x26, 0x8c, 0x3d, 0xc8, 0xe9, 0x7c, 0xd3, 0xd6, 0xd1, 0x2f, 0x07, 0x6d, 0xe6, 0xdf, 0xfb, 0x79, 0xd6, 0x99, 0x59, 0x96, 0x48, 0x40, 0x0f, 0x3a, 0x7b, 0xb2, 0xa0, 0x72}} , + {{0x4e, 0x3b, 0x69, 0xc8, 0x43, 0x75, 0x51, 0x6c, 0x79, 0x56, 0xe4, 0xcb, 0xf7, 0xa6, 0x51, 0xc2, 0x2c, 0x42, 0x0b, 0xd4, 0x82, 0x20, 0x1c, 0x01, 0x08, 0x66, 0xd7, 0xbf, 0x04, 0x56, 0xfc, 0x02}}}, +{{{0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2, 0xc9, 0x85, 0xe6, 0x98, 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95, 0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c}} , + {{0x6b, 0xa6, 0xf5, 0x4b, 0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90, 0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52, 0xe6, 0x99, 0x2c, 0x5f}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x85, 0xe0, 0x24, 0x32, 0xb4, 0xd1, 0xef, 0xfc, 0x69, 0xa2, 0xbf, 0x8f, 0x72, 0x2c, 0x95, 0xf6, 0xe4, 0x6e, 0x7d, 0x90, 0xf7, 0x57, 0x81, 0xa0, 0xf7, 0xda, 0xef, 0x33, 0x07, 0xe3, 0x6b, 0x78}} , + {{0x36, 0x27, 0x3e, 0xc6, 0x12, 0x07, 0xab, 0x4e, 0xbe, 0x69, 0x9d, 0xb3, 0xbe, 0x08, 0x7c, 0x2a, 0x47, 0x08, 0xfd, 0xd4, 0xcd, 0x0e, 0x27, 0x34, 0x5b, 0x98, 0x34, 0x2f, 0x77, 0x5f, 0x3a, 0x65}}}, +{{{0x13, 0xaa, 0x2e, 0x4c, 0xf0, 0x22, 0xb8, 0x6c, 0xb3, 0x19, 0x4d, 0xeb, 0x6b, 0xd0, 0xa4, 0xc6, 0x9c, 0xdd, 0xc8, 0x5b, 0x81, 0x57, 0x89, 0xdf, 0x33, 0xa9, 0x68, 0x49, 0x80, 0xe4, 0xfe, 0x21}} , + {{0x00, 0x17, 0x90, 0x30, 0xe9, 0xd3, 0x60, 0x30, 0x31, 0xc2, 0x72, 0x89, 0x7a, 0x36, 0xa5, 0xbd, 0x39, 0x83, 0x85, 0x50, 0xa1, 0x5d, 0x6c, 0x41, 0x1d, 0xb5, 0x2c, 0x07, 0x40, 0x77, 0x0b, 0x50}}}, +{{{0x64, 0x34, 0xec, 0xc0, 0x9e, 0x44, 0x41, 0xaf, 0xa0, 0x36, 0x05, 0x6d, 0xea, 0x30, 0x25, 0x46, 0x35, 0x24, 0x9d, 0x86, 0xbd, 0x95, 0xf1, 0x6a, 0x46, 0xd7, 0x94, 0x54, 0xf9, 0x3b, 0xbd, 0x5d}} , + {{0x77, 0x5b, 0xe2, 0x37, 0xc7, 0xe1, 0x7c, 0x13, 0x8c, 0x9f, 0x7b, 0x7b, 0x2a, 0xce, 0x42, 0xa3, 0xb9, 0x2a, 0x99, 0xa8, 0xc0, 0xd8, 0x3c, 0x86, 0xb0, 0xfb, 0xe9, 0x76, 0x77, 0xf7, 0xf5, 0x56}}}, +{{{0xdf, 0xb3, 0x46, 0x11, 0x6e, 0x13, 0xb7, 0x28, 0x4e, 0x56, 0xdd, 0xf1, 0xac, 0xad, 0x58, 0xc3, 0xf8, 0x88, 0x94, 0x5e, 0x06, 0x98, 0xa1, 0xe4, 0x6a, 0xfb, 0x0a, 0x49, 0x5d, 0x8a, 0xfe, 0x77}} , + {{0x46, 0x02, 0xf5, 0xa5, 0xaf, 0xc5, 0x75, 0x6d, 0xba, 0x45, 0x35, 0x0a, 0xfe, 0xc9, 0xac, 0x22, 0x91, 0x8d, 0x21, 0x95, 0x33, 0x03, 0xc0, 0x8a, 0x16, 0xf3, 0x39, 0xe0, 0x01, 0x0f, 0x53, 0x3c}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x34, 0x75, 0x37, 0x1f, 0x34, 0x4e, 0xa9, 0x1d, 0x68, 0x67, 0xf8, 0x49, 0x98, 0x96, 0xfc, 0x4c, 0x65, 0x97, 0xf7, 0x02, 0x4a, 0x52, 0x6c, 0x01, 0xbd, 0x48, 0xbb, 0x1b, 0xed, 0xa4, 0xe2, 0x53}} , + {{0x59, 0xd5, 0x9b, 0x5a, 0xa2, 0x90, 0xd3, 0xb8, 0x37, 0x4c, 0x55, 0x82, 0x28, 0x08, 0x0f, 0x7f, 0xaa, 0x81, 0x65, 0xe0, 0x0c, 0x52, 0xc9, 0xa3, 0x32, 0x27, 0x64, 0xda, 0xfd, 0x34, 0x23, 0x5a}}}, +{{{0xb5, 0xb0, 0x0c, 0x4d, 0xb3, 0x7b, 0x23, 0xc8, 0x1f, 0x8a, 0x39, 0x66, 0xe6, 0xba, 0x4c, 0x10, 0x37, 0xca, 0x9c, 0x7c, 0x05, 0x9e, 0xff, 0xc0, 0xf8, 0x8e, 0xb1, 0x8f, 0x6f, 0x67, 0x18, 0x26}} , + {{0x4b, 0x41, 0x13, 0x54, 0x23, 0x1a, 0xa4, 0x4e, 0xa9, 0x8b, 0x1e, 0x4b, 0xfc, 0x15, 0x24, 0xbb, 0x7e, 0xcb, 0xb6, 0x1e, 0x1b, 0xf5, 0xf2, 0xc8, 0x56, 0xec, 0x32, 0xa2, 0x60, 0x5b, 0xa0, 0x2a}}}, +{{{0xa4, 0x29, 0x47, 0x86, 0x2e, 0x92, 0x4f, 0x11, 0x4f, 0xf3, 0xb2, 0x5c, 0xd5, 0x3e, 0xa6, 0xb9, 0xc8, 0xe2, 0x33, 0x11, 0x1f, 0x01, 0x8f, 0xb0, 0x9b, 0xc7, 0xa5, 0xff, 0x83, 0x0f, 0x1e, 0x28}} , + {{0x1d, 0x29, 0x7a, 0xa1, 0xec, 0x8e, 0xb5, 0xad, 0xea, 0x02, 0x68, 0x60, 0x74, 0x29, 0x1c, 0xa5, 0xcf, 0xc8, 0x3b, 0x7d, 0x8b, 0x2b, 0x7c, 0xad, 0xa4, 0x40, 0x17, 0x51, 0x59, 0x7c, 0x2e, 0x5d}}}, +{{{0x0a, 0x6c, 0x4f, 0xbc, 0x3e, 0x32, 0xe7, 0x4a, 0x1a, 0x13, 0xc1, 0x49, 0x38, 0xbf, 0xf7, 0xc2, 0xd3, 0x8f, 0x6b, 0xad, 0x52, 0xf7, 0xcf, 0xbc, 0x27, 0xcb, 0x40, 0x67, 0x76, 0xcd, 0x6d, 0x56}} , + {{0xe5, 0xb0, 0x27, 0xad, 0xbe, 0x9b, 0xf2, 0xb5, 0x63, 0xde, 0x3a, 0x23, 0x95, 0xb7, 0x0a, 0x7e, 0xf3, 0x9e, 0x45, 0x6f, 0x19, 0x39, 0x75, 0x8f, 0x39, 0x3d, 0x0f, 0xc0, 0x9f, 0xf1, 0xe9, 0x51}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x88, 0xaa, 0x14, 0x24, 0x86, 0x94, 0x11, 0x12, 0x3e, 0x1a, 0xb5, 0xcc, 0xbb, 0xe0, 0x9c, 0xd5, 0x9c, 0x6d, 0xba, 0x58, 0x72, 0x8d, 0xfb, 0x22, 0x7b, 0x9f, 0x7c, 0x94, 0x30, 0xb3, 0x51, 0x21}} , + {{0xf6, 0x74, 0x3d, 0xf2, 0xaf, 0xd0, 0x1e, 0x03, 0x7c, 0x23, 0x6b, 0xc9, 0xfc, 0x25, 0x70, 0x90, 0xdc, 0x9a, 0xa4, 0xfb, 0x49, 0xfc, 0x3d, 0x0a, 0x35, 0x38, 0x6f, 0xe4, 0x7e, 0x50, 0x01, 0x2a}}}, +{{{0xd6, 0xe3, 0x96, 0x61, 0x3a, 0xfd, 0xef, 0x9b, 0x1f, 0x90, 0xa4, 0x24, 0x14, 0x5b, 0xc8, 0xde, 0x50, 0xb1, 0x1d, 0xaf, 0xe8, 0x55, 0x8a, 0x87, 0x0d, 0xfe, 0xaa, 0x3b, 0x82, 0x2c, 0x8d, 0x7b}} , + {{0x85, 0x0c, 0xaf, 0xf8, 0x83, 0x44, 0x49, 0xd9, 0x45, 0xcf, 0xf7, 0x48, 0xd9, 0x53, 0xb4, 0xf1, 0x65, 0xa0, 0xe1, 0xc3, 0xb3, 0x15, 0xed, 0x89, 0x9b, 0x4f, 0x62, 0xb3, 0x57, 0xa5, 0x45, 0x1c}}}, +{{{0x8f, 0x12, 0xea, 0xaf, 0xd1, 0x1f, 0x79, 0x10, 0x0b, 0xf6, 0xa3, 0x7b, 0xea, 0xac, 0x8b, 0x57, 0x32, 0x62, 0xe7, 0x06, 0x12, 0x51, 0xa0, 0x3b, 0x43, 0x5e, 0xa4, 0x20, 0x78, 0x31, 0xce, 0x0d}} , + {{0x84, 0x7c, 0xc2, 0xa6, 0x91, 0x23, 0xce, 0xbd, 0xdc, 0xf9, 0xce, 0xd5, 0x75, 0x30, 0x22, 0xe6, 0xf9, 0x43, 0x62, 0x0d, 0xf7, 0x75, 0x9d, 0x7f, 0x8c, 0xff, 0x7d, 0xe4, 0x72, 0xac, 0x9f, 0x1c}}}, +{{{0x88, 0xc1, 0x99, 0xd0, 0x3c, 0x1c, 0x5d, 0xb4, 0xef, 0x13, 0x0f, 0x90, 0xb9, 0x36, 0x2f, 0x95, 0x95, 0xc6, 0xdc, 0xde, 0x0a, 0x51, 0xe2, 0x8d, 0xf3, 0xbc, 0x51, 0xec, 0xdf, 0xb1, 0xa2, 0x5f}} , + {{0x2e, 0x68, 0xa1, 0x23, 0x7d, 0x9b, 0x40, 0x69, 0x85, 0x7b, 0x42, 0xbf, 0x90, 0x4b, 0xd6, 0x40, 0x2f, 0xd7, 0x52, 0x52, 0xb2, 0x21, 0xde, 0x64, 0xbd, 0x88, 0xc3, 0x6d, 0xa5, 0xfa, 0x81, 0x3f}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xfb, 0xfd, 0x47, 0x7b, 0x8a, 0x66, 0x9e, 0x79, 0x2e, 0x64, 0x82, 0xef, 0xf7, 0x21, 0xec, 0xf6, 0xd8, 0x86, 0x09, 0x31, 0x7c, 0xdd, 0x03, 0x6a, 0x58, 0xa0, 0x77, 0xb7, 0x9b, 0x8c, 0x87, 0x1f}} , + {{0x55, 0x47, 0xe4, 0xa8, 0x3d, 0x55, 0x21, 0x34, 0xab, 0x1d, 0xae, 0xe0, 0xf4, 0xea, 0xdb, 0xc5, 0xb9, 0x58, 0xbf, 0xc4, 0x2a, 0x89, 0x31, 0x1a, 0xf4, 0x2d, 0xe1, 0xca, 0x37, 0x99, 0x47, 0x59}}}, +{{{0xc7, 0xca, 0x63, 0xc1, 0x49, 0xa9, 0x35, 0x45, 0x55, 0x7e, 0xda, 0x64, 0x32, 0x07, 0x50, 0xf7, 0x32, 0xac, 0xde, 0x75, 0x58, 0x9b, 0x11, 0xb2, 0x3a, 0x1f, 0xf5, 0xf7, 0x79, 0x04, 0xe6, 0x08}} , + {{0x46, 0xfa, 0x22, 0x4b, 0xfa, 0xe1, 0xfe, 0x96, 0xfc, 0x67, 0xba, 0x67, 0x97, 0xc4, 0xe7, 0x1b, 0x86, 0x90, 0x5f, 0xee, 0xf4, 0x5b, 0x11, 0xb2, 0xcd, 0xad, 0xee, 0xc2, 0x48, 0x6c, 0x2b, 0x1b}}}, +{{{0xe3, 0x39, 0x62, 0xb4, 0x4f, 0x31, 0x04, 0xc9, 0xda, 0xd5, 0x73, 0x51, 0x57, 0xc5, 0xb8, 0xf3, 0xa3, 0x43, 0x70, 0xe4, 0x61, 0x81, 0x84, 0xe2, 0xbb, 0xbf, 0x4f, 0x9e, 0xa4, 0x5e, 0x74, 0x06}} , + {{0x29, 0xac, 0xff, 0x27, 0xe0, 0x59, 0xbe, 0x39, 0x9c, 0x0d, 0x83, 0xd7, 0x10, 0x0b, 0x15, 0xb7, 0xe1, 0xc2, 0x2c, 0x30, 0x73, 0x80, 0x3a, 0x7d, 0x5d, 0xab, 0x58, 0x6b, 0xc1, 0xf0, 0xf4, 0x22}}}, +{{{0xfe, 0x7f, 0xfb, 0x35, 0x7d, 0xc6, 0x01, 0x23, 0x28, 0xc4, 0x02, 0xac, 0x1f, 0x42, 0xb4, 0x9d, 0xfc, 0x00, 0x94, 0xa5, 0xee, 0xca, 0xda, 0x97, 0x09, 0x41, 0x77, 0x87, 0x5d, 0x7b, 0x87, 0x78}} , + {{0xf5, 0xfb, 0x90, 0x2d, 0x81, 0x19, 0x9e, 0x2f, 0x6d, 0x85, 0x88, 0x8c, 0x40, 0x5c, 0x77, 0x41, 0x4d, 0x01, 0x19, 0x76, 0x60, 0xe8, 0x4c, 0x48, 0xe4, 0x33, 0x83, 0x32, 0x6c, 0xb4, 0x41, 0x03}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xff, 0x10, 0xc2, 0x09, 0x4f, 0x6e, 0xf4, 0xd2, 0xdf, 0x7e, 0xca, 0x7b, 0x1c, 0x1d, 0xba, 0xa3, 0xb6, 0xda, 0x67, 0x33, 0xd4, 0x87, 0x36, 0x4b, 0x11, 0x20, 0x05, 0xa6, 0x29, 0xc1, 0x87, 0x17}} , + {{0xf6, 0x96, 0xca, 0x2f, 0xda, 0x38, 0xa7, 0x1b, 0xfc, 0xca, 0x7d, 0xfe, 0x08, 0x89, 0xe2, 0x47, 0x2b, 0x6a, 0x5d, 0x4b, 0xfa, 0xa1, 0xb4, 0xde, 0xb6, 0xc2, 0x31, 0x51, 0xf5, 0xe0, 0xa4, 0x0b}}}, +{{{0x5c, 0xe5, 0xc6, 0x04, 0x8e, 0x2b, 0x57, 0xbe, 0x38, 0x85, 0x23, 0xcb, 0xb7, 0xbe, 0x4f, 0xa9, 0xd3, 0x6e, 0x12, 0xaa, 0xd5, 0xb2, 0x2e, 0x93, 0x29, 0x9a, 0x4a, 0x88, 0x18, 0x43, 0xf5, 0x01}} , + {{0x50, 0xfc, 0xdb, 0xa2, 0x59, 0x21, 0x8d, 0xbd, 0x7e, 0x33, 0xae, 0x2f, 0x87, 0x1a, 0xd0, 0x97, 0xc7, 0x0d, 0x4d, 0x63, 0x01, 0xef, 0x05, 0x84, 0xec, 0x40, 0xdd, 0xa8, 0x0a, 0x4f, 0x70, 0x0b}}}, +{{{0x41, 0x69, 0x01, 0x67, 0x5c, 0xd3, 0x8a, 0xc5, 0xcf, 0x3f, 0xd1, 0x57, 0xd1, 0x67, 0x3e, 0x01, 0x39, 0xb5, 0xcb, 0x81, 0x56, 0x96, 0x26, 0xb6, 0xc2, 0xe7, 0x5c, 0xfb, 0x63, 0x97, 0x58, 0x06}} , + {{0x0c, 0x0e, 0xf3, 0xba, 0xf0, 0xe5, 0xba, 0xb2, 0x57, 0x77, 0xc6, 0x20, 0x9b, 0x89, 0x24, 0xbe, 0xf2, 0x9c, 0x8a, 0xba, 0x69, 0xc1, 0xf1, 0xb0, 0x4f, 0x2a, 0x05, 0x9a, 0xee, 0x10, 0x7e, 0x36}}}, +{{{0x3f, 0x26, 0xe9, 0x40, 0xe9, 0x03, 0xad, 0x06, 0x69, 0x91, 0xe0, 0xd1, 0x89, 0x60, 0x84, 0x79, 0xde, 0x27, 0x6d, 0xe6, 0x76, 0xbd, 0xea, 0xe6, 0xae, 0x48, 0xc3, 0x67, 0xc0, 0x57, 0xcd, 0x2f}} , + {{0x7f, 0xc1, 0xdc, 0xb9, 0xc7, 0xbc, 0x86, 0x3d, 0x55, 0x4b, 0x28, 0x7a, 0xfb, 0x4d, 0xc7, 0xf8, 0xbc, 0x67, 0x2a, 0x60, 0x4d, 0x8f, 0x07, 0x0b, 0x1a, 0x17, 0xbf, 0xfa, 0xac, 0xa7, 0x3d, 0x1a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x91, 0x3f, 0xed, 0x5e, 0x18, 0x78, 0x3f, 0x23, 0x2c, 0x0d, 0x8c, 0x44, 0x00, 0xe8, 0xfb, 0xe9, 0x8e, 0xd6, 0xd1, 0x36, 0x58, 0x57, 0x9e, 0xae, 0x4b, 0x5c, 0x0b, 0x07, 0xbc, 0x6b, 0x55, 0x2b}} , + {{0x6f, 0x4d, 0x17, 0xd7, 0xe1, 0x84, 0xd9, 0x78, 0xb1, 0x90, 0xfd, 0x2e, 0xb3, 0xb5, 0x19, 0x3f, 0x1b, 0xfa, 0xc0, 0x68, 0xb3, 0xdd, 0x00, 0x2e, 0x89, 0xbd, 0x7e, 0x80, 0x32, 0x13, 0xa0, 0x7b}}}, +{{{0x1a, 0x6f, 0x40, 0xaf, 0x44, 0x44, 0xb0, 0x43, 0x8f, 0x0d, 0xd0, 0x1e, 0xc4, 0x0b, 0x19, 0x5d, 0x8e, 0xfe, 0xc1, 0xf3, 0xc5, 0x5c, 0x91, 0xf8, 0x04, 0x4e, 0xbe, 0x90, 0xb4, 0x47, 0x5c, 0x3f}} , + {{0xb0, 0x3b, 0x2c, 0xf3, 0xfe, 0x32, 0x71, 0x07, 0x3f, 0xaa, 0xba, 0x45, 0x60, 0xa8, 0x8d, 0xea, 0x54, 0xcb, 0x39, 0x10, 0xb4, 0xf2, 0x8b, 0xd2, 0x14, 0x82, 0x42, 0x07, 0x8e, 0xe9, 0x7c, 0x53}}}, +{{{0xb0, 0xae, 0xc1, 0x8d, 0xc9, 0x8f, 0xb9, 0x7a, 0x77, 0xef, 0xba, 0x79, 0xa0, 0x3c, 0xa8, 0xf5, 0x6a, 0xe2, 0x3f, 0x5d, 0x00, 0xe3, 0x4b, 0x45, 0x24, 0x7b, 0x43, 0x78, 0x55, 0x1d, 0x2b, 0x1e}} , + {{0x01, 0xb8, 0xd6, 0x16, 0x67, 0xa0, 0x15, 0xb9, 0xe1, 0x58, 0xa4, 0xa7, 0x31, 0x37, 0x77, 0x2f, 0x8b, 0x12, 0x9f, 0xf4, 0x3f, 0xc7, 0x36, 0x66, 0xd2, 0xa8, 0x56, 0xf7, 0x7f, 0x74, 0xc6, 0x41}}}, +{{{0x5d, 0xf8, 0xb4, 0xa8, 0x30, 0xdd, 0xcc, 0x38, 0xa5, 0xd3, 0xca, 0xd8, 0xd1, 0xf8, 0xb2, 0x31, 0x91, 0xd4, 0x72, 0x05, 0x57, 0x4a, 0x3b, 0x82, 0x4a, 0xc6, 0x68, 0x20, 0xe2, 0x18, 0x41, 0x61}} , + {{0x19, 0xd4, 0x8d, 0x47, 0x29, 0x12, 0x65, 0xb0, 0x11, 0x78, 0x47, 0xb5, 0xcb, 0xa3, 0xa5, 0xfa, 0x05, 0x85, 0x54, 0xa9, 0x33, 0x97, 0x8d, 0x2b, 0xc2, 0xfe, 0x99, 0x35, 0x28, 0xe5, 0xeb, 0x63}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xb1, 0x3f, 0x3f, 0xef, 0xd8, 0xf4, 0xfc, 0xb3, 0xa0, 0x60, 0x50, 0x06, 0x2b, 0x29, 0x52, 0x70, 0x15, 0x0b, 0x24, 0x24, 0xf8, 0x5f, 0x79, 0x18, 0xcc, 0xff, 0x89, 0x99, 0x84, 0xa1, 0xae, 0x13}} , + {{0x44, 0x1f, 0xb8, 0xc2, 0x01, 0xc1, 0x30, 0x19, 0x55, 0x05, 0x60, 0x10, 0xa4, 0x6c, 0x2d, 0x67, 0x70, 0xe5, 0x25, 0x1b, 0xf2, 0xbf, 0xdd, 0xfb, 0x70, 0x2b, 0xa1, 0x8c, 0x9c, 0x94, 0x84, 0x08}}}, +{{{0xe7, 0xc4, 0x43, 0x4d, 0xc9, 0x2b, 0x69, 0x5d, 0x1d, 0x3c, 0xaf, 0xbb, 0x43, 0x38, 0x4e, 0x98, 0x3d, 0xed, 0x0d, 0x21, 0x03, 0xfd, 0xf0, 0x99, 0x47, 0x04, 0xb0, 0x98, 0x69, 0x55, 0x72, 0x0f}} , + {{0x5e, 0xdf, 0x15, 0x53, 0x3b, 0x86, 0x80, 0xb0, 0xf1, 0x70, 0x68, 0x8f, 0x66, 0x7c, 0x0e, 0x49, 0x1a, 0xd8, 0x6b, 0xfe, 0x4e, 0xef, 0xca, 0x47, 0xd4, 0x03, 0xc1, 0x37, 0x50, 0x9c, 0xc1, 0x16}}}, +{{{0xcd, 0x24, 0xc6, 0x3e, 0x0c, 0x82, 0x9b, 0x91, 0x2b, 0x61, 0x4a, 0xb2, 0x0f, 0x88, 0x55, 0x5f, 0x5a, 0x57, 0xff, 0xe5, 0x74, 0x0b, 0x13, 0x43, 0x00, 0xd8, 0x6b, 0xcf, 0xd2, 0x15, 0x03, 0x2c}} , + {{0xdc, 0xff, 0x15, 0x61, 0x2f, 0x4a, 0x2f, 0x62, 0xf2, 0x04, 0x2f, 0xb5, 0x0c, 0xb7, 0x1e, 0x3f, 0x74, 0x1a, 0x0f, 0xd7, 0xea, 0xcd, 0xd9, 0x7d, 0xf6, 0x12, 0x0e, 0x2f, 0xdb, 0x5a, 0x3b, 0x16}}}, +{{{0x1b, 0x37, 0x47, 0xe3, 0xf5, 0x9e, 0xea, 0x2c, 0x2a, 0xe7, 0x82, 0x36, 0xf4, 0x1f, 0x81, 0x47, 0x92, 0x4b, 0x69, 0x0e, 0x11, 0x8c, 0x5d, 0x53, 0x5b, 0x81, 0x27, 0x08, 0xbc, 0xa0, 0xae, 0x25}} , + {{0x69, 0x32, 0xa1, 0x05, 0x11, 0x42, 0x00, 0xd2, 0x59, 0xac, 0x4d, 0x62, 0x8b, 0x13, 0xe2, 0x50, 0x5d, 0xa0, 0x9d, 0x9b, 0xfd, 0xbb, 0x12, 0x41, 0x75, 0x41, 0x9e, 0xcc, 0xdc, 0xc7, 0xdc, 0x5d}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xd9, 0xe3, 0x38, 0x06, 0x46, 0x70, 0x82, 0x5e, 0x28, 0x49, 0x79, 0xff, 0x25, 0xd2, 0x4e, 0x29, 0x8d, 0x06, 0xb0, 0x23, 0xae, 0x9b, 0x66, 0xe4, 0x7d, 0xc0, 0x70, 0x91, 0xa3, 0xfc, 0xec, 0x4e}} , + {{0x62, 0x12, 0x37, 0x6a, 0x30, 0xf6, 0x1e, 0xfb, 0x14, 0x5c, 0x0d, 0x0e, 0xb7, 0x81, 0x6a, 0xe7, 0x08, 0x05, 0xac, 0xaa, 0x38, 0x46, 0xe2, 0x73, 0xea, 0x4b, 0x07, 0x81, 0x43, 0x7c, 0x9e, 0x5e}}}, +{{{0xfc, 0xf9, 0x21, 0x4f, 0x2e, 0x76, 0x9b, 0x1f, 0x28, 0x60, 0x77, 0x43, 0x32, 0x9d, 0xbe, 0x17, 0x30, 0x2a, 0xc6, 0x18, 0x92, 0x66, 0x62, 0x30, 0x98, 0x40, 0x11, 0xa6, 0x7f, 0x18, 0x84, 0x28}} , + {{0x3f, 0xab, 0xd3, 0xf4, 0x8a, 0x76, 0xa1, 0x3c, 0xca, 0x2d, 0x49, 0xc3, 0xea, 0x08, 0x0b, 0x85, 0x17, 0x2a, 0xc3, 0x6c, 0x08, 0xfd, 0x57, 0x9f, 0x3d, 0x5f, 0xdf, 0x67, 0x68, 0x42, 0x00, 0x32}}}, +{{{0x51, 0x60, 0x1b, 0x06, 0x4f, 0x8a, 0x21, 0xba, 0x38, 0xa8, 0xba, 0xd6, 0x40, 0xf6, 0xe9, 0x9b, 0x76, 0x4d, 0x56, 0x21, 0x5b, 0x0a, 0x9b, 0x2e, 0x4f, 0x3d, 0x81, 0x32, 0x08, 0x9f, 0x97, 0x5b}} , + {{0xe5, 0x44, 0xec, 0x06, 0x9d, 0x90, 0x79, 0x9f, 0xd3, 0xe0, 0x79, 0xaf, 0x8f, 0x10, 0xfd, 0xdd, 0x04, 0xae, 0x27, 0x97, 0x46, 0x33, 0x79, 0xea, 0xb8, 0x4e, 0xca, 0x5a, 0x59, 0x57, 0xe1, 0x0e}}}, +{{{0x1a, 0xda, 0xf3, 0xa5, 0x41, 0x43, 0x28, 0xfc, 0x7e, 0xe7, 0x71, 0xea, 0xc6, 0x3b, 0x59, 0xcc, 0x2e, 0xd3, 0x40, 0xec, 0xb3, 0x13, 0x6f, 0x44, 0xcd, 0x13, 0xb2, 0x37, 0xf2, 0x6e, 0xd9, 0x1c}} , + {{0xe3, 0xdb, 0x60, 0xcd, 0x5c, 0x4a, 0x18, 0x0f, 0xef, 0x73, 0x36, 0x71, 0x8c, 0xf6, 0x11, 0xb4, 0xd8, 0xce, 0x17, 0x5e, 0x4f, 0x26, 0x77, 0x97, 0x5f, 0xcb, 0xef, 0x91, 0xeb, 0x6a, 0x62, 0x7a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x18, 0x4a, 0xa2, 0x97, 0x08, 0x81, 0x2d, 0x83, 0xc4, 0xcc, 0xf0, 0x83, 0x7e, 0xec, 0x0d, 0x95, 0x4c, 0x5b, 0xfb, 0xfa, 0x98, 0x80, 0x4a, 0x66, 0x56, 0x0c, 0x51, 0xb3, 0xf2, 0x04, 0x5d, 0x27}} , + {{0x3b, 0xb9, 0xb8, 0x06, 0x5a, 0x2e, 0xfe, 0xc3, 0x82, 0x37, 0x9c, 0xa3, 0x11, 0x1f, 0x9c, 0xa6, 0xda, 0x63, 0x48, 0x9b, 0xad, 0xde, 0x2d, 0xa6, 0xbc, 0x6e, 0x32, 0xda, 0x27, 0x65, 0xdd, 0x57}}}, +{{{0x84, 0x4f, 0x37, 0x31, 0x7d, 0x2e, 0xbc, 0xad, 0x87, 0x07, 0x2a, 0x6b, 0x37, 0xfc, 0x5f, 0xeb, 0x4e, 0x75, 0x35, 0xa6, 0xde, 0xab, 0x0a, 0x19, 0x3a, 0xb7, 0xb1, 0xef, 0x92, 0x6a, 0x3b, 0x3c}} , + {{0x3b, 0xb2, 0x94, 0x6d, 0x39, 0x60, 0xac, 0xee, 0xe7, 0x81, 0x1a, 0x3b, 0x76, 0x87, 0x5c, 0x05, 0x94, 0x2a, 0x45, 0xb9, 0x80, 0xe9, 0x22, 0xb1, 0x07, 0xcb, 0x40, 0x9e, 0x70, 0x49, 0x6d, 0x12}}}, +{{{0xfd, 0x18, 0x78, 0x84, 0xa8, 0x4c, 0x7d, 0x6e, 0x59, 0xa6, 0xe5, 0x74, 0xf1, 0x19, 0xa6, 0x84, 0x2e, 0x51, 0xc1, 0x29, 0x13, 0xf2, 0x14, 0x6b, 0x5d, 0x53, 0x51, 0xf7, 0xef, 0xbf, 0x01, 0x22}} , + {{0xa4, 0x4b, 0x62, 0x4c, 0xe6, 0xfd, 0x72, 0x07, 0xf2, 0x81, 0xfc, 0xf2, 0xbd, 0x12, 0x7c, 0x68, 0x76, 0x2a, 0xba, 0xf5, 0x65, 0xb1, 0x1f, 0x17, 0x0a, 0x38, 0xb0, 0xbf, 0xc0, 0xf8, 0xf4, 0x2a}}}, +{{{0x55, 0x60, 0x55, 0x5b, 0xe4, 0x1d, 0x71, 0x4c, 0x9d, 0x5b, 0x9f, 0x70, 0xa6, 0x85, 0x9a, 0x2c, 0xa0, 0xe2, 0x32, 0x48, 0xce, 0x9e, 0x2a, 0xa5, 0x07, 0x3b, 0xc7, 0x6c, 0x86, 0x77, 0xde, 0x3c}} , + {{0xf7, 0x18, 0x7a, 0x96, 0x7e, 0x43, 0x57, 0xa9, 0x55, 0xfc, 0x4e, 0xb6, 0x72, 0x00, 0xf2, 0xe4, 0xd7, 0x52, 0xd3, 0xd3, 0xb6, 0x85, 0xf6, 0x71, 0xc7, 0x44, 0x3f, 0x7f, 0xd7, 0xb3, 0xf2, 0x79}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x46, 0xca, 0xa7, 0x55, 0x7b, 0x79, 0xf3, 0xca, 0x5a, 0x65, 0xf6, 0xed, 0x50, 0x14, 0x7b, 0xe4, 0xc4, 0x2a, 0x65, 0x9e, 0xe2, 0xf9, 0xca, 0xa7, 0x22, 0x26, 0x53, 0xcb, 0x21, 0x5b, 0xa7, 0x31}} , + {{0x90, 0xd7, 0xc5, 0x26, 0x08, 0xbd, 0xb0, 0x53, 0x63, 0x58, 0xc3, 0x31, 0x5e, 0x75, 0x46, 0x15, 0x91, 0xa6, 0xf8, 0x2f, 0x1a, 0x08, 0x65, 0x88, 0x2f, 0x98, 0x04, 0xf1, 0x7c, 0x6e, 0x00, 0x77}}}, +{{{0x81, 0x21, 0x61, 0x09, 0xf6, 0x4e, 0xf1, 0x92, 0xee, 0x63, 0x61, 0x73, 0x87, 0xc7, 0x54, 0x0e, 0x42, 0x4b, 0xc9, 0x47, 0xd1, 0xb8, 0x7e, 0x91, 0x75, 0x37, 0x99, 0x28, 0xb8, 0xdd, 0x7f, 0x50}} , + {{0x89, 0x8f, 0xc0, 0xbe, 0x5d, 0xd6, 0x9f, 0xa0, 0xf0, 0x9d, 0x81, 0xce, 0x3a, 0x7b, 0x98, 0x58, 0xbb, 0xd7, 0x78, 0xc8, 0x3f, 0x13, 0xf1, 0x74, 0x19, 0xdf, 0xf8, 0x98, 0x89, 0x5d, 0xfa, 0x5f}}}, +{{{0x9e, 0x35, 0x85, 0x94, 0x47, 0x1f, 0x90, 0x15, 0x26, 0xd0, 0x84, 0xed, 0x8a, 0x80, 0xf7, 0x63, 0x42, 0x86, 0x27, 0xd7, 0xf4, 0x75, 0x58, 0xdc, 0x9c, 0xc0, 0x22, 0x7e, 0x20, 0x35, 0xfd, 0x1f}} , + {{0x68, 0x0e, 0x6f, 0x97, 0xba, 0x70, 0xbb, 0xa3, 0x0e, 0xe5, 0x0b, 0x12, 0xf4, 0xa2, 0xdc, 0x47, 0xf8, 0xe6, 0xd0, 0x23, 0x6c, 0x33, 0xa8, 0x99, 0x46, 0x6e, 0x0f, 0x44, 0xba, 0x76, 0x48, 0x0f}}}, +{{{0xa3, 0x2a, 0x61, 0x37, 0xe2, 0x59, 0x12, 0x0e, 0x27, 0xba, 0x64, 0x43, 0xae, 0xc0, 0x42, 0x69, 0x79, 0xa4, 0x1e, 0x29, 0x8b, 0x15, 0xeb, 0xf8, 0xaf, 0xd4, 0xa2, 0x68, 0x33, 0xb5, 0x7a, 0x24}} , + {{0x2c, 0x19, 0x33, 0xdd, 0x1b, 0xab, 0xec, 0x01, 0xb0, 0x23, 0xf8, 0x42, 0x2b, 0x06, 0x88, 0xea, 0x3d, 0x2d, 0x00, 0x2a, 0x78, 0x45, 0x4d, 0x38, 0xed, 0x2e, 0x2e, 0x44, 0x49, 0xed, 0xcb, 0x33}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xa0, 0x68, 0xe8, 0x41, 0x8f, 0x91, 0xf8, 0x11, 0x13, 0x90, 0x2e, 0xa7, 0xab, 0x30, 0xef, 0xad, 0xa0, 0x61, 0x00, 0x88, 0xef, 0xdb, 0xce, 0x5b, 0x5c, 0xbb, 0x62, 0xc8, 0x56, 0xf9, 0x00, 0x73}} , + {{0x3f, 0x60, 0xc1, 0x82, 0x2d, 0xa3, 0x28, 0x58, 0x24, 0x9e, 0x9f, 0xe3, 0x70, 0xcc, 0x09, 0x4e, 0x1a, 0x3f, 0x11, 0x11, 0x15, 0x07, 0x3c, 0xa4, 0x41, 0xe0, 0x65, 0xa3, 0x0a, 0x41, 0x6d, 0x11}}}, +{{{0x31, 0x40, 0x01, 0x52, 0x56, 0x94, 0x5b, 0x28, 0x8a, 0xaa, 0x52, 0xee, 0xd8, 0x0a, 0x05, 0x8d, 0xcd, 0xb5, 0xaa, 0x2e, 0x38, 0xaa, 0xb7, 0x87, 0xf7, 0x2b, 0xfb, 0x04, 0xcb, 0x84, 0x3d, 0x54}} , + {{0x20, 0xef, 0x59, 0xde, 0xa4, 0x2b, 0x93, 0x6e, 0x2e, 0xec, 0x42, 0x9a, 0xd4, 0x2d, 0xf4, 0x46, 0x58, 0x27, 0x2b, 0x18, 0x8f, 0x83, 0x3d, 0x69, 0x9e, 0xd4, 0x3e, 0xb6, 0xc5, 0xfd, 0x58, 0x03}}}, +{{{0x33, 0x89, 0xc9, 0x63, 0x62, 0x1c, 0x17, 0xb4, 0x60, 0xc4, 0x26, 0x68, 0x09, 0xc3, 0x2e, 0x37, 0x0f, 0x7b, 0xb4, 0x9c, 0xb6, 0xf9, 0xfb, 0xd4, 0x51, 0x78, 0xc8, 0x63, 0xea, 0x77, 0x47, 0x07}} , + {{0x32, 0xb4, 0x18, 0x47, 0x79, 0xcb, 0xd4, 0x5a, 0x07, 0x14, 0x0f, 0xa0, 0xd5, 0xac, 0xd0, 0x41, 0x40, 0xab, 0x61, 0x23, 0xe5, 0x2a, 0x2a, 0x6f, 0xf7, 0xa8, 0xd4, 0x76, 0xef, 0xe7, 0x45, 0x6c}}}, +{{{0xa1, 0x5e, 0x60, 0x4f, 0xfb, 0xe1, 0x70, 0x6a, 0x1f, 0x55, 0x4f, 0x09, 0xb4, 0x95, 0x33, 0x36, 0xc6, 0x81, 0x01, 0x18, 0x06, 0x25, 0x27, 0xa4, 0xb4, 0x24, 0xa4, 0x86, 0x03, 0x4c, 0xac, 0x02}} , + {{0x77, 0x38, 0xde, 0xd7, 0x60, 0x48, 0x07, 0xf0, 0x74, 0xa8, 0xff, 0x54, 0xe5, 0x30, 0x43, 0xff, 0x77, 0xfb, 0x21, 0x07, 0xff, 0xb2, 0x07, 0x6b, 0xe4, 0xe5, 0x30, 0xfc, 0x19, 0x6c, 0xa3, 0x01}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x13, 0xc5, 0x2c, 0xac, 0xd3, 0x83, 0x82, 0x7c, 0x29, 0xf7, 0x05, 0xa5, 0x00, 0xb6, 0x1f, 0x86, 0x55, 0xf4, 0xd6, 0x2f, 0x0c, 0x99, 0xd0, 0x65, 0x9b, 0x6b, 0x46, 0x0d, 0x43, 0xf8, 0x16, 0x28}} , + {{0x1e, 0x7f, 0xb4, 0x74, 0x7e, 0xb1, 0x89, 0x4f, 0x18, 0x5a, 0xab, 0x64, 0x06, 0xdf, 0x45, 0x87, 0xe0, 0x6a, 0xc6, 0xf0, 0x0e, 0xc9, 0x24, 0x35, 0x38, 0xea, 0x30, 0x54, 0xb4, 0xc4, 0x52, 0x54}}}, +{{{0xe9, 0x9f, 0xdc, 0x3f, 0xc1, 0x89, 0x44, 0x74, 0x27, 0xe4, 0xc1, 0x90, 0xff, 0x4a, 0xa7, 0x3c, 0xee, 0xcd, 0xf4, 0x1d, 0x25, 0x94, 0x7f, 0x63, 0x16, 0x48, 0xbc, 0x64, 0xfe, 0x95, 0xc4, 0x0c}} , + {{0x8b, 0x19, 0x75, 0x6e, 0x03, 0x06, 0x5e, 0x6a, 0x6f, 0x1a, 0x8c, 0xe3, 0xd3, 0x28, 0xf2, 0xe0, 0xb9, 0x7a, 0x43, 0x69, 0xe6, 0xd3, 0xc0, 0xfe, 0x7e, 0x97, 0xab, 0x6c, 0x7b, 0x8e, 0x13, 0x42}}}, +{{{0xd4, 0xca, 0x70, 0x3d, 0xab, 0xfb, 0x5f, 0x5e, 0x00, 0x0c, 0xcc, 0x77, 0x22, 0xf8, 0x78, 0x55, 0xae, 0x62, 0x35, 0xfb, 0x9a, 0xc6, 0x03, 0xe4, 0x0c, 0xee, 0xab, 0xc7, 0xc0, 0x89, 0x87, 0x54}} , + {{0x32, 0xad, 0xae, 0x85, 0x58, 0x43, 0xb8, 0xb1, 0xe6, 0x3e, 0x00, 0x9c, 0x78, 0x88, 0x56, 0xdb, 0x9c, 0xfc, 0x79, 0xf6, 0xf9, 0x41, 0x5f, 0xb7, 0xbc, 0x11, 0xf9, 0x20, 0x36, 0x1c, 0x53, 0x2b}}}, +{{{0x5a, 0x20, 0x5b, 0xa1, 0xa5, 0x44, 0x91, 0x24, 0x02, 0x63, 0x12, 0x64, 0xb8, 0x55, 0xf6, 0xde, 0x2c, 0xdb, 0x47, 0xb8, 0xc6, 0x0a, 0xc3, 0x00, 0x78, 0x93, 0xd8, 0xf5, 0xf5, 0x18, 0x28, 0x0a}} , + {{0xd6, 0x1b, 0x9a, 0x6c, 0xe5, 0x46, 0xea, 0x70, 0x96, 0x8d, 0x4e, 0x2a, 0x52, 0x21, 0x26, 0x4b, 0xb1, 0xbb, 0x0f, 0x7c, 0xa9, 0x9b, 0x04, 0xbb, 0x51, 0x08, 0xf1, 0x9a, 0xa4, 0x76, 0x7c, 0x18}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xfa, 0x94, 0xf7, 0x40, 0xd0, 0xd7, 0xeb, 0xa9, 0x82, 0x36, 0xd5, 0x15, 0xb9, 0x33, 0x7a, 0xbf, 0x8a, 0xf2, 0x63, 0xaa, 0x37, 0xf5, 0x59, 0xac, 0xbd, 0xbb, 0x32, 0x36, 0xbe, 0x73, 0x99, 0x38}} , + {{0x2c, 0xb3, 0xda, 0x7a, 0xd8, 0x3d, 0x99, 0xca, 0xd2, 0xf4, 0xda, 0x99, 0x8e, 0x4f, 0x98, 0xb7, 0xf4, 0xae, 0x3e, 0x9f, 0x8e, 0x35, 0x60, 0xa4, 0x33, 0x75, 0xa4, 0x04, 0x93, 0xb1, 0x6b, 0x4d}}}, +{{{0x97, 0x9d, 0xa8, 0xcd, 0x97, 0x7b, 0x9d, 0xb9, 0xe7, 0xa5, 0xef, 0xfd, 0xa8, 0x42, 0x6b, 0xc3, 0x62, 0x64, 0x7d, 0xa5, 0x1b, 0xc9, 0x9e, 0xd2, 0x45, 0xb9, 0xee, 0x03, 0xb0, 0xbf, 0xc0, 0x68}} , + {{0xed, 0xb7, 0x84, 0x2c, 0xf6, 0xd3, 0xa1, 0x6b, 0x24, 0x6d, 0x87, 0x56, 0x97, 0x59, 0x79, 0x62, 0x9f, 0xac, 0xed, 0xf3, 0xc9, 0x89, 0x21, 0x2e, 0x04, 0xb3, 0xcc, 0x2f, 0xbe, 0xd6, 0x0a, 0x4b}}}, +{{{0x39, 0x61, 0x05, 0xed, 0x25, 0x89, 0x8b, 0x5d, 0x1b, 0xcb, 0x0c, 0x55, 0xf4, 0x6a, 0x00, 0x8a, 0x46, 0xe8, 0x1e, 0xc6, 0x83, 0xc8, 0x5a, 0x76, 0xdb, 0xcc, 0x19, 0x7a, 0xcc, 0x67, 0x46, 0x0b}} , + {{0x53, 0xcf, 0xc2, 0xa1, 0xad, 0x6a, 0xf3, 0xcd, 0x8f, 0xc9, 0xde, 0x1c, 0xf8, 0x6c, 0x8f, 0xf8, 0x76, 0x42, 0xe7, 0xfe, 0xb2, 0x72, 0x21, 0x0a, 0x66, 0x74, 0x8f, 0xb7, 0xeb, 0xe4, 0x6f, 0x01}}}, +{{{0x22, 0x8c, 0x6b, 0xbe, 0xfc, 0x4d, 0x70, 0x62, 0x6e, 0x52, 0x77, 0x99, 0x88, 0x7e, 0x7b, 0x57, 0x7a, 0x0d, 0xfe, 0xdc, 0x72, 0x92, 0xf1, 0x68, 0x1d, 0x97, 0xd7, 0x7c, 0x8d, 0x53, 0x10, 0x37}} , + {{0x53, 0x88, 0x77, 0x02, 0xca, 0x27, 0xa8, 0xe5, 0x45, 0xe2, 0xa8, 0x48, 0x2a, 0xab, 0x18, 0xca, 0xea, 0x2d, 0x2a, 0x54, 0x17, 0x37, 0x32, 0x09, 0xdc, 0xe0, 0x4a, 0xb7, 0x7d, 0x82, 0x10, 0x7d}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x8a, 0x64, 0x1e, 0x14, 0x0a, 0x57, 0xd4, 0xda, 0x5c, 0x96, 0x9b, 0x01, 0x4c, 0x67, 0xbf, 0x8b, 0x30, 0xfe, 0x08, 0xdb, 0x0d, 0xd5, 0xa8, 0xd7, 0x09, 0x11, 0x85, 0xa2, 0xd3, 0x45, 0xfb, 0x7e}} , + {{0xda, 0x8c, 0xc2, 0xd0, 0xac, 0x18, 0xe8, 0x52, 0x36, 0xd4, 0x21, 0xa3, 0xdd, 0x57, 0x22, 0x79, 0xb7, 0xf8, 0x71, 0x9d, 0xc6, 0x91, 0x70, 0x86, 0x56, 0xbf, 0xa1, 0x11, 0x8b, 0x19, 0xe1, 0x0f}}}, +{{{0x18, 0x32, 0x98, 0x2c, 0x8f, 0x91, 0xae, 0x12, 0xf0, 0x8c, 0xea, 0xf3, 0x3c, 0xb9, 0x5d, 0xe4, 0x69, 0xed, 0xb2, 0x47, 0x18, 0xbd, 0xce, 0x16, 0x52, 0x5c, 0x23, 0xe2, 0xa5, 0x25, 0x52, 0x5d}} , + {{0xb9, 0xb1, 0xe7, 0x5d, 0x4e, 0xbc, 0xee, 0xbb, 0x40, 0x81, 0x77, 0x82, 0x19, 0xab, 0xb5, 0xc6, 0xee, 0xab, 0x5b, 0x6b, 0x63, 0x92, 0x8a, 0x34, 0x8d, 0xcd, 0xee, 0x4f, 0x49, 0xe5, 0xc9, 0x7e}}}, +{{{0x21, 0xac, 0x8b, 0x22, 0xcd, 0xc3, 0x9a, 0xe9, 0x5e, 0x78, 0xbd, 0xde, 0xba, 0xad, 0xab, 0xbf, 0x75, 0x41, 0x09, 0xc5, 0x58, 0xa4, 0x7d, 0x92, 0xb0, 0x7f, 0xf2, 0xa1, 0xd1, 0xc0, 0xb3, 0x6d}} , + {{0x62, 0x4f, 0xd0, 0x75, 0x77, 0xba, 0x76, 0x77, 0xd7, 0xb8, 0xd8, 0x92, 0x6f, 0x98, 0x34, 0x3d, 0xd6, 0x4e, 0x1c, 0x0f, 0xf0, 0x8f, 0x2e, 0xf1, 0xb3, 0xbd, 0xb1, 0xb9, 0xec, 0x99, 0xb4, 0x07}}}, +{{{0x60, 0x57, 0x2e, 0x9a, 0x72, 0x1d, 0x6b, 0x6e, 0x58, 0x33, 0x24, 0x8c, 0x48, 0x39, 0x46, 0x8e, 0x89, 0x6a, 0x88, 0x51, 0x23, 0x62, 0xb5, 0x32, 0x09, 0x36, 0xe3, 0x57, 0xf5, 0x98, 0xde, 0x6f}} , + {{0x8b, 0x2c, 0x00, 0x48, 0x4a, 0xf9, 0x5b, 0x87, 0x69, 0x52, 0xe5, 0x5b, 0xd1, 0xb1, 0xe5, 0x25, 0x25, 0xe0, 0x9c, 0xc2, 0x13, 0x44, 0xe8, 0xb9, 0x0a, 0x70, 0xad, 0xbd, 0x0f, 0x51, 0x94, 0x69}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xa2, 0xdc, 0xab, 0xa9, 0x25, 0x2d, 0xac, 0x5f, 0x03, 0x33, 0x08, 0xe7, 0x7e, 0xfe, 0x95, 0x36, 0x3c, 0x5b, 0x3a, 0xd3, 0x05, 0x82, 0x1c, 0x95, 0x2d, 0xd8, 0x77, 0x7e, 0x02, 0xd9, 0x5b, 0x70}} , + {{0xc2, 0xfe, 0x1b, 0x0c, 0x67, 0xcd, 0xd6, 0xe0, 0x51, 0x8e, 0x2c, 0xe0, 0x79, 0x88, 0xf0, 0xcf, 0x41, 0x4a, 0xad, 0x23, 0xd4, 0x46, 0xca, 0x94, 0xa1, 0xc3, 0xeb, 0x28, 0x06, 0xfa, 0x17, 0x14}}}, +{{{0x7b, 0xaa, 0x70, 0x0a, 0x4b, 0xfb, 0xf5, 0xbf, 0x80, 0xc5, 0xcf, 0x08, 0x7a, 0xdd, 0xa1, 0xf4, 0x9d, 0x54, 0x50, 0x53, 0x23, 0x77, 0x23, 0xf5, 0x34, 0xa5, 0x22, 0xd1, 0x0d, 0x96, 0x2e, 0x47}} , + {{0xcc, 0xb7, 0x32, 0x89, 0x57, 0xd0, 0x98, 0x75, 0xe4, 0x37, 0x99, 0xa9, 0xe8, 0xba, 0xed, 0xba, 0xeb, 0xc7, 0x4f, 0x15, 0x76, 0x07, 0x0c, 0x4c, 0xef, 0x9f, 0x52, 0xfc, 0x04, 0x5d, 0x58, 0x10}}}, +{{{0xce, 0x82, 0xf0, 0x8f, 0x79, 0x02, 0xa8, 0xd1, 0xda, 0x14, 0x09, 0x48, 0xee, 0x8a, 0x40, 0x98, 0x76, 0x60, 0x54, 0x5a, 0xde, 0x03, 0x24, 0xf5, 0xe6, 0x2f, 0xe1, 0x03, 0xbf, 0x68, 0x82, 0x7f}} , + {{0x64, 0xe9, 0x28, 0xc7, 0xa4, 0xcf, 0x2a, 0xf9, 0x90, 0x64, 0x72, 0x2c, 0x8b, 0xeb, 0xec, 0xa0, 0xf2, 0x7d, 0x35, 0xb5, 0x90, 0x4d, 0x7f, 0x5b, 0x4a, 0x49, 0xe4, 0xb8, 0x3b, 0xc8, 0xa1, 0x2f}}}, +{{{0x8b, 0xc5, 0xcc, 0x3d, 0x69, 0xa6, 0xa1, 0x18, 0x44, 0xbc, 0x4d, 0x77, 0x37, 0xc7, 0x86, 0xec, 0x0c, 0xc9, 0xd6, 0x44, 0xa9, 0x23, 0x27, 0xb9, 0x03, 0x34, 0xa7, 0x0a, 0xd5, 0xc7, 0x34, 0x37}} , + {{0xf9, 0x7e, 0x3e, 0x66, 0xee, 0xf9, 0x99, 0x28, 0xff, 0xad, 0x11, 0xd8, 0xe2, 0x66, 0xc5, 0xcd, 0x0f, 0x0d, 0x0b, 0x6a, 0xfc, 0x7c, 0x24, 0xa8, 0x4f, 0xa8, 0x5e, 0x80, 0x45, 0x8b, 0x6c, 0x41}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xef, 0x1e, 0xec, 0xf7, 0x8d, 0x77, 0xf2, 0xea, 0xdb, 0x60, 0x03, 0x21, 0xc0, 0xff, 0x5e, 0x67, 0xc3, 0x71, 0x0b, 0x21, 0xb4, 0x41, 0xa0, 0x68, 0x38, 0xc6, 0x01, 0xa3, 0xd3, 0x51, 0x3c, 0x3c}} , + {{0x92, 0xf8, 0xd6, 0x4b, 0xef, 0x42, 0x13, 0xb2, 0x4a, 0xc4, 0x2e, 0x72, 0x3f, 0xc9, 0x11, 0xbd, 0x74, 0x02, 0x0e, 0xf5, 0x13, 0x9d, 0x83, 0x1a, 0x1b, 0xd5, 0x54, 0xde, 0xc4, 0x1e, 0x16, 0x6c}}}, +{{{0x27, 0x52, 0xe4, 0x63, 0xaa, 0x94, 0xe6, 0xc3, 0x28, 0x9c, 0xc6, 0x56, 0xac, 0xfa, 0xb6, 0xbd, 0xe2, 0xcc, 0x76, 0xc6, 0x27, 0x27, 0xa2, 0x8e, 0x78, 0x2b, 0x84, 0x72, 0x10, 0xbd, 0x4e, 0x2a}} , + {{0xea, 0xa7, 0x23, 0xef, 0x04, 0x61, 0x80, 0x50, 0xc9, 0x6e, 0xa5, 0x96, 0xd1, 0xd1, 0xc8, 0xc3, 0x18, 0xd7, 0x2d, 0xfd, 0x26, 0xbd, 0xcb, 0x7b, 0x92, 0x51, 0x0e, 0x4a, 0x65, 0x57, 0xb8, 0x49}}}, +{{{0xab, 0x55, 0x36, 0xc3, 0xec, 0x63, 0x55, 0x11, 0x55, 0xf6, 0xa5, 0xc7, 0x01, 0x5f, 0xfe, 0x79, 0xd8, 0x0a, 0xf7, 0x03, 0xd8, 0x98, 0x99, 0xf5, 0xd0, 0x00, 0x54, 0x6b, 0x66, 0x28, 0xf5, 0x25}} , + {{0x7a, 0x8d, 0xa1, 0x5d, 0x70, 0x5d, 0x51, 0x27, 0xee, 0x30, 0x65, 0x56, 0x95, 0x46, 0xde, 0xbd, 0x03, 0x75, 0xb4, 0x57, 0x59, 0x89, 0xeb, 0x02, 0x9e, 0xcc, 0x89, 0x19, 0xa7, 0xcb, 0x17, 0x67}}}, +{{{0x6a, 0xeb, 0xfc, 0x9a, 0x9a, 0x10, 0xce, 0xdb, 0x3a, 0x1c, 0x3c, 0x6a, 0x9d, 0xea, 0x46, 0xbc, 0x45, 0x49, 0xac, 0xe3, 0x41, 0x12, 0x7c, 0xf0, 0xf7, 0x4f, 0xf9, 0xf7, 0xff, 0x2c, 0x89, 0x04}} , + {{0x30, 0x31, 0x54, 0x1a, 0x46, 0xca, 0xe6, 0xc6, 0xcb, 0xe2, 0xc3, 0xc1, 0x8b, 0x75, 0x81, 0xbe, 0xee, 0xf8, 0xa3, 0x11, 0x1c, 0x25, 0xa3, 0xa7, 0x35, 0x51, 0x55, 0xe2, 0x25, 0xaa, 0xe2, 0x3a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xb4, 0x48, 0x10, 0x9f, 0x8a, 0x09, 0x76, 0xfa, 0xf0, 0x7a, 0xb0, 0x70, 0xf7, 0x83, 0x80, 0x52, 0x84, 0x2b, 0x26, 0xa2, 0xc4, 0x5d, 0x4f, 0xba, 0xb1, 0xc8, 0x40, 0x0d, 0x78, 0x97, 0xc4, 0x60}} , + {{0xd4, 0xb1, 0x6c, 0x08, 0xc7, 0x40, 0x38, 0x73, 0x5f, 0x0b, 0xf3, 0x76, 0x5d, 0xb2, 0xa5, 0x2f, 0x57, 0x57, 0x07, 0xed, 0x08, 0xa2, 0x6c, 0x4f, 0x08, 0x02, 0xb5, 0x0e, 0xee, 0x44, 0xfa, 0x22}}}, +{{{0x0f, 0x00, 0x3f, 0xa6, 0x04, 0x19, 0x56, 0x65, 0x31, 0x7f, 0x8b, 0xeb, 0x0d, 0xe1, 0x47, 0x89, 0x97, 0x16, 0x53, 0xfa, 0x81, 0xa7, 0xaa, 0xb2, 0xbf, 0x67, 0xeb, 0x72, 0x60, 0x81, 0x0d, 0x48}} , + {{0x7e, 0x13, 0x33, 0xcd, 0xa8, 0x84, 0x56, 0x1e, 0x67, 0xaf, 0x6b, 0x43, 0xac, 0x17, 0xaf, 0x16, 0xc0, 0x52, 0x99, 0x49, 0x5b, 0x87, 0x73, 0x7e, 0xb5, 0x43, 0xda, 0x6b, 0x1d, 0x0f, 0x2d, 0x55}}}, +{{{0xe9, 0x58, 0x1f, 0xff, 0x84, 0x3f, 0x93, 0x1c, 0xcb, 0xe1, 0x30, 0x69, 0xa5, 0x75, 0x19, 0x7e, 0x14, 0x5f, 0xf8, 0xfc, 0x09, 0xdd, 0xa8, 0x78, 0x9d, 0xca, 0x59, 0x8b, 0xd1, 0x30, 0x01, 0x13}} , + {{0xff, 0x76, 0x03, 0xc5, 0x4b, 0x89, 0x99, 0x70, 0x00, 0x59, 0x70, 0x9c, 0xd5, 0xd9, 0x11, 0x89, 0x5a, 0x46, 0xfe, 0xef, 0xdc, 0xd9, 0x55, 0x2b, 0x45, 0xa7, 0xb0, 0x2d, 0xfb, 0x24, 0xc2, 0x29}}}, +{{{0x38, 0x06, 0xf8, 0x0b, 0xac, 0x82, 0xc4, 0x97, 0x2b, 0x90, 0xe0, 0xf7, 0xa8, 0xab, 0x6c, 0x08, 0x80, 0x66, 0x90, 0x46, 0xf7, 0x26, 0x2d, 0xf8, 0xf1, 0xc4, 0x6b, 0x4a, 0x82, 0x98, 0x8e, 0x37}} , + {{0x8e, 0xb4, 0xee, 0xb8, 0xd4, 0x3f, 0xb2, 0x1b, 0xe0, 0x0a, 0x3d, 0x75, 0x34, 0x28, 0xa2, 0x8e, 0xc4, 0x92, 0x7b, 0xfe, 0x60, 0x6e, 0x6d, 0xb8, 0x31, 0x1d, 0x62, 0x0d, 0x78, 0x14, 0x42, 0x11}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x5e, 0xa8, 0xd8, 0x04, 0x9b, 0x73, 0xc9, 0xc9, 0xdc, 0x0d, 0x73, 0xbf, 0x0a, 0x0a, 0x73, 0xff, 0x18, 0x1f, 0x9c, 0x51, 0xaa, 0xc6, 0xf1, 0x83, 0x25, 0xfd, 0xab, 0xa3, 0x11, 0xd3, 0x01, 0x24}} , + {{0x4d, 0xe3, 0x7e, 0x38, 0x62, 0x5e, 0x64, 0xbb, 0x2b, 0x53, 0xb5, 0x03, 0x68, 0xc4, 0xf2, 0x2b, 0x5a, 0x03, 0x32, 0x99, 0x4a, 0x41, 0x9a, 0xe1, 0x1a, 0xae, 0x8c, 0x48, 0xf3, 0x24, 0x32, 0x65}}}, +{{{0xe8, 0xdd, 0xad, 0x3a, 0x8c, 0xea, 0xf4, 0xb3, 0xb2, 0xe5, 0x73, 0xf2, 0xed, 0x8b, 0xbf, 0xed, 0xb1, 0x0c, 0x0c, 0xfb, 0x2b, 0xf1, 0x01, 0x48, 0xe8, 0x26, 0x03, 0x8e, 0x27, 0x4d, 0x96, 0x72}} , + {{0xc8, 0x09, 0x3b, 0x60, 0xc9, 0x26, 0x4d, 0x7c, 0xf2, 0x9c, 0xd4, 0xa1, 0x3b, 0x26, 0xc2, 0x04, 0x33, 0x44, 0x76, 0x3c, 0x02, 0xbb, 0x11, 0x42, 0x0c, 0x22, 0xb7, 0xc6, 0xe1, 0xac, 0xb4, 0x0e}}}, +{{{0x6f, 0x85, 0xe7, 0xef, 0xde, 0x67, 0x30, 0xfc, 0xbf, 0x5a, 0xe0, 0x7b, 0x7a, 0x2a, 0x54, 0x6b, 0x5d, 0x62, 0x85, 0xa1, 0xf8, 0x16, 0x88, 0xec, 0x61, 0xb9, 0x96, 0xb5, 0xef, 0x2d, 0x43, 0x4d}} , + {{0x7c, 0x31, 0x33, 0xcc, 0xe4, 0xcf, 0x6c, 0xff, 0x80, 0x47, 0x77, 0xd1, 0xd8, 0xe9, 0x69, 0x97, 0x98, 0x7f, 0x20, 0x57, 0x1d, 0x1d, 0x4f, 0x08, 0x27, 0xc8, 0x35, 0x57, 0x40, 0xc6, 0x21, 0x0c}}}, +{{{0xd2, 0x8e, 0x9b, 0xfa, 0x42, 0x8e, 0xdf, 0x8f, 0xc7, 0x86, 0xf9, 0xa4, 0xca, 0x70, 0x00, 0x9d, 0x21, 0xbf, 0xec, 0x57, 0x62, 0x30, 0x58, 0x8c, 0x0d, 0x35, 0xdb, 0x5d, 0x8b, 0x6a, 0xa0, 0x5a}} , + {{0xc1, 0x58, 0x7c, 0x0d, 0x20, 0xdd, 0x11, 0x26, 0x5f, 0x89, 0x3b, 0x97, 0x58, 0xf8, 0x8b, 0xe3, 0xdf, 0x32, 0xe2, 0xfc, 0xd8, 0x67, 0xf2, 0xa5, 0x37, 0x1e, 0x6d, 0xec, 0x7c, 0x27, 0x20, 0x79}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xd0, 0xe9, 0xc0, 0xfa, 0x95, 0x45, 0x23, 0x96, 0xf1, 0x2c, 0x79, 0x25, 0x14, 0xce, 0x40, 0x14, 0x44, 0x2c, 0x36, 0x50, 0xd9, 0x63, 0x56, 0xb7, 0x56, 0x3b, 0x9e, 0xa7, 0xef, 0x89, 0xbb, 0x0e}} , + {{0xce, 0x7f, 0xdc, 0x0a, 0xcc, 0x82, 0x1c, 0x0a, 0x78, 0x71, 0xe8, 0x74, 0x8d, 0x01, 0x30, 0x0f, 0xa7, 0x11, 0x4c, 0xdf, 0x38, 0xd7, 0xa7, 0x0d, 0xf8, 0x48, 0x52, 0x00, 0x80, 0x7b, 0x5f, 0x0e}}}, +{{{0x25, 0x83, 0xe6, 0x94, 0x7b, 0x81, 0xb2, 0x91, 0xae, 0x0e, 0x05, 0xc9, 0xa3, 0x68, 0x2d, 0xd9, 0x88, 0x25, 0x19, 0x2a, 0x61, 0x61, 0x21, 0x97, 0x15, 0xa1, 0x35, 0xa5, 0x46, 0xc8, 0xa2, 0x0e}} , + {{0x1b, 0x03, 0x0d, 0x8b, 0x5a, 0x1b, 0x97, 0x4b, 0xf2, 0x16, 0x31, 0x3d, 0x1f, 0x33, 0xa0, 0x50, 0x3a, 0x18, 0xbe, 0x13, 0xa1, 0x76, 0xc1, 0xba, 0x1b, 0xf1, 0x05, 0x7b, 0x33, 0xa8, 0x82, 0x3b}}}, +{{{0xba, 0x36, 0x7b, 0x6d, 0xa9, 0xea, 0x14, 0x12, 0xc5, 0xfa, 0x91, 0x00, 0xba, 0x9b, 0x99, 0xcc, 0x56, 0x02, 0xe9, 0xa0, 0x26, 0x40, 0x66, 0x8c, 0xc4, 0xf8, 0x85, 0x33, 0x68, 0xe7, 0x03, 0x20}} , + {{0x50, 0x5b, 0xff, 0xa9, 0xb2, 0xf1, 0xf1, 0x78, 0xcf, 0x14, 0xa4, 0xa9, 0xfc, 0x09, 0x46, 0x94, 0x54, 0x65, 0x0d, 0x9c, 0x5f, 0x72, 0x21, 0xe2, 0x97, 0xa5, 0x2d, 0x81, 0xce, 0x4a, 0x5f, 0x79}}}, +{{{0x3d, 0x5f, 0x5c, 0xd2, 0xbc, 0x7d, 0x77, 0x0e, 0x2a, 0x6d, 0x22, 0x45, 0x84, 0x06, 0xc4, 0xdd, 0xc6, 0xa6, 0xc6, 0xd7, 0x49, 0xad, 0x6d, 0x87, 0x91, 0x0e, 0x3a, 0x67, 0x1d, 0x2c, 0x1d, 0x56}} , + {{0xfe, 0x7a, 0x74, 0xcf, 0xd4, 0xd2, 0xe5, 0x19, 0xde, 0xd0, 0xdb, 0x70, 0x23, 0x69, 0xe6, 0x6d, 0xec, 0xec, 0xcc, 0x09, 0x33, 0x6a, 0x77, 0xdc, 0x6b, 0x22, 0x76, 0x5d, 0x92, 0x09, 0xac, 0x2d}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x23, 0x15, 0x17, 0xeb, 0xd3, 0xdb, 0x12, 0x5e, 0x01, 0xf0, 0x91, 0xab, 0x2c, 0x41, 0xce, 0xac, 0xed, 0x1b, 0x4b, 0x2d, 0xbc, 0xdb, 0x17, 0x66, 0x89, 0x46, 0xad, 0x4b, 0x1e, 0x6f, 0x0b, 0x14}} , + {{0x11, 0xce, 0xbf, 0xb6, 0x77, 0x2d, 0x48, 0x22, 0x18, 0x4f, 0xa3, 0x5d, 0x4a, 0xb0, 0x70, 0x12, 0x3e, 0x54, 0xd7, 0xd8, 0x0e, 0x2b, 0x27, 0xdc, 0x53, 0xff, 0xca, 0x8c, 0x59, 0xb3, 0x4e, 0x44}}}, +{{{0x07, 0x76, 0x61, 0x0f, 0x66, 0xb2, 0x21, 0x39, 0x7e, 0xc0, 0xec, 0x45, 0x28, 0x82, 0xa1, 0x29, 0x32, 0x44, 0x35, 0x13, 0x5e, 0x61, 0x5e, 0x54, 0xcb, 0x7c, 0xef, 0xf6, 0x41, 0xcf, 0x9f, 0x0a}} , + {{0xdd, 0xf9, 0xda, 0x84, 0xc3, 0xe6, 0x8a, 0x9f, 0x24, 0xd2, 0x96, 0x5d, 0x39, 0x6f, 0x58, 0x8c, 0xc1, 0x56, 0x93, 0xab, 0xb5, 0x79, 0x3b, 0xd2, 0xa8, 0x73, 0x16, 0xed, 0xfa, 0xb4, 0x2f, 0x73}}}, +{{{0x8b, 0xb1, 0x95, 0xe5, 0x92, 0x50, 0x35, 0x11, 0x76, 0xac, 0xf4, 0x4d, 0x24, 0xc3, 0x32, 0xe6, 0xeb, 0xfe, 0x2c, 0x87, 0xc4, 0xf1, 0x56, 0xc4, 0x75, 0x24, 0x7a, 0x56, 0x85, 0x5a, 0x3a, 0x13}} , + {{0x0d, 0x16, 0xac, 0x3c, 0x4a, 0x58, 0x86, 0x3a, 0x46, 0x7f, 0x6c, 0xa3, 0x52, 0x6e, 0x37, 0xe4, 0x96, 0x9c, 0xe9, 0x5c, 0x66, 0x41, 0x67, 0xe4, 0xfb, 0x79, 0x0c, 0x05, 0xf6, 0x64, 0xd5, 0x7c}}}, +{{{0x28, 0xc1, 0xe1, 0x54, 0x73, 0xf2, 0xbf, 0x76, 0x74, 0x19, 0x19, 0x1b, 0xe4, 0xb9, 0xa8, 0x46, 0x65, 0x73, 0xf3, 0x77, 0x9b, 0x29, 0x74, 0x5b, 0xc6, 0x89, 0x6c, 0x2c, 0x7c, 0xf8, 0xb3, 0x0f}} , + {{0xf7, 0xd5, 0xe9, 0x74, 0x5d, 0xb8, 0x25, 0x16, 0xb5, 0x30, 0xbc, 0x84, 0xc5, 0xf0, 0xad, 0xca, 0x12, 0x28, 0xbc, 0x9d, 0xd4, 0xfa, 0x82, 0xe6, 0xe3, 0xbf, 0xa2, 0x15, 0x2c, 0xd4, 0x34, 0x10}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x61, 0xb1, 0x46, 0xba, 0x0e, 0x31, 0xa5, 0x67, 0x6c, 0x7f, 0xd6, 0xd9, 0x27, 0x85, 0x0f, 0x79, 0x14, 0xc8, 0x6c, 0x2f, 0x5f, 0x5b, 0x9c, 0x35, 0x3d, 0x38, 0x86, 0x77, 0x65, 0x55, 0x6a, 0x7b}} , + {{0xd3, 0xb0, 0x3a, 0x66, 0x60, 0x1b, 0x43, 0xf1, 0x26, 0x58, 0x99, 0x09, 0x8f, 0x2d, 0xa3, 0x14, 0x71, 0x85, 0xdb, 0xed, 0xf6, 0x26, 0xd5, 0x61, 0x9a, 0x73, 0xac, 0x0e, 0xea, 0xac, 0xb7, 0x0c}}}, +{{{0x5e, 0xf4, 0xe5, 0x17, 0x0e, 0x10, 0x9f, 0xe7, 0x43, 0x5f, 0x67, 0x5c, 0xac, 0x4b, 0xe5, 0x14, 0x41, 0xd2, 0xbf, 0x48, 0xf5, 0x14, 0xb0, 0x71, 0xc6, 0x61, 0xc1, 0xb2, 0x70, 0x58, 0xd2, 0x5a}} , + {{0x2d, 0xba, 0x16, 0x07, 0x92, 0x94, 0xdc, 0xbd, 0x50, 0x2b, 0xc9, 0x7f, 0x42, 0x00, 0xba, 0x61, 0xed, 0xf8, 0x43, 0xed, 0xf5, 0xf9, 0x40, 0x60, 0xb2, 0xb0, 0x82, 0xcb, 0xed, 0x75, 0xc7, 0x65}}}, +{{{0x80, 0xba, 0x0d, 0x09, 0x40, 0xa7, 0x39, 0xa6, 0x67, 0x34, 0x7e, 0x66, 0xbe, 0x56, 0xfb, 0x53, 0x78, 0xc4, 0x46, 0xe8, 0xed, 0x68, 0x6c, 0x7f, 0xce, 0xe8, 0x9f, 0xce, 0xa2, 0x64, 0x58, 0x53}} , + {{0xe8, 0xc1, 0xa9, 0xc2, 0x7b, 0x59, 0x21, 0x33, 0xe2, 0x43, 0x73, 0x2b, 0xac, 0x2d, 0xc1, 0x89, 0x3b, 0x15, 0xe2, 0xd5, 0xc0, 0x97, 0x8a, 0xfd, 0x6f, 0x36, 0x33, 0xb7, 0xb9, 0xc3, 0x88, 0x09}}}, +{{{0xd0, 0xb6, 0x56, 0x30, 0x5c, 0xae, 0xb3, 0x75, 0x44, 0xa4, 0x83, 0x51, 0x6e, 0x01, 0x65, 0xef, 0x45, 0x76, 0xe6, 0xf5, 0xa2, 0x0d, 0xd4, 0x16, 0x3b, 0x58, 0x2f, 0xf2, 0x2f, 0x36, 0x18, 0x3f}} , + {{0xfd, 0x2f, 0xe0, 0x9b, 0x1e, 0x8c, 0xc5, 0x18, 0xa9, 0xca, 0xd4, 0x2b, 0x35, 0xb6, 0x95, 0x0a, 0x9f, 0x7e, 0xfb, 0xc4, 0xef, 0x88, 0x7b, 0x23, 0x43, 0xec, 0x2f, 0x0d, 0x0f, 0x7a, 0xfc, 0x5c}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb, 0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, 0x7d, 0x17, 0x7e, 0x1c, 0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b}} , + {{0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63, 0x12, 0x7e, 0x02, 0x1d, 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a, 0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61}}}, +{{{0x54, 0x83, 0x02, 0x18, 0x82, 0x93, 0x99, 0x07, 0xd0, 0xa7, 0xda, 0xd8, 0x75, 0x89, 0xfa, 0xf2, 0xd9, 0xa3, 0xb8, 0x6b, 0x5a, 0x35, 0x28, 0xd2, 0x6b, 0x59, 0xc2, 0xf8, 0x45, 0xe2, 0xbc, 0x06}} , + {{0x65, 0xc0, 0xa3, 0x88, 0x51, 0x95, 0xfc, 0x96, 0x94, 0x78, 0xe8, 0x0d, 0x8b, 0x41, 0xc9, 0xc2, 0x58, 0x48, 0x75, 0x10, 0x2f, 0xcd, 0x2a, 0xc9, 0xa0, 0x6d, 0x0f, 0xdd, 0x9c, 0x98, 0x26, 0x3d}}}, +{{{0x2f, 0x66, 0x29, 0x1b, 0x04, 0x89, 0xbd, 0x7e, 0xee, 0x6e, 0xdd, 0xb7, 0x0e, 0xef, 0xb0, 0x0c, 0xb4, 0xfc, 0x7f, 0xc2, 0xc9, 0x3a, 0x3c, 0x64, 0xef, 0x45, 0x44, 0xaf, 0x8a, 0x90, 0x65, 0x76}} , + {{0xa1, 0x4c, 0x70, 0x4b, 0x0e, 0xa0, 0x83, 0x70, 0x13, 0xa4, 0xaf, 0xb8, 0x38, 0x19, 0x22, 0x65, 0x09, 0xb4, 0x02, 0x4f, 0x06, 0xf8, 0x17, 0xce, 0x46, 0x45, 0xda, 0x50, 0x7c, 0x8a, 0xd1, 0x4e}}}, +{{{0xf7, 0xd4, 0x16, 0x6c, 0x4e, 0x95, 0x9d, 0x5d, 0x0f, 0x91, 0x2b, 0x52, 0xfe, 0x5c, 0x34, 0xe5, 0x30, 0xe6, 0xa4, 0x3b, 0xf3, 0xf3, 0x34, 0x08, 0xa9, 0x4a, 0xa0, 0xb5, 0x6e, 0xb3, 0x09, 0x0a}} , + {{0x26, 0xd9, 0x5e, 0xa3, 0x0f, 0xeb, 0xa2, 0xf3, 0x20, 0x3b, 0x37, 0xd4, 0xe4, 0x9e, 0xce, 0x06, 0x3d, 0x53, 0xed, 0xae, 0x2b, 0xeb, 0xb6, 0x24, 0x0a, 0x11, 0xa3, 0x0f, 0xd6, 0x7f, 0xa4, 0x3a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xdb, 0x9f, 0x2c, 0xfc, 0xd6, 0xb2, 0x1e, 0x2e, 0x52, 0x7a, 0x06, 0x87, 0x2d, 0x86, 0x72, 0x2b, 0x6d, 0x90, 0x77, 0x46, 0x43, 0xb5, 0x7a, 0xf8, 0x60, 0x7d, 0x91, 0x60, 0x5b, 0x9d, 0x9e, 0x07}} , + {{0x97, 0x87, 0xc7, 0x04, 0x1c, 0x38, 0x01, 0x39, 0x58, 0xc7, 0x85, 0xa3, 0xfc, 0x64, 0x00, 0x64, 0x25, 0xa2, 0xbf, 0x50, 0x94, 0xca, 0x26, 0x31, 0x45, 0x0a, 0x24, 0xd2, 0x51, 0x29, 0x51, 0x16}}}, +{{{0x4d, 0x4a, 0xd7, 0x98, 0x71, 0x57, 0xac, 0x7d, 0x8b, 0x37, 0xbd, 0x63, 0xff, 0x87, 0xb1, 0x49, 0x95, 0x20, 0x7c, 0xcf, 0x7c, 0x59, 0xc4, 0x91, 0x9c, 0xef, 0xd0, 0xdb, 0x60, 0x09, 0x9d, 0x46}} , + {{0xcb, 0x78, 0x94, 0x90, 0xe4, 0x45, 0xb3, 0xf6, 0xd9, 0xf6, 0x57, 0x74, 0xd5, 0xf8, 0x83, 0x4f, 0x39, 0xc9, 0xbd, 0x88, 0xc2, 0x57, 0x21, 0x1f, 0x24, 0x32, 0x68, 0xf8, 0xc7, 0x21, 0x5f, 0x0b}}}, +{{{0x2a, 0x36, 0x68, 0xfc, 0x5f, 0xb6, 0x4f, 0xa5, 0xe3, 0x9d, 0x24, 0x2f, 0xc0, 0x93, 0x61, 0xcf, 0xf8, 0x0a, 0xed, 0xe1, 0xdb, 0x27, 0xec, 0x0e, 0x14, 0x32, 0x5f, 0x8e, 0xa1, 0x62, 0x41, 0x16}} , + {{0x95, 0x21, 0x01, 0xce, 0x95, 0x5b, 0x0e, 0x57, 0xc7, 0xb9, 0x62, 0xb5, 0x28, 0xca, 0x11, 0xec, 0xb4, 0x46, 0x06, 0x73, 0x26, 0xff, 0xfb, 0x66, 0x7d, 0xee, 0x5f, 0xb2, 0x56, 0xfd, 0x2a, 0x08}}}, +{{{0x92, 0x67, 0x77, 0x56, 0xa1, 0xff, 0xc4, 0xc5, 0x95, 0xf0, 0xe3, 0x3a, 0x0a, 0xca, 0x94, 0x4d, 0x9e, 0x7e, 0x3d, 0xb9, 0x6e, 0xb6, 0xb0, 0xce, 0xa4, 0x30, 0x89, 0x99, 0xe9, 0xad, 0x11, 0x59}} , + {{0xf6, 0x48, 0x95, 0xa1, 0x6f, 0x5f, 0xb7, 0xa5, 0xbb, 0x30, 0x00, 0x1c, 0xd2, 0x8a, 0xd6, 0x25, 0x26, 0x1b, 0xb2, 0x0d, 0x37, 0x6a, 0x05, 0xf4, 0x9d, 0x3e, 0x17, 0x2a, 0x43, 0xd2, 0x3a, 0x06}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x32, 0x99, 0x93, 0xd1, 0x9a, 0x72, 0xf3, 0xa9, 0x16, 0xbd, 0xb4, 0x4c, 0xdd, 0xf9, 0xd4, 0xb2, 0x64, 0x9a, 0xd3, 0x05, 0xe4, 0xa3, 0x73, 0x1c, 0xcb, 0x7e, 0x57, 0x67, 0xff, 0x04, 0xb3, 0x10}} , + {{0xb9, 0x4b, 0xa4, 0xad, 0xd0, 0x6d, 0x61, 0x23, 0xb4, 0xaf, 0x34, 0xa9, 0xaa, 0x65, 0xec, 0xd9, 0x69, 0xe3, 0x85, 0xcd, 0xcc, 0xe7, 0xb0, 0x9b, 0x41, 0xc1, 0x1c, 0xf9, 0xa0, 0xfa, 0xb7, 0x13}}}, +{{{0x04, 0xfd, 0x88, 0x3c, 0x0c, 0xd0, 0x09, 0x52, 0x51, 0x4f, 0x06, 0x19, 0xcc, 0xc3, 0xbb, 0xde, 0x80, 0xc5, 0x33, 0xbc, 0xf9, 0xf3, 0x17, 0x36, 0xdd, 0xc6, 0xde, 0xe8, 0x9b, 0x5d, 0x79, 0x1b}} , + {{0x65, 0x0a, 0xbe, 0x51, 0x57, 0xad, 0x50, 0x79, 0x08, 0x71, 0x9b, 0x07, 0x95, 0x8f, 0xfb, 0xae, 0x4b, 0x38, 0xba, 0xcf, 0x53, 0x2a, 0x86, 0x1e, 0xc0, 0x50, 0x5c, 0x67, 0x1b, 0xf6, 0x87, 0x6c}}}, +{{{0x4f, 0x00, 0xb2, 0x66, 0x55, 0xed, 0x4a, 0xed, 0x8d, 0xe1, 0x66, 0x18, 0xb2, 0x14, 0x74, 0x8d, 0xfd, 0x1a, 0x36, 0x0f, 0x26, 0x5c, 0x8b, 0x89, 0xf3, 0xab, 0xf2, 0xf3, 0x24, 0x67, 0xfd, 0x70}} , + {{0xfd, 0x4e, 0x2a, 0xc1, 0x3a, 0xca, 0x8f, 0x00, 0xd8, 0xec, 0x74, 0x67, 0xef, 0x61, 0xe0, 0x28, 0xd0, 0x96, 0xf4, 0x48, 0xde, 0x81, 0xe3, 0xef, 0xdc, 0xaa, 0x7d, 0xf3, 0xb6, 0x55, 0xa6, 0x65}}}, +{{{0xeb, 0xcb, 0xc5, 0x70, 0x91, 0x31, 0x10, 0x93, 0x0d, 0xc8, 0xd0, 0xef, 0x62, 0xe8, 0x6f, 0x82, 0xe3, 0x69, 0x3d, 0x91, 0x7f, 0x31, 0xe1, 0x26, 0x35, 0x3c, 0x4a, 0x2f, 0xab, 0xc4, 0x9a, 0x5e}} , + {{0xab, 0x1b, 0xb5, 0xe5, 0x2b, 0xc3, 0x0e, 0x29, 0xb0, 0xd0, 0x73, 0xe6, 0x4f, 0x64, 0xf2, 0xbc, 0xe4, 0xe4, 0xe1, 0x9a, 0x52, 0x33, 0x2f, 0xbd, 0xcc, 0x03, 0xee, 0x8a, 0xfa, 0x00, 0x5f, 0x50}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xf6, 0xdb, 0x0d, 0x22, 0x3d, 0xb5, 0x14, 0x75, 0x31, 0xf0, 0x81, 0xe2, 0xb9, 0x37, 0xa2, 0xa9, 0x84, 0x11, 0x9a, 0x07, 0xb5, 0x53, 0x89, 0x78, 0xa9, 0x30, 0x27, 0xa1, 0xf1, 0x4e, 0x5c, 0x2e}} , + {{0x8b, 0x00, 0x54, 0xfb, 0x4d, 0xdc, 0xcb, 0x17, 0x35, 0x40, 0xff, 0xb7, 0x8c, 0xfe, 0x4a, 0xe4, 0x4e, 0x99, 0x4e, 0xa8, 0x74, 0x54, 0x5d, 0x5c, 0x96, 0xa3, 0x12, 0x55, 0x36, 0x31, 0x17, 0x5c}}}, +{{{0xce, 0x24, 0xef, 0x7b, 0x86, 0xf2, 0x0f, 0x77, 0xe8, 0x5c, 0x7d, 0x87, 0x38, 0x2d, 0xef, 0xaf, 0xf2, 0x8c, 0x72, 0x2e, 0xeb, 0xb6, 0x55, 0x4b, 0x6e, 0xf1, 0x4e, 0x8a, 0x0e, 0x9a, 0x6c, 0x4c}} , + {{0x25, 0xea, 0x86, 0xc2, 0xd1, 0x4f, 0xb7, 0x3e, 0xa8, 0x5c, 0x8d, 0x66, 0x81, 0x25, 0xed, 0xc5, 0x4c, 0x05, 0xb9, 0xd8, 0xd6, 0x70, 0xbe, 0x73, 0x82, 0xe8, 0xa1, 0xe5, 0x1e, 0x71, 0xd5, 0x26}}}, +{{{0x4e, 0x6d, 0xc3, 0xa7, 0x4f, 0x22, 0x45, 0x26, 0xa2, 0x7e, 0x16, 0xf7, 0xf7, 0x63, 0xdc, 0x86, 0x01, 0x2a, 0x71, 0x38, 0x5c, 0x33, 0xc3, 0xce, 0x30, 0xff, 0xf9, 0x2c, 0x91, 0x71, 0x8a, 0x72}} , + {{0x8c, 0x44, 0x09, 0x28, 0xd5, 0x23, 0xc9, 0x8f, 0xf3, 0x84, 0x45, 0xc6, 0x9a, 0x5e, 0xff, 0xd2, 0xc7, 0x57, 0x93, 0xa3, 0xc1, 0x69, 0xdd, 0x62, 0x0f, 0xda, 0x5c, 0x30, 0x59, 0x5d, 0xe9, 0x4c}}}, +{{{0x92, 0x7e, 0x50, 0x27, 0x72, 0xd7, 0x0c, 0xd6, 0x69, 0x96, 0x81, 0x35, 0x84, 0x94, 0x35, 0x8b, 0x6c, 0xaa, 0x62, 0x86, 0x6e, 0x1c, 0x15, 0xf3, 0x6c, 0xb3, 0xff, 0x65, 0x1b, 0xa2, 0x9b, 0x59}} , + {{0xe2, 0xa9, 0x65, 0x88, 0xc4, 0x50, 0xfa, 0xbb, 0x3b, 0x6e, 0x5f, 0x44, 0x01, 0xca, 0x97, 0xd4, 0xdd, 0xf6, 0xcd, 0x3f, 0x3f, 0xe5, 0x97, 0x67, 0x2b, 0x8c, 0x66, 0x0f, 0x35, 0x9b, 0xf5, 0x07}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xf1, 0x59, 0x27, 0xd8, 0xdb, 0x5a, 0x11, 0x5e, 0x82, 0xf3, 0x38, 0xff, 0x1c, 0xed, 0xfe, 0x3f, 0x64, 0x54, 0x3f, 0x7f, 0xd1, 0x81, 0xed, 0xef, 0x65, 0xc5, 0xcb, 0xfd, 0xe1, 0x80, 0xcd, 0x11}} , + {{0xe0, 0xdb, 0x22, 0x28, 0xe6, 0xff, 0x61, 0x9d, 0x41, 0x14, 0x2d, 0x3b, 0x26, 0x22, 0xdf, 0xf1, 0x34, 0x81, 0xe9, 0x45, 0xee, 0x0f, 0x98, 0x8b, 0xa6, 0x3f, 0xef, 0xf7, 0x43, 0x19, 0xf1, 0x43}}}, +{{{0xee, 0xf3, 0x00, 0xa1, 0x50, 0xde, 0xc0, 0xb6, 0x01, 0xe3, 0x8c, 0x3c, 0x4d, 0x31, 0xd2, 0xb0, 0x58, 0xcd, 0xed, 0x10, 0x4a, 0x7a, 0xef, 0x80, 0xa9, 0x19, 0x32, 0xf3, 0xd8, 0x33, 0x8c, 0x06}} , + {{0xcb, 0x7d, 0x4f, 0xff, 0x30, 0xd8, 0x12, 0x3b, 0x39, 0x1c, 0x06, 0xf9, 0x4c, 0x34, 0x35, 0x71, 0xb5, 0x16, 0x94, 0x67, 0xdf, 0xee, 0x11, 0xde, 0xa4, 0x1d, 0x88, 0x93, 0x35, 0xa9, 0x32, 0x10}}}, +{{{0xe9, 0xc3, 0xbc, 0x7b, 0x5c, 0xfc, 0xb2, 0xf9, 0xc9, 0x2f, 0xe5, 0xba, 0x3a, 0x0b, 0xab, 0x64, 0x38, 0x6f, 0x5b, 0x4b, 0x93, 0xda, 0x64, 0xec, 0x4d, 0x3d, 0xa0, 0xf5, 0xbb, 0xba, 0x47, 0x48}} , + {{0x60, 0xbc, 0x45, 0x1f, 0x23, 0xa2, 0x3b, 0x70, 0x76, 0xe6, 0x97, 0x99, 0x4f, 0x77, 0x54, 0x67, 0x30, 0x9a, 0xe7, 0x66, 0xd6, 0xcd, 0x2e, 0x51, 0x24, 0x2c, 0x42, 0x4a, 0x11, 0xfe, 0x6f, 0x7e}}}, +{{{0x87, 0xc0, 0xb1, 0xf0, 0xa3, 0x6f, 0x0c, 0x93, 0xa9, 0x0a, 0x72, 0xef, 0x5c, 0xbe, 0x65, 0x35, 0xa7, 0x6a, 0x4e, 0x2c, 0xbf, 0x21, 0x23, 0xe8, 0x2f, 0x97, 0xc7, 0x3e, 0xc8, 0x17, 0xac, 0x1e}} , + {{0x7b, 0xef, 0x21, 0xe5, 0x40, 0xcc, 0x1e, 0xdc, 0xd6, 0xbd, 0x97, 0x7a, 0x7c, 0x75, 0x86, 0x7a, 0x25, 0x5a, 0x6e, 0x7c, 0xe5, 0x51, 0x3c, 0x1b, 0x5b, 0x82, 0x9a, 0x07, 0x60, 0xa1, 0x19, 0x04}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x96, 0x88, 0xa6, 0xab, 0x8f, 0xe3, 0x3a, 0x49, 0xf8, 0xfe, 0x34, 0xe7, 0x6a, 0xb2, 0xfe, 0x40, 0x26, 0x74, 0x57, 0x4c, 0xf6, 0xd4, 0x99, 0xce, 0x5d, 0x7b, 0x2f, 0x67, 0xd6, 0x5a, 0xe4, 0x4e}} , + {{0x5c, 0x82, 0xb3, 0xbd, 0x55, 0x25, 0xf6, 0x6a, 0x93, 0xa4, 0x02, 0xc6, 0x7d, 0x5c, 0xb1, 0x2b, 0x5b, 0xff, 0xfb, 0x56, 0xf8, 0x01, 0x41, 0x90, 0xc6, 0xb6, 0xac, 0x4f, 0xfe, 0xa7, 0x41, 0x70}}}, +{{{0xdb, 0xfa, 0x9b, 0x2c, 0xd4, 0x23, 0x67, 0x2c, 0x8a, 0x63, 0x6c, 0x07, 0x26, 0x48, 0x4f, 0xc2, 0x03, 0xd2, 0x53, 0x20, 0x28, 0xed, 0x65, 0x71, 0x47, 0xa9, 0x16, 0x16, 0x12, 0xbc, 0x28, 0x33}} , + {{0x39, 0xc0, 0xfa, 0xfa, 0xcd, 0x33, 0x43, 0xc7, 0x97, 0x76, 0x9b, 0x93, 0x91, 0x72, 0xeb, 0xc5, 0x18, 0x67, 0x4c, 0x11, 0xf0, 0xf4, 0xe5, 0x73, 0xb2, 0x5c, 0x1b, 0xc2, 0x26, 0x3f, 0xbf, 0x2b}}}, +{{{0x86, 0xe6, 0x8c, 0x1d, 0xdf, 0xca, 0xfc, 0xd5, 0xf8, 0x3a, 0xc3, 0x44, 0x72, 0xe6, 0x78, 0x9d, 0x2b, 0x97, 0xf8, 0x28, 0x45, 0xb4, 0x20, 0xc9, 0x2a, 0x8c, 0x67, 0xaa, 0x11, 0xc5, 0x5b, 0x2f}} , + {{0x17, 0x0f, 0x86, 0x52, 0xd7, 0x9d, 0xc3, 0x44, 0x51, 0x76, 0x32, 0x65, 0xb4, 0x37, 0x81, 0x99, 0x46, 0x37, 0x62, 0xed, 0xcf, 0x64, 0x9d, 0x72, 0x40, 0x7a, 0x4c, 0x0b, 0x76, 0x2a, 0xfb, 0x56}}}, +{{{0x33, 0xa7, 0x90, 0x7c, 0xc3, 0x6f, 0x17, 0xa5, 0xa0, 0x67, 0x72, 0x17, 0xea, 0x7e, 0x63, 0x14, 0x83, 0xde, 0xc1, 0x71, 0x2d, 0x41, 0x32, 0x7a, 0xf3, 0xd1, 0x2b, 0xd8, 0x2a, 0xa6, 0x46, 0x36}} , + {{0xac, 0xcc, 0x6b, 0x7c, 0xf9, 0xb8, 0x8b, 0x08, 0x5c, 0xd0, 0x7d, 0x8f, 0x73, 0xea, 0x20, 0xda, 0x86, 0xca, 0x00, 0xc7, 0xad, 0x73, 0x4d, 0xe9, 0xe8, 0xa9, 0xda, 0x1f, 0x03, 0x06, 0xdd, 0x24}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x9c, 0xb2, 0x61, 0x0a, 0x98, 0x2a, 0xa5, 0xd7, 0xee, 0xa9, 0xac, 0x65, 0xcb, 0x0a, 0x1e, 0xe2, 0xbe, 0xdc, 0x85, 0x59, 0x0f, 0x9c, 0xa6, 0x57, 0x34, 0xa5, 0x87, 0xeb, 0x7b, 0x1e, 0x0c, 0x3c}} , + {{0x2f, 0xbd, 0x84, 0x63, 0x0d, 0xb5, 0xa0, 0xf0, 0x4b, 0x9e, 0x93, 0xc6, 0x34, 0x9a, 0x34, 0xff, 0x73, 0x19, 0x2f, 0x6e, 0x54, 0x45, 0x2c, 0x92, 0x31, 0x76, 0x34, 0xf1, 0xb2, 0x26, 0xe8, 0x74}}}, +{{{0x0a, 0x67, 0x90, 0x6d, 0x0c, 0x4c, 0xcc, 0xc0, 0xe6, 0xbd, 0xa7, 0x5e, 0x55, 0x8c, 0xcd, 0x58, 0x9b, 0x11, 0xa2, 0xbb, 0x4b, 0xb1, 0x43, 0x04, 0x3c, 0x55, 0xed, 0x23, 0xfe, 0xcd, 0xb1, 0x53}} , + {{0x05, 0xfb, 0x75, 0xf5, 0x01, 0xaf, 0x38, 0x72, 0x58, 0xfc, 0x04, 0x29, 0x34, 0x7a, 0x67, 0xa2, 0x08, 0x50, 0x6e, 0xd0, 0x2b, 0x73, 0xd5, 0xb8, 0xe4, 0x30, 0x96, 0xad, 0x45, 0xdf, 0xa6, 0x5c}}}, +{{{0x0d, 0x88, 0x1a, 0x90, 0x7e, 0xdc, 0xd8, 0xfe, 0xc1, 0x2f, 0x5d, 0x67, 0xee, 0x67, 0x2f, 0xed, 0x6f, 0x55, 0x43, 0x5f, 0x87, 0x14, 0x35, 0x42, 0xd3, 0x75, 0xae, 0xd5, 0xd3, 0x85, 0x1a, 0x76}} , + {{0x87, 0xc8, 0xa0, 0x6e, 0xe1, 0xb0, 0xad, 0x6a, 0x4a, 0x34, 0x71, 0xed, 0x7c, 0xd6, 0x44, 0x03, 0x65, 0x4a, 0x5c, 0x5c, 0x04, 0xf5, 0x24, 0x3f, 0xb0, 0x16, 0x5e, 0x8c, 0xb2, 0xd2, 0xc5, 0x20}}}, +{{{0x98, 0x83, 0xc2, 0x37, 0xa0, 0x41, 0xa8, 0x48, 0x5c, 0x5f, 0xbf, 0xc8, 0xfa, 0x24, 0xe0, 0x59, 0x2c, 0xbd, 0xf6, 0x81, 0x7e, 0x88, 0xe6, 0xca, 0x04, 0xd8, 0x5d, 0x60, 0xbb, 0x74, 0xa7, 0x0b}} , + {{0x21, 0x13, 0x91, 0xbf, 0x77, 0x7a, 0x33, 0xbc, 0xe9, 0x07, 0x39, 0x0a, 0xdd, 0x7d, 0x06, 0x10, 0x9a, 0xee, 0x47, 0x73, 0x1b, 0x15, 0x5a, 0xfb, 0xcd, 0x4d, 0xd0, 0xd2, 0x3a, 0x01, 0xba, 0x54}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x48, 0xd5, 0x39, 0x4a, 0x0b, 0x20, 0x6a, 0x43, 0xa0, 0x07, 0x82, 0x5e, 0x49, 0x7c, 0xc9, 0x47, 0xf1, 0x7c, 0x37, 0xb9, 0x23, 0xef, 0x6b, 0x46, 0x45, 0x8c, 0x45, 0x76, 0xdf, 0x14, 0x6b, 0x6e}} , + {{0x42, 0xc9, 0xca, 0x29, 0x4c, 0x76, 0x37, 0xda, 0x8a, 0x2d, 0x7c, 0x3a, 0x58, 0xf2, 0x03, 0xb4, 0xb5, 0xb9, 0x1a, 0x13, 0x2d, 0xde, 0x5f, 0x6b, 0x9d, 0xba, 0x52, 0xc9, 0x5d, 0xb3, 0xf3, 0x30}}}, +{{{0x4c, 0x6f, 0xfe, 0x6b, 0x0c, 0x62, 0xd7, 0x48, 0x71, 0xef, 0xb1, 0x85, 0x79, 0xc0, 0xed, 0x24, 0xb1, 0x08, 0x93, 0x76, 0x8e, 0xf7, 0x38, 0x8e, 0xeb, 0xfe, 0x80, 0x40, 0xaf, 0x90, 0x64, 0x49}} , + {{0x4a, 0x88, 0xda, 0xc1, 0x98, 0x44, 0x3c, 0x53, 0x4e, 0xdb, 0x4b, 0xb9, 0x12, 0x5f, 0xcd, 0x08, 0x04, 0xef, 0x75, 0xe7, 0xb1, 0x3a, 0xe5, 0x07, 0xfa, 0xca, 0x65, 0x7b, 0x72, 0x10, 0x64, 0x7f}}}, +{{{0x3d, 0x81, 0xf0, 0xeb, 0x16, 0xfd, 0x58, 0x33, 0x8d, 0x7c, 0x1a, 0xfb, 0x20, 0x2c, 0x8a, 0xee, 0x90, 0xbb, 0x33, 0x6d, 0x45, 0xe9, 0x8e, 0x99, 0x85, 0xe1, 0x08, 0x1f, 0xc5, 0xf1, 0xb5, 0x46}} , + {{0xe4, 0xe7, 0x43, 0x4b, 0xa0, 0x3f, 0x2b, 0x06, 0xba, 0x17, 0xae, 0x3d, 0xe6, 0xce, 0xbd, 0xb8, 0xed, 0x74, 0x11, 0x35, 0xec, 0x96, 0xfe, 0x31, 0xe3, 0x0e, 0x7a, 0x4e, 0xc9, 0x1d, 0xcb, 0x20}}}, +{{{0xe0, 0x67, 0xe9, 0x7b, 0xdb, 0x96, 0x5c, 0xb0, 0x32, 0xd0, 0x59, 0x31, 0x90, 0xdc, 0x92, 0x97, 0xac, 0x09, 0x38, 0x31, 0x0f, 0x7e, 0xd6, 0x5d, 0xd0, 0x06, 0xb6, 0x1f, 0xea, 0xf0, 0x5b, 0x07}} , + {{0x81, 0x9f, 0xc7, 0xde, 0x6b, 0x41, 0x22, 0x35, 0x14, 0x67, 0x77, 0x3e, 0x90, 0x81, 0xb0, 0xd9, 0x85, 0x4c, 0xca, 0x9b, 0x3f, 0x04, 0x59, 0xd6, 0xaa, 0x17, 0xc3, 0x88, 0x34, 0x37, 0xba, 0x43}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x4c, 0xb6, 0x69, 0xc8, 0x81, 0x95, 0x94, 0x33, 0x92, 0x34, 0xe9, 0x3c, 0x84, 0x0d, 0x3d, 0x5a, 0x37, 0x9c, 0x22, 0xa0, 0xaa, 0x65, 0xce, 0xb4, 0xc2, 0x2d, 0x66, 0x67, 0x02, 0xff, 0x74, 0x10}} , + {{0x22, 0xb0, 0xd5, 0xe6, 0xc7, 0xef, 0xb1, 0xa7, 0x13, 0xda, 0x60, 0xb4, 0x80, 0xc1, 0x42, 0x7d, 0x10, 0x70, 0x97, 0x04, 0x4d, 0xda, 0x23, 0x89, 0xc2, 0x0e, 0x68, 0xcb, 0xde, 0xe0, 0x9b, 0x29}}}, +{{{0x33, 0xfe, 0x42, 0x2a, 0x36, 0x2b, 0x2e, 0x36, 0x64, 0x5c, 0x8b, 0xcc, 0x81, 0x6a, 0x15, 0x08, 0xa1, 0x27, 0xe8, 0x57, 0xe5, 0x78, 0x8e, 0xf2, 0x58, 0x19, 0x12, 0x42, 0xae, 0xc4, 0x63, 0x3e}} , + {{0x78, 0x96, 0x9c, 0xa7, 0xca, 0x80, 0xae, 0x02, 0x85, 0xb1, 0x7c, 0x04, 0x5c, 0xc1, 0x5b, 0x26, 0xc1, 0xba, 0xed, 0xa5, 0x59, 0x70, 0x85, 0x8c, 0x8c, 0xe8, 0x87, 0xac, 0x6a, 0x28, 0x99, 0x35}}}, +{{{0x9f, 0x04, 0x08, 0x28, 0xbe, 0x87, 0xda, 0x80, 0x28, 0x38, 0xde, 0x9f, 0xcd, 0xe4, 0xe3, 0x62, 0xfb, 0x2e, 0x46, 0x8d, 0x01, 0xb3, 0x06, 0x51, 0xd4, 0x19, 0x3b, 0x11, 0xfa, 0xe2, 0xad, 0x1e}} , + {{0xa0, 0x20, 0x99, 0x69, 0x0a, 0xae, 0xa3, 0x70, 0x4e, 0x64, 0x80, 0xb7, 0x85, 0x9c, 0x87, 0x54, 0x43, 0x43, 0x55, 0x80, 0x6d, 0x8d, 0x7c, 0xa9, 0x64, 0xca, 0x6c, 0x2e, 0x21, 0xd8, 0xc8, 0x6c}}}, +{{{0x91, 0x4a, 0x07, 0xad, 0x08, 0x75, 0xc1, 0x4f, 0xa4, 0xb2, 0xc3, 0x6f, 0x46, 0x3e, 0xb1, 0xce, 0x52, 0xab, 0x67, 0x09, 0x54, 0x48, 0x6b, 0x6c, 0xd7, 0x1d, 0x71, 0x76, 0xcb, 0xff, 0xdd, 0x31}} , + {{0x36, 0x88, 0xfa, 0xfd, 0xf0, 0x36, 0x6f, 0x07, 0x74, 0x88, 0x50, 0xd0, 0x95, 0x38, 0x4a, 0x48, 0x2e, 0x07, 0x64, 0x97, 0x11, 0x76, 0x01, 0x1a, 0x27, 0x4d, 0x8e, 0x25, 0x9a, 0x9b, 0x1c, 0x22}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xbe, 0x57, 0xbd, 0x0e, 0x0f, 0xac, 0x5e, 0x76, 0xa3, 0x71, 0xad, 0x2b, 0x10, 0x45, 0x02, 0xec, 0x59, 0xd5, 0x5d, 0xa9, 0x44, 0xcc, 0x25, 0x4c, 0xb3, 0x3c, 0x5b, 0x69, 0x07, 0x55, 0x26, 0x6b}} , + {{0x30, 0x6b, 0xd4, 0xa7, 0x51, 0x29, 0xe3, 0xf9, 0x7a, 0x75, 0x2a, 0x82, 0x2f, 0xd6, 0x1d, 0x99, 0x2b, 0x80, 0xd5, 0x67, 0x1e, 0x15, 0x9d, 0xca, 0xfd, 0xeb, 0xac, 0x97, 0x35, 0x09, 0x7f, 0x3f}}}, +{{{0x35, 0x0d, 0x34, 0x0a, 0xb8, 0x67, 0x56, 0x29, 0x20, 0xf3, 0x19, 0x5f, 0xe2, 0x83, 0x42, 0x73, 0x53, 0xa8, 0xc5, 0x02, 0x19, 0x33, 0xb4, 0x64, 0xbd, 0xc3, 0x87, 0x8c, 0xd7, 0x76, 0xed, 0x25}} , + {{0x47, 0x39, 0x37, 0x76, 0x0d, 0x1d, 0x0c, 0xf5, 0x5a, 0x6d, 0x43, 0x88, 0x99, 0x15, 0xb4, 0x52, 0x0f, 0x2a, 0xb3, 0xb0, 0x3f, 0xa6, 0xb3, 0x26, 0xb3, 0xc7, 0x45, 0xf5, 0x92, 0x5f, 0x9b, 0x17}}}, +{{{0x9d, 0x23, 0xbd, 0x15, 0xfe, 0x52, 0x52, 0x15, 0x26, 0x79, 0x86, 0xba, 0x06, 0x56, 0x66, 0xbb, 0x8c, 0x2e, 0x10, 0x11, 0xd5, 0x4a, 0x18, 0x52, 0xda, 0x84, 0x44, 0xf0, 0x3e, 0xe9, 0x8c, 0x35}} , + {{0xad, 0xa0, 0x41, 0xec, 0xc8, 0x4d, 0xb9, 0xd2, 0x6e, 0x96, 0x4e, 0x5b, 0xc5, 0xc2, 0xa0, 0x1b, 0xcf, 0x0c, 0xbf, 0x17, 0x66, 0x57, 0xc1, 0x17, 0x90, 0x45, 0x71, 0xc2, 0xe1, 0x24, 0xeb, 0x27}}}, +{{{0x2c, 0xb9, 0x42, 0xa4, 0xaf, 0x3b, 0x42, 0x0e, 0xc2, 0x0f, 0xf2, 0xea, 0x83, 0xaf, 0x9a, 0x13, 0x17, 0xb0, 0xbd, 0x89, 0x17, 0xe3, 0x72, 0xcb, 0x0e, 0x76, 0x7e, 0x41, 0x63, 0x04, 0x88, 0x71}} , + {{0x75, 0x78, 0x38, 0x86, 0x57, 0xdd, 0x9f, 0xee, 0x54, 0x70, 0x65, 0xbf, 0xf1, 0x2c, 0xe0, 0x39, 0x0d, 0xe3, 0x89, 0xfd, 0x8e, 0x93, 0x4f, 0x43, 0xdc, 0xd5, 0x5b, 0xde, 0xf9, 0x98, 0xe5, 0x7b}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xe7, 0x3b, 0x65, 0x11, 0xdf, 0xb2, 0xf2, 0x63, 0x94, 0x12, 0x6f, 0x5c, 0x9e, 0x77, 0xc1, 0xb6, 0xd8, 0xab, 0x58, 0x7a, 0x1d, 0x95, 0x73, 0xdd, 0xe7, 0xe3, 0x6f, 0xf2, 0x03, 0x1d, 0xdb, 0x76}} , + {{0xae, 0x06, 0x4e, 0x2c, 0x52, 0x1b, 0xbc, 0x5a, 0x5a, 0xa5, 0xbe, 0x27, 0xbd, 0xeb, 0xe1, 0x14, 0x17, 0x68, 0x26, 0x07, 0x03, 0xd1, 0x18, 0x0b, 0xdf, 0xf1, 0x06, 0x5c, 0xa6, 0x1b, 0xb9, 0x24}}}, +{{{0xc5, 0x66, 0x80, 0x13, 0x0e, 0x48, 0x8c, 0x87, 0x31, 0x84, 0xb4, 0x60, 0xed, 0xc5, 0xec, 0xb6, 0xc5, 0x05, 0x33, 0x5f, 0x2f, 0x7d, 0x40, 0xb6, 0x32, 0x1d, 0x38, 0x74, 0x1b, 0xf1, 0x09, 0x3d}} , + {{0xd4, 0x69, 0x82, 0xbc, 0x8d, 0xf8, 0x34, 0x36, 0x75, 0x55, 0x18, 0x55, 0x58, 0x3c, 0x79, 0xaf, 0x26, 0x80, 0xab, 0x9b, 0x95, 0x00, 0xf1, 0xcb, 0xda, 0xc1, 0x9f, 0xf6, 0x2f, 0xa2, 0xf4, 0x45}}}, +{{{0x17, 0xbe, 0xeb, 0x85, 0xed, 0x9e, 0xcd, 0x56, 0xf5, 0x17, 0x45, 0x42, 0xb4, 0x1f, 0x44, 0x4c, 0x05, 0x74, 0x15, 0x47, 0x00, 0xc6, 0x6a, 0x3d, 0x24, 0x09, 0x0d, 0x58, 0xb1, 0x42, 0xd7, 0x04}} , + {{0x8d, 0xbd, 0xa3, 0xc4, 0x06, 0x9b, 0x1f, 0x90, 0x58, 0x60, 0x74, 0xb2, 0x00, 0x3b, 0x3c, 0xd2, 0xda, 0x82, 0xbb, 0x10, 0x90, 0x69, 0x92, 0xa9, 0xb4, 0x30, 0x81, 0xe3, 0x7c, 0xa8, 0x89, 0x45}}}, +{{{0x3f, 0xdc, 0x05, 0xcb, 0x41, 0x3c, 0xc8, 0x23, 0x04, 0x2c, 0x38, 0x99, 0xe3, 0x68, 0x55, 0xf9, 0xd3, 0x32, 0xc7, 0xbf, 0xfa, 0xd4, 0x1b, 0x5d, 0xde, 0xdc, 0x10, 0x42, 0xc0, 0x42, 0xd9, 0x75}} , + {{0x2d, 0xab, 0x35, 0x4e, 0x87, 0xc4, 0x65, 0x97, 0x67, 0x24, 0xa4, 0x47, 0xad, 0x3f, 0x8e, 0xf3, 0xcb, 0x31, 0x17, 0x77, 0xc5, 0xe2, 0xd7, 0x8f, 0x3c, 0xc1, 0xcd, 0x56, 0x48, 0xc1, 0x6c, 0x69}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x14, 0xae, 0x5f, 0x88, 0x7b, 0xa5, 0x90, 0xdf, 0x10, 0xb2, 0x8b, 0x5e, 0x24, 0x17, 0xc3, 0xa3, 0xd4, 0x0f, 0x92, 0x61, 0x1a, 0x19, 0x5a, 0xad, 0x76, 0xbd, 0xd8, 0x1c, 0xdd, 0xe0, 0x12, 0x6d}} , + {{0x8e, 0xbd, 0x70, 0x8f, 0x02, 0xa3, 0x24, 0x4d, 0x5a, 0x67, 0xc4, 0xda, 0xf7, 0x20, 0x0f, 0x81, 0x5b, 0x7a, 0x05, 0x24, 0x67, 0x83, 0x0b, 0x2a, 0x80, 0xe7, 0xfd, 0x74, 0x4b, 0x9e, 0x5c, 0x0d}}}, +{{{0x94, 0xd5, 0x5f, 0x1f, 0xa2, 0xfb, 0xeb, 0xe1, 0x07, 0x34, 0xf8, 0x20, 0xad, 0x81, 0x30, 0x06, 0x2d, 0xa1, 0x81, 0x95, 0x36, 0xcf, 0x11, 0x0b, 0xaf, 0xc1, 0x2b, 0x9a, 0x6c, 0x55, 0xc1, 0x16}} , + {{0x36, 0x4f, 0xf1, 0x5e, 0x74, 0x35, 0x13, 0x28, 0xd7, 0x11, 0xcf, 0xb8, 0xde, 0x93, 0xb3, 0x05, 0xb8, 0xb5, 0x73, 0xe9, 0xeb, 0xad, 0x19, 0x1e, 0x89, 0x0f, 0x8b, 0x15, 0xd5, 0x8c, 0xe3, 0x23}}}, +{{{0x33, 0x79, 0xe7, 0x18, 0xe6, 0x0f, 0x57, 0x93, 0x15, 0xa0, 0xa7, 0xaa, 0xc4, 0xbf, 0x4f, 0x30, 0x74, 0x95, 0x5e, 0x69, 0x4a, 0x5b, 0x45, 0xe4, 0x00, 0xeb, 0x23, 0x74, 0x4c, 0xdf, 0x6b, 0x45}} , + {{0x97, 0x29, 0x6c, 0xc4, 0x42, 0x0b, 0xdd, 0xc0, 0x29, 0x5c, 0x9b, 0x34, 0x97, 0xd0, 0xc7, 0x79, 0x80, 0x63, 0x74, 0xe4, 0x8e, 0x37, 0xb0, 0x2b, 0x7c, 0xe8, 0x68, 0x6c, 0xc3, 0x82, 0x97, 0x57}}}, +{{{0x22, 0xbe, 0x83, 0xb6, 0x4b, 0x80, 0x6b, 0x43, 0x24, 0x5e, 0xef, 0x99, 0x9b, 0xa8, 0xfc, 0x25, 0x8d, 0x3b, 0x03, 0x94, 0x2b, 0x3e, 0xe7, 0x95, 0x76, 0x9b, 0xcc, 0x15, 0xdb, 0x32, 0xe6, 0x66}} , + {{0x84, 0xf0, 0x4a, 0x13, 0xa6, 0xd6, 0xfa, 0x93, 0x46, 0x07, 0xf6, 0x7e, 0x5c, 0x6d, 0x5e, 0xf6, 0xa6, 0xe7, 0x48, 0xf0, 0x06, 0xea, 0xff, 0x90, 0xc1, 0xcc, 0x4c, 0x19, 0x9c, 0x3c, 0x4e, 0x53}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x2a, 0x50, 0xe3, 0x07, 0x15, 0x59, 0xf2, 0x8b, 0x81, 0xf2, 0xf3, 0xd3, 0x6c, 0x99, 0x8c, 0x70, 0x67, 0xec, 0xcc, 0xee, 0x9e, 0x59, 0x45, 0x59, 0x7d, 0x47, 0x75, 0x69, 0xf5, 0x24, 0x93, 0x5d}} , + {{0x6a, 0x4f, 0x1b, 0xbe, 0x6b, 0x30, 0xcf, 0x75, 0x46, 0xe3, 0x7b, 0x9d, 0xfc, 0xcd, 0xd8, 0x5c, 0x1f, 0xb4, 0xc8, 0xe2, 0x24, 0xec, 0x1a, 0x28, 0x05, 0x32, 0x57, 0xfd, 0x3c, 0x5a, 0x98, 0x10}}}, +{{{0xa3, 0xdb, 0xf7, 0x30, 0xd8, 0xc2, 0x9a, 0xe1, 0xd3, 0xce, 0x22, 0xe5, 0x80, 0x1e, 0xd9, 0xe4, 0x1f, 0xab, 0xc0, 0x71, 0x1a, 0x86, 0x0e, 0x27, 0x99, 0x5b, 0xfa, 0x76, 0x99, 0xb0, 0x08, 0x3c}} , + {{0x2a, 0x93, 0xd2, 0x85, 0x1b, 0x6a, 0x5d, 0xa6, 0xee, 0xd1, 0xd1, 0x33, 0xbd, 0x6a, 0x36, 0x73, 0x37, 0x3a, 0x44, 0xb4, 0xec, 0xa9, 0x7a, 0xde, 0x83, 0x40, 0xd7, 0xdf, 0x28, 0xba, 0xa2, 0x30}}}, +{{{0xd3, 0xb5, 0x6d, 0x05, 0x3f, 0x9f, 0xf3, 0x15, 0x8d, 0x7c, 0xca, 0xc9, 0xfc, 0x8a, 0x7c, 0x94, 0xb0, 0x63, 0x36, 0x9b, 0x78, 0xd1, 0x91, 0x1f, 0x93, 0xd8, 0x57, 0x43, 0xde, 0x76, 0xa3, 0x43}} , + {{0x9b, 0x35, 0xe2, 0xa9, 0x3d, 0x32, 0x1e, 0xbb, 0x16, 0x28, 0x70, 0xe9, 0x45, 0x2f, 0x8f, 0x70, 0x7f, 0x08, 0x7e, 0x53, 0xc4, 0x7a, 0xbf, 0xf7, 0xe1, 0xa4, 0x6a, 0xd8, 0xac, 0x64, 0x1b, 0x11}}}, +{{{0xb2, 0xeb, 0x47, 0x46, 0x18, 0x3e, 0x1f, 0x99, 0x0c, 0xcc, 0xf1, 0x2c, 0xe0, 0xe7, 0x8f, 0xe0, 0x01, 0x7e, 0x65, 0xb8, 0x0c, 0xd0, 0xfb, 0xc8, 0xb9, 0x90, 0x98, 0x33, 0x61, 0x3b, 0xd8, 0x27}} , + {{0xa0, 0xbe, 0x72, 0x3a, 0x50, 0x4b, 0x74, 0xab, 0x01, 0xc8, 0x93, 0xc5, 0xe4, 0xc7, 0x08, 0x6c, 0xb4, 0xca, 0xee, 0xeb, 0x8e, 0xd7, 0x4e, 0x26, 0xc6, 0x1d, 0xe2, 0x71, 0xaf, 0x89, 0xa0, 0x2a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x98, 0x0b, 0xe4, 0xde, 0xdb, 0xa8, 0xfa, 0x82, 0x74, 0x06, 0x52, 0x6d, 0x08, 0x52, 0x8a, 0xff, 0x62, 0xc5, 0x6a, 0x44, 0x0f, 0x51, 0x8c, 0x1f, 0x6e, 0xb6, 0xc6, 0x2c, 0x81, 0xd3, 0x76, 0x46}} , + {{0xf4, 0x29, 0x74, 0x2e, 0x80, 0xa7, 0x1a, 0x8f, 0xf6, 0xbd, 0xd6, 0x8e, 0xbf, 0xc1, 0x95, 0x2a, 0xeb, 0xa0, 0x7f, 0x45, 0xa0, 0x50, 0x14, 0x05, 0xb1, 0x57, 0x4c, 0x74, 0xb7, 0xe2, 0x89, 0x7d}}}, +{{{0x07, 0xee, 0xa7, 0xad, 0xb7, 0x09, 0x0b, 0x49, 0x4e, 0xbf, 0xca, 0xe5, 0x21, 0xe6, 0xe6, 0xaf, 0xd5, 0x67, 0xf3, 0xce, 0x7e, 0x7c, 0x93, 0x7b, 0x5a, 0x10, 0x12, 0x0e, 0x6c, 0x06, 0x11, 0x75}} , + {{0xd5, 0xfc, 0x86, 0xa3, 0x3b, 0xa3, 0x3e, 0x0a, 0xfb, 0x0b, 0xf7, 0x36, 0xb1, 0x5b, 0xda, 0x70, 0xb7, 0x00, 0xa7, 0xda, 0x88, 0x8f, 0x84, 0xa8, 0xbc, 0x1c, 0x39, 0xb8, 0x65, 0xf3, 0x4d, 0x60}}}, +{{{0x96, 0x9d, 0x31, 0xf4, 0xa2, 0xbe, 0x81, 0xb9, 0xa5, 0x59, 0x9e, 0xba, 0x07, 0xbe, 0x74, 0x58, 0xd8, 0xeb, 0xc5, 0x9f, 0x3d, 0xd1, 0xf4, 0xae, 0xce, 0x53, 0xdf, 0x4f, 0xc7, 0x2a, 0x89, 0x4d}} , + {{0x29, 0xd8, 0xf2, 0xaa, 0xe9, 0x0e, 0xf7, 0x2e, 0x5f, 0x9d, 0x8a, 0x5b, 0x09, 0xed, 0xc9, 0x24, 0x22, 0xf4, 0x0f, 0x25, 0x8f, 0x1c, 0x84, 0x6e, 0x34, 0x14, 0x6c, 0xea, 0xb3, 0x86, 0x5d, 0x04}}}, +{{{0x07, 0x98, 0x61, 0xe8, 0x6a, 0xd2, 0x81, 0x49, 0x25, 0xd5, 0x5b, 0x18, 0xc7, 0x35, 0x52, 0x51, 0xa4, 0x46, 0xad, 0x18, 0x0d, 0xc9, 0x5f, 0x18, 0x91, 0x3b, 0xb4, 0xc0, 0x60, 0x59, 0x8d, 0x66}} , + {{0x03, 0x1b, 0x79, 0x53, 0x6e, 0x24, 0xae, 0x57, 0xd9, 0x58, 0x09, 0x85, 0x48, 0xa2, 0xd3, 0xb5, 0xe2, 0x4d, 0x11, 0x82, 0xe6, 0x86, 0x3c, 0xe9, 0xb1, 0x00, 0x19, 0xc2, 0x57, 0xf7, 0x66, 0x7a}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x0f, 0xe3, 0x89, 0x03, 0xd7, 0x22, 0x95, 0x9f, 0xca, 0xb4, 0x8d, 0x9e, 0x6d, 0x97, 0xff, 0x8d, 0x21, 0x59, 0x07, 0xef, 0x03, 0x2d, 0x5e, 0xf8, 0x44, 0x46, 0xe7, 0x85, 0x80, 0xc5, 0x89, 0x50}} , + {{0x8b, 0xd8, 0x53, 0x86, 0x24, 0x86, 0x29, 0x52, 0x01, 0xfa, 0x20, 0xc3, 0x4e, 0x95, 0xcb, 0xad, 0x7b, 0x34, 0x94, 0x30, 0xb7, 0x7a, 0xfa, 0x96, 0x41, 0x60, 0x2b, 0xcb, 0x59, 0xb9, 0xca, 0x50}}}, +{{{0xc2, 0x5b, 0x9b, 0x78, 0x23, 0x1b, 0x3a, 0x88, 0x94, 0x5f, 0x0a, 0x9b, 0x98, 0x2b, 0x6e, 0x53, 0x11, 0xf6, 0xff, 0xc6, 0x7d, 0x42, 0xcc, 0x02, 0x80, 0x40, 0x0d, 0x1e, 0xfb, 0xaf, 0x61, 0x07}} , + {{0xb0, 0xe6, 0x2f, 0x81, 0x70, 0xa1, 0x2e, 0x39, 0x04, 0x7c, 0xc4, 0x2c, 0x87, 0x45, 0x4a, 0x5b, 0x69, 0x97, 0xac, 0x6d, 0x2c, 0x10, 0x42, 0x7c, 0x3b, 0x15, 0x70, 0x60, 0x0e, 0x11, 0x6d, 0x3a}}}, +{{{0x9b, 0x18, 0x80, 0x5e, 0xdb, 0x05, 0xbd, 0xc6, 0xb7, 0x3c, 0xc2, 0x40, 0x4d, 0x5d, 0xce, 0x97, 0x8a, 0x34, 0x15, 0xab, 0x28, 0x5d, 0x10, 0xf0, 0x37, 0x0c, 0xcc, 0x16, 0xfa, 0x1f, 0x33, 0x0d}} , + {{0x19, 0xf9, 0x35, 0xaa, 0x59, 0x1a, 0x0c, 0x5c, 0x06, 0xfc, 0x6a, 0x0b, 0x97, 0x53, 0x36, 0xfc, 0x2a, 0xa5, 0x5a, 0x9b, 0x30, 0xef, 0x23, 0xaf, 0x39, 0x5d, 0x9a, 0x6b, 0x75, 0x57, 0x48, 0x0b}}}, +{{{0x26, 0xdc, 0x76, 0x3b, 0xfc, 0xf9, 0x9c, 0x3f, 0x89, 0x0b, 0x62, 0x53, 0xaf, 0x83, 0x01, 0x2e, 0xbc, 0x6a, 0xc6, 0x03, 0x0d, 0x75, 0x2a, 0x0d, 0xe6, 0x94, 0x54, 0xcf, 0xb3, 0xe5, 0x96, 0x25}} , + {{0xfe, 0x82, 0xb1, 0x74, 0x31, 0x8a, 0xa7, 0x6f, 0x56, 0xbd, 0x8d, 0xf4, 0xe0, 0x94, 0x51, 0x59, 0xde, 0x2c, 0x5a, 0xf4, 0x84, 0x6b, 0x4a, 0x88, 0x93, 0xc0, 0x0c, 0x9a, 0xac, 0xa7, 0xa0, 0x68}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x25, 0x0d, 0xd6, 0xc7, 0x23, 0x47, 0x10, 0xad, 0xc7, 0x08, 0x5c, 0x87, 0x87, 0x93, 0x98, 0x18, 0xb8, 0xd3, 0x9c, 0xac, 0x5a, 0x3d, 0xc5, 0x75, 0xf8, 0x49, 0x32, 0x14, 0xcc, 0x51, 0x96, 0x24}} , + {{0x65, 0x9c, 0x5d, 0xf0, 0x37, 0x04, 0xf0, 0x34, 0x69, 0x2a, 0xf0, 0xa5, 0x64, 0xca, 0xde, 0x2b, 0x5b, 0x15, 0x10, 0xd2, 0xab, 0x06, 0xdd, 0xc4, 0xb0, 0xb6, 0x5b, 0xc1, 0x17, 0xdf, 0x8f, 0x02}}}, +{{{0xbd, 0x59, 0x3d, 0xbf, 0x5c, 0x31, 0x44, 0x2c, 0x32, 0x94, 0x04, 0x60, 0x84, 0x0f, 0xad, 0x00, 0xb6, 0x8f, 0xc9, 0x1d, 0xcc, 0x5c, 0xa2, 0x49, 0x0e, 0x50, 0x91, 0x08, 0x9a, 0x43, 0x55, 0x05}} , + {{0x5d, 0x93, 0x55, 0xdf, 0x9b, 0x12, 0x19, 0xec, 0x93, 0x85, 0x42, 0x9e, 0x66, 0x0f, 0x9d, 0xaf, 0x99, 0xaf, 0x26, 0x89, 0xbc, 0x61, 0xfd, 0xff, 0xce, 0x4b, 0xf4, 0x33, 0x95, 0xc9, 0x35, 0x58}}}, +{{{0x12, 0x55, 0xf9, 0xda, 0xcb, 0x44, 0xa7, 0xdc, 0x57, 0xe2, 0xf9, 0x9a, 0xe6, 0x07, 0x23, 0x60, 0x54, 0xa7, 0x39, 0xa5, 0x9b, 0x84, 0x56, 0x6e, 0xaa, 0x8b, 0x8f, 0xb0, 0x2c, 0x87, 0xaf, 0x67}} , + {{0x00, 0xa9, 0x4c, 0xb2, 0x12, 0xf8, 0x32, 0xa8, 0x7a, 0x00, 0x4b, 0x49, 0x32, 0xba, 0x1f, 0x5d, 0x44, 0x8e, 0x44, 0x7a, 0xdc, 0x11, 0xfb, 0x39, 0x08, 0x57, 0x87, 0xa5, 0x12, 0x42, 0x93, 0x0e}}}, +{{{0x17, 0xb4, 0xae, 0x72, 0x59, 0xd0, 0xaa, 0xa8, 0x16, 0x8b, 0x63, 0x11, 0xb3, 0x43, 0x04, 0xda, 0x0c, 0xa8, 0xb7, 0x68, 0xdd, 0x4e, 0x54, 0xe7, 0xaf, 0x5d, 0x5d, 0x05, 0x76, 0x36, 0xec, 0x0d}} , + {{0x6d, 0x7c, 0x82, 0x32, 0x38, 0x55, 0x57, 0x74, 0x5b, 0x7d, 0xc3, 0xc4, 0xfb, 0x06, 0x29, 0xf0, 0x13, 0x55, 0x54, 0xc6, 0xa7, 0xdc, 0x4c, 0x9f, 0x98, 0x49, 0x20, 0xa8, 0xc3, 0x8d, 0xfa, 0x48}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x87, 0x47, 0x9d, 0xe9, 0x25, 0xd5, 0xe3, 0x47, 0x78, 0xdf, 0x85, 0xa7, 0x85, 0x5e, 0x7a, 0x4c, 0x5f, 0x79, 0x1a, 0xf3, 0xa2, 0xb2, 0x28, 0xa0, 0x9c, 0xdd, 0x30, 0x40, 0xd4, 0x38, 0xbd, 0x28}} , + {{0xfc, 0xbb, 0xd5, 0x78, 0x6d, 0x1d, 0xd4, 0x99, 0xb4, 0xaa, 0x44, 0x44, 0x7a, 0x1b, 0xd8, 0xfe, 0xb4, 0x99, 0xb9, 0xcc, 0xe7, 0xc4, 0xd3, 0x3a, 0x73, 0x83, 0x41, 0x5c, 0x40, 0xd7, 0x2d, 0x55}}}, +{{{0x26, 0xe1, 0x7b, 0x5f, 0xe5, 0xdc, 0x3f, 0x7d, 0xa1, 0xa7, 0x26, 0x44, 0x22, 0x23, 0xc0, 0x8f, 0x7d, 0xf1, 0xb5, 0x11, 0x47, 0x7b, 0x19, 0xd4, 0x75, 0x6f, 0x1e, 0xa5, 0x27, 0xfe, 0xc8, 0x0e}} , + {{0xd3, 0x11, 0x3d, 0xab, 0xef, 0x2c, 0xed, 0xb1, 0x3d, 0x7c, 0x32, 0x81, 0x6b, 0xfe, 0xf8, 0x1c, 0x3c, 0x7b, 0xc0, 0x61, 0xdf, 0xb8, 0x75, 0x76, 0x7f, 0xaa, 0xd8, 0x93, 0xaf, 0x3d, 0xe8, 0x3d}}}, +{{{0xfd, 0x5b, 0x4e, 0x8d, 0xb6, 0x7e, 0x82, 0x9b, 0xef, 0xce, 0x04, 0x69, 0x51, 0x52, 0xff, 0xef, 0xa0, 0x52, 0xb5, 0x79, 0x17, 0x5e, 0x2f, 0xde, 0xd6, 0x3c, 0x2d, 0xa0, 0x43, 0xb4, 0x0b, 0x19}} , + {{0xc0, 0x61, 0x48, 0x48, 0x17, 0xf4, 0x9e, 0x18, 0x51, 0x2d, 0xea, 0x2f, 0xf2, 0xf2, 0xe0, 0xa3, 0x14, 0xb7, 0x8b, 0x3a, 0x30, 0xf5, 0x81, 0xc1, 0x5d, 0x71, 0x39, 0x62, 0x55, 0x1f, 0x60, 0x5a}}}, +{{{0xe5, 0x89, 0x8a, 0x76, 0x6c, 0xdb, 0x4d, 0x0a, 0x5b, 0x72, 0x9d, 0x59, 0x6e, 0x63, 0x63, 0x18, 0x7c, 0xe3, 0xfa, 0xe2, 0xdb, 0xa1, 0x8d, 0xf4, 0xa5, 0xd7, 0x16, 0xb2, 0xd0, 0xb3, 0x3f, 0x39}} , + {{0xce, 0x60, 0x09, 0x6c, 0xf5, 0x76, 0x17, 0x24, 0x80, 0x3a, 0x96, 0xc7, 0x94, 0x2e, 0xf7, 0x6b, 0xef, 0xb5, 0x05, 0x96, 0xef, 0xd3, 0x7b, 0x51, 0xda, 0x05, 0x44, 0x67, 0xbc, 0x07, 0x21, 0x4e}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xe9, 0x73, 0x6f, 0x21, 0xb9, 0xde, 0x22, 0x7d, 0xeb, 0x97, 0x31, 0x10, 0xa3, 0xea, 0xe1, 0xc6, 0x37, 0xeb, 0x8f, 0x43, 0x58, 0xde, 0x41, 0x64, 0x0e, 0x3e, 0x07, 0x99, 0x3d, 0xf1, 0xdf, 0x1e}} , + {{0xf8, 0xad, 0x43, 0xc2, 0x17, 0x06, 0xe2, 0xe4, 0xa9, 0x86, 0xcd, 0x18, 0xd7, 0x78, 0xc8, 0x74, 0x66, 0xd2, 0x09, 0x18, 0xa5, 0xf1, 0xca, 0xa6, 0x62, 0x92, 0xc1, 0xcb, 0x00, 0xeb, 0x42, 0x2e}}}, +{{{0x7b, 0x34, 0x24, 0x4c, 0xcf, 0x38, 0xe5, 0x6c, 0x0a, 0x01, 0x2c, 0x22, 0x0b, 0x24, 0x38, 0xad, 0x24, 0x7e, 0x19, 0xf0, 0x6c, 0xf9, 0x31, 0xf4, 0x35, 0x11, 0xf6, 0x46, 0x33, 0x3a, 0x23, 0x59}} , + {{0x20, 0x0b, 0xa1, 0x08, 0x19, 0xad, 0x39, 0x54, 0xea, 0x3e, 0x23, 0x09, 0xb6, 0xe2, 0xd2, 0xbc, 0x4d, 0xfc, 0x9c, 0xf0, 0x13, 0x16, 0x22, 0x3f, 0xb9, 0xd2, 0x11, 0x86, 0x90, 0x55, 0xce, 0x3c}}}, +{{{0xc4, 0x0b, 0x4b, 0x62, 0x99, 0x37, 0x84, 0x3f, 0x74, 0xa2, 0xf9, 0xce, 0xe2, 0x0b, 0x0f, 0x2a, 0x3d, 0xa3, 0xe3, 0xdb, 0x5a, 0x9d, 0x93, 0xcc, 0xa5, 0xef, 0x82, 0x91, 0x1d, 0xe6, 0x6c, 0x68}} , + {{0xa3, 0x64, 0x17, 0x9b, 0x8b, 0xc8, 0x3a, 0x61, 0xe6, 0x9d, 0xc6, 0xed, 0x7b, 0x03, 0x52, 0x26, 0x9d, 0x3a, 0xb3, 0x13, 0xcc, 0x8a, 0xfd, 0x2c, 0x1a, 0x1d, 0xed, 0x13, 0xd0, 0x55, 0x57, 0x0e}}}, +{{{0x1a, 0xea, 0xbf, 0xfd, 0x4a, 0x3c, 0x8e, 0xec, 0x29, 0x7e, 0x77, 0x77, 0x12, 0x99, 0xd7, 0x84, 0xf9, 0x55, 0x7f, 0xf1, 0x8b, 0xb4, 0xd2, 0x95, 0xa3, 0x8d, 0xf0, 0x8a, 0xa7, 0xeb, 0x82, 0x4b}} , + {{0x2c, 0x28, 0xf4, 0x3a, 0xf6, 0xde, 0x0a, 0xe0, 0x41, 0x44, 0x23, 0xf8, 0x3f, 0x03, 0x64, 0x9f, 0xc3, 0x55, 0x4c, 0xc6, 0xc1, 0x94, 0x1c, 0x24, 0x5d, 0x5f, 0x92, 0x45, 0x96, 0x57, 0x37, 0x14}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xc1, 0xcd, 0x90, 0x66, 0xb9, 0x76, 0xa0, 0x5b, 0xa5, 0x85, 0x75, 0x23, 0xf9, 0x89, 0xa5, 0x82, 0xb2, 0x6f, 0xb1, 0xeb, 0xc4, 0x69, 0x6f, 0x18, 0x5a, 0xed, 0x94, 0x3d, 0x9d, 0xd9, 0x2c, 0x1a}} , + {{0x35, 0xb0, 0xe6, 0x73, 0x06, 0xb7, 0x37, 0xe0, 0xf8, 0xb0, 0x22, 0xe8, 0xd2, 0xed, 0x0b, 0xef, 0xe6, 0xc6, 0x5a, 0x99, 0x9e, 0x1a, 0x9f, 0x04, 0x97, 0xe4, 0x4d, 0x0b, 0xbe, 0xba, 0x44, 0x40}}}, +{{{0xc1, 0x56, 0x96, 0x91, 0x5f, 0x1f, 0xbb, 0x54, 0x6f, 0x88, 0x89, 0x0a, 0xb2, 0xd6, 0x41, 0x42, 0x6a, 0x82, 0xee, 0x14, 0xaa, 0x76, 0x30, 0x65, 0x0f, 0x67, 0x39, 0xa6, 0x51, 0x7c, 0x49, 0x24}} , + {{0x35, 0xa3, 0x78, 0xd1, 0x11, 0x0f, 0x75, 0xd3, 0x70, 0x46, 0xdb, 0x20, 0x51, 0xcb, 0x92, 0x80, 0x54, 0x10, 0x74, 0x36, 0x86, 0xa9, 0xd7, 0xa3, 0x08, 0x78, 0xf1, 0x01, 0x29, 0xf8, 0x80, 0x3b}}}, +{{{0xdb, 0xa7, 0x9d, 0x9d, 0xbf, 0xa0, 0xcc, 0xed, 0x53, 0xa2, 0xa2, 0x19, 0x39, 0x48, 0x83, 0x19, 0x37, 0x58, 0xd1, 0x04, 0x28, 0x40, 0xf7, 0x8a, 0xc2, 0x08, 0xb7, 0xa5, 0x42, 0xcf, 0x53, 0x4c}} , + {{0xa7, 0xbb, 0xf6, 0x8e, 0xad, 0xdd, 0xf7, 0x90, 0xdd, 0x5f, 0x93, 0x89, 0xae, 0x04, 0x37, 0xe6, 0x9a, 0xb7, 0xe8, 0xc0, 0xdf, 0x16, 0x2a, 0xbf, 0xc4, 0x3a, 0x3c, 0x41, 0xd5, 0x89, 0x72, 0x5a}}}, +{{{0x1f, 0x96, 0xff, 0x34, 0x2c, 0x13, 0x21, 0xcb, 0x0a, 0x89, 0x85, 0xbe, 0xb3, 0x70, 0x9e, 0x1e, 0xde, 0x97, 0xaf, 0x96, 0x30, 0xf7, 0x48, 0x89, 0x40, 0x8d, 0x07, 0xf1, 0x25, 0xf0, 0x30, 0x58}} , + {{0x1e, 0xd4, 0x93, 0x57, 0xe2, 0x17, 0xe7, 0x9d, 0xab, 0x3c, 0x55, 0x03, 0x82, 0x2f, 0x2b, 0xdb, 0x56, 0x1e, 0x30, 0x2e, 0x24, 0x47, 0x6e, 0xe6, 0xff, 0x33, 0x24, 0x2c, 0x75, 0x51, 0xd4, 0x67}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0x2b, 0x06, 0xd9, 0xa1, 0x5d, 0xe1, 0xf4, 0xd1, 0x1e, 0x3c, 0x9a, 0xc6, 0x29, 0x2b, 0x13, 0x13, 0x78, 0xc0, 0xd8, 0x16, 0x17, 0x2d, 0x9e, 0xa9, 0xc9, 0x79, 0x57, 0xab, 0x24, 0x91, 0x92, 0x19}} , + {{0x69, 0xfb, 0xa1, 0x9c, 0xa6, 0x75, 0x49, 0x7d, 0x60, 0x73, 0x40, 0x42, 0xc4, 0x13, 0x0a, 0x95, 0x79, 0x1e, 0x04, 0x83, 0x94, 0x99, 0x9b, 0x1e, 0x0c, 0xe8, 0x1f, 0x54, 0xef, 0xcb, 0xc0, 0x52}}}, +{{{0x14, 0x89, 0x73, 0xa1, 0x37, 0x87, 0x6a, 0x7a, 0xcf, 0x1d, 0xd9, 0x2e, 0x1a, 0x67, 0xed, 0x74, 0xc0, 0xf0, 0x9c, 0x33, 0xdd, 0xdf, 0x08, 0xbf, 0x7b, 0xd1, 0x66, 0xda, 0xe6, 0xc9, 0x49, 0x08}} , + {{0xe9, 0xdd, 0x5e, 0x55, 0xb0, 0x0a, 0xde, 0x21, 0x4c, 0x5a, 0x2e, 0xd4, 0x80, 0x3a, 0x57, 0x92, 0x7a, 0xf1, 0xc4, 0x2c, 0x40, 0xaf, 0x2f, 0xc9, 0x92, 0x03, 0xe5, 0x5a, 0xbc, 0xdc, 0xf4, 0x09}}}, +{{{0xf3, 0xe1, 0x2b, 0x7c, 0x05, 0x86, 0x80, 0x93, 0x4a, 0xad, 0xb4, 0x8f, 0x7e, 0x99, 0x0c, 0xfd, 0xcd, 0xef, 0xd1, 0xff, 0x2c, 0x69, 0x34, 0x13, 0x41, 0x64, 0xcf, 0x3b, 0xd0, 0x90, 0x09, 0x1e}} , + {{0x9d, 0x45, 0xd6, 0x80, 0xe6, 0x45, 0xaa, 0xf4, 0x15, 0xaa, 0x5c, 0x34, 0x87, 0x99, 0xa2, 0x8c, 0x26, 0x84, 0x62, 0x7d, 0xb6, 0x29, 0xc0, 0x52, 0xea, 0xf5, 0x81, 0x18, 0x0f, 0x35, 0xa9, 0x0e}}}, +{{{0xe7, 0x20, 0x72, 0x7c, 0x6d, 0x94, 0x5f, 0x52, 0x44, 0x54, 0xe3, 0xf1, 0xb2, 0xb0, 0x36, 0x46, 0x0f, 0xae, 0x92, 0xe8, 0x70, 0x9d, 0x6e, 0x79, 0xb1, 0xad, 0x37, 0xa9, 0x5f, 0xc0, 0xde, 0x03}} , + {{0x15, 0x55, 0x37, 0xc6, 0x1c, 0x27, 0x1c, 0x6d, 0x14, 0x4f, 0xca, 0xa4, 0xc4, 0x88, 0x25, 0x46, 0x39, 0xfc, 0x5a, 0xe5, 0xfe, 0x29, 0x11, 0x69, 0xf5, 0x72, 0x84, 0x4d, 0x78, 0x9f, 0x94, 0x15}}}, +{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, +{{{0xec, 0xd3, 0xff, 0x57, 0x0b, 0xb0, 0xb2, 0xdc, 0xf8, 0x4f, 0xe2, 0x12, 0xd5, 0x36, 0xbe, 0x6b, 0x09, 0x43, 0x6d, 0xa3, 0x4d, 0x90, 0x2d, 0xb8, 0x74, 0xe8, 0x71, 0x45, 0x19, 0x8b, 0x0c, 0x6a}} , + {{0xb8, 0x42, 0x1c, 0x03, 0xad, 0x2c, 0x03, 0x8e, 0xac, 0xd7, 0x98, 0x29, 0x13, 0xc6, 0x02, 0x29, 0xb5, 0xd4, 0xe7, 0xcf, 0xcc, 0x8b, 0x83, 0xec, 0x35, 0xc7, 0x9c, 0x74, 0xb7, 0xad, 0x85, 0x5f}}}, +{{{0x78, 0x84, 0xe1, 0x56, 0x45, 0x69, 0x68, 0x5a, 0x4f, 0xb8, 0xb1, 0x29, 0xff, 0x33, 0x03, 0x31, 0xb7, 0xcb, 0x96, 0x25, 0xe6, 0xe6, 0x41, 0x98, 0x1a, 0xbb, 0x03, 0x56, 0xf2, 0xb2, 0x91, 0x34}} , + {{0x2c, 0x6c, 0xf7, 0x66, 0xa4, 0x62, 0x6b, 0x39, 0xb3, 0xba, 0x65, 0xd3, 0x1c, 0xf8, 0x11, 0xaa, 0xbe, 0xdc, 0x80, 0x59, 0x87, 0xf5, 0x7b, 0xe5, 0xe3, 0xb3, 0x3e, 0x39, 0xda, 0xbe, 0x88, 0x09}}}, +{{{0x8b, 0xf1, 0xa0, 0xf5, 0xdc, 0x29, 0xb4, 0xe2, 0x07, 0xc6, 0x7a, 0x00, 0xd0, 0x89, 0x17, 0x51, 0xd4, 0xbb, 0xd4, 0x22, 0xea, 0x7e, 0x7d, 0x7c, 0x24, 0xea, 0xf2, 0xe8, 0x22, 0x12, 0x95, 0x06}} , + {{0xda, 0x7c, 0xa4, 0x0c, 0xf4, 0xba, 0x6e, 0xe1, 0x89, 0xb5, 0x59, 0xca, 0xf1, 0xc0, 0x29, 0x36, 0x09, 0x44, 0xe2, 0x7f, 0xd1, 0x63, 0x15, 0x99, 0xea, 0x25, 0xcf, 0x0c, 0x9d, 0xc0, 0x44, 0x6f}}}, +{{{0x1d, 0x86, 0x4e, 0xcf, 0xf7, 0x37, 0x10, 0x25, 0x8f, 0x12, 0xfb, 0x19, 0xfb, 0xe0, 0xed, 0x10, 0xc8, 0xe2, 0xf5, 0x75, 0xb1, 0x33, 0xc0, 0x96, 0x0d, 0xfb, 0x15, 0x6c, 0x0d, 0x07, 0x5f, 0x05}} , + {{0x69, 0x3e, 0x47, 0x97, 0x2c, 0xaf, 0x52, 0x7c, 0x78, 0x83, 0xad, 0x1b, 0x39, 0x82, 0x2f, 0x02, 0x6f, 0x47, 0xdb, 0x2a, 0xb0, 0xe1, 0x91, 0x99, 0x55, 0xb8, 0x99, 0x3a, 0xa0, 0x44, 0x11, 0x51}}} diff --git a/libssh/src/getpass.c b/libssh/src/getpass.c index 0ffb955d..c36f263b 100644 --- a/libssh/src/getpass.c +++ b/libssh/src/getpass.c @@ -3,7 +3,7 @@ * * This file is part of the SSH Library * - * Copyright (c) 2011 by Andreas Schneider + * Copyright (c) 2011-2013 by Andreas Schneider * * 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 diff --git a/libssh/src/gssapi.c b/libssh/src/gssapi.c index c92c66cb..099294ee 100644 --- a/libssh/src/gssapi.c +++ b/libssh/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'; @@ -308,14 +311,11 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){ return SSH_PACKET_USED; } if (ssh_string_len(out_token) != 0){ - rc = buffer_add_u8(session->out_buffer, - SSH2_MSG_USERAUTH_GSSAPI_TOKEN); - if (rc < 0) { - ssh_set_error_oom(session); - return SSH_PACKET_USED; - } - rc = buffer_add_ssh_string(session->out_buffer, out_token); - if (rc < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bS", + SSH2_MSG_USERAUTH_GSSAPI_TOKEN, + out_token); + if (rc != SSH_OK) { ssh_set_error_oom(session); return SSH_PACKET_USED; } @@ -335,14 +335,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; @@ -353,12 +353,12 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){ hexa = ssh_get_hexa(output_token.value, output_token.length); SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa); SAFE_FREE(hexa); - token = ssh_string_new(output_token.length); - ssh_string_fill(token, output_token.value, output_token.length); - buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); - buffer_add_ssh_string(session->out_buffer,token); + ssh_buffer_pack(session->out_buffer, + "bdP", + SSH2_MSG_USERAUTH_GSSAPI_TOKEN, + output_token.length, + (size_t)output_token.length, output_token.value); packet_send(session); - ssh_string_free(token); } if(maj_stat == GSS_S_COMPLETE){ session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC; @@ -370,69 +370,24 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){ static ssh_buffer ssh_gssapi_build_mic(ssh_session session){ ssh_buffer mic_buffer; - ssh_string str; int rc; - str = ssh_string_new(session->current_crypto->digest_len); - if (str == NULL) { - return NULL; - } - ssh_string_fill(str, session->current_crypto->session_id, - session->current_crypto->digest_len); - mic_buffer = ssh_buffer_new(); if (mic_buffer == NULL) { - ssh_string_free(str); + ssh_set_error_oom(session); return NULL; } - rc = buffer_add_ssh_string(mic_buffer, str); - ssh_string_free(str); - if (rc < 0) { - ssh_buffer_free(mic_buffer); - return NULL; - } - - rc = buffer_add_u8(mic_buffer, SSH2_MSG_USERAUTH_REQUEST); - if (rc < 0) { - ssh_buffer_free(mic_buffer); - return NULL; - } - - str = ssh_string_from_char(session->gssapi->user); - if (str == NULL) { - ssh_buffer_free(mic_buffer); - return NULL; - } - - rc = buffer_add_ssh_string(mic_buffer, str); - ssh_string_free(str); - if (rc < 0) { - ssh_buffer_free(mic_buffer); - return NULL; - } - - str = ssh_string_from_char("ssh-connection"); - if (str == NULL) { - ssh_buffer_free(mic_buffer); - return NULL; - } - rc = buffer_add_ssh_string(mic_buffer, str); - ssh_string_free(str); - if (rc < 0) { - ssh_buffer_free(mic_buffer); - return NULL; - } - - str = ssh_string_from_char("gssapi-with-mic"); - if (str == NULL) { - ssh_buffer_free(mic_buffer); - return NULL; - } - - rc = buffer_add_ssh_string(mic_buffer, str); - ssh_string_free(str); - if (rc < 0) { + rc = ssh_buffer_pack(mic_buffer, + "dPbsss", + session->current_crypto->digest_len, + (size_t)session->current_crypto->digest_len, session->current_crypto->session_id, + SSH2_MSG_USERAUTH_REQUEST, + session->gssapi->user, + "ssh-connection", + "gssapi-with-mic"); + if (rc != SSH_OK) { + ssh_set_error_oom(session); ssh_buffer_free(mic_buffer); return NULL; } @@ -484,8 +439,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 +491,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,49 +515,20 @@ 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; int i; - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); - if (rc < 0) { - goto fail; - } - /* username */ - str = ssh_string_from_char(session->opts.username); - if (str == NULL) { - goto fail; - } - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - /* service */ - str = ssh_string_from_char("ssh-connection"); - if (str == NULL) { - goto fail; - } - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - /* method */ - str = ssh_string_from_char("gssapi-with-mic"); - if (str == NULL) { - goto fail; - } - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto fail; - } - rc = buffer_add_u32(session->out_buffer, htonl(n_oid)); - if (rc < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bsssd", + SSH2_MSG_USERAUTH_REQUEST, + session->opts.username, + "ssh-connection", + "gssapi-with-mic", + n_oid); + + if (rc != SSH_OK) { + ssh_set_error_oom(session); goto fail; } @@ -612,92 +542,79 @@ static int ssh_gssapi_send_auth_mic(ssh_session session, ssh_string *oid_set, in session->auth_state = SSH_AUTH_STATE_GSSAPI_REQUEST_SENT; return packet_send(session); fail: - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); 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; icount; ++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 +630,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; ielements[i].length + 2); @@ -769,15 +720,10 @@ 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 +737,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; @@ -824,15 +766,14 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){ hexa = ssh_get_hexa(output_token.value, output_token.length); SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa); SAFE_FREE(hexa); - token = ssh_string_new(output_token.length); - ssh_string_fill(token, output_token.value, output_token.length); - buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); - buffer_add_ssh_string(session->out_buffer,token); + ssh_buffer_pack(session->out_buffer, + "bdP", + SSH2_MSG_USERAUTH_GSSAPI_TOKEN, + output_token.length, + (size_t)output_token.length, output_token.value); packet_send(session); - ssh_string_free(token); session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN; } - session->gssapi->client.oid = oid; return SSH_PACKET_USED; } @@ -856,31 +797,21 @@ 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; } - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_MIC); - if (rc < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bdP", + SSH2_MSG_USERAUTH_GSSAPI_MIC, + mic_token_buf.length, + (size_t)mic_token_buf.length, mic_token_buf.value); + if (rc != SSH_OK) { ssh_buffer_free(mic_buffer); ssh_set_error_oom(session); return SSH_ERROR; } - rc = buffer_add_u32(session->out_buffer, htonl(mic_token_buf.length)); - if (rc < 0) { - ssh_buffer_free(mic_buffer); - ssh_set_error_oom(session); - return SSH_ERROR; - } - - rc = buffer_add_data(session->out_buffer, mic_token_buf.value, mic_token_buf.length); - ssh_buffer_free(mic_buffer); - if (rc < 0) { - ssh_set_error_oom(session); - return SSH_ERROR; - } - return packet_send(session); } @@ -889,8 +820,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 +839,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); @@ -932,12 +861,12 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){ hexa = ssh_get_hexa(output_token.value, output_token.length); SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa); SAFE_FREE(hexa); - token = ssh_string_new(output_token.length); - ssh_string_fill(token, output_token.value, output_token.length); - buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_TOKEN); - buffer_add_ssh_string(session->out_buffer,token); + ssh_buffer_pack(session->out_buffer, + "bdP", + SSH2_MSG_USERAUTH_GSSAPI_TOKEN, + output_token.length, + (size_t)output_token.length, output_token.value); packet_send(session); - ssh_string_free(token); } if(maj_stat == GSS_S_COMPLETE){ session->auth_state = SSH_AUTH_STATE_NONE; diff --git a/libssh/src/gzip.c b/libssh/src/gzip.c index 339217d4..ca190bc2 100644 --- a/libssh/src/gzip.c +++ b/libssh/src/gzip.c @@ -4,7 +4,7 @@ * This file is part of the SSH Library * * Copyright (c) 2003 by Aris Adamantiadis - * Copyright (c) 2009 by Andreas Schneider + * Copyright (c) 2009 by Andreas Schneider * * 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 @@ -90,7 +90,7 @@ static ssh_buffer gzip_compress(ssh_session session,ssh_buffer source,int level) return NULL; } len = BLOCKSIZE - zout->avail_out; - if (buffer_add_data(dest, out_buf, len) < 0) { + if (ssh_buffer_add_data(dest, out_buf, len) < 0) { ssh_buffer_free(dest); return NULL; } @@ -108,12 +108,12 @@ int compress_buffer(ssh_session session, ssh_buffer buf) { return -1; } - if (buffer_reinit(buf) < 0) { + if (ssh_buffer_reinit(buf) < 0) { ssh_buffer_free(dest); return -1; } - if (buffer_add_data(buf, buffer_get_rest(dest), buffer_get_rest_len(dest)) < 0) { + if (ssh_buffer_add_data(buf, buffer_get_rest(dest), buffer_get_rest_len(dest)) < 0) { ssh_buffer_free(dest); return -1; } @@ -181,7 +181,7 @@ static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t } len = BLOCKSIZE - zin->avail_out; - if (buffer_add_data(dest,out_buf,len) < 0) { + if (ssh_buffer_add_data(dest,out_buf,len) < 0) { ssh_buffer_free(dest); return NULL; } @@ -204,12 +204,12 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen){ return -1; } - if (buffer_reinit(buf) < 0) { + if (ssh_buffer_reinit(buf) < 0) { ssh_buffer_free(dest); return -1; } - if (buffer_add_data(buf, buffer_get_rest(dest), buffer_get_rest_len(dest)) < 0) { + if (ssh_buffer_add_data(buf, buffer_get_rest(dest), buffer_get_rest_len(dest)) < 0) { ssh_buffer_free(dest); return -1; } diff --git a/libssh/src/kex.c b/libssh/src/kex.c index 7cd404f7..f1a1b566 100644 --- a/libssh/src/kex.c +++ b/libssh/src/kex.c @@ -35,6 +35,7 @@ #include "libssh/ssh2.h" #include "libssh/string.h" #include "libssh/curve25519.h" +#include "libssh/knownhosts.h" #ifdef HAVE_LIBGCRYPT # define BLOWFISH "blowfish-cbc," @@ -72,7 +73,7 @@ #ifdef HAVE_ECDH #define ECDH "ecdh-sha2-nistp256," -#define HOSTKEYS "ecdsa-sha2-nistp256,ssh-rsa,ssh-dss" +#define HOSTKEYS "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss" #else #define HOSTKEYS "ssh-rsa,ssh-dss" #define ECDH "" @@ -87,8 +88,8 @@ static const char *default_methods[] = { HOSTKEYS, AES BLOWFISH DES, AES BLOWFISH DES, - "hmac-sha1", - "hmac-sha1", + "hmac-sha1,hmac-sha2-256,hmac-sha2-512", + "hmac-sha1,hmac-sha2-256,hmac-sha2-512", "none", "none", "", @@ -102,8 +103,8 @@ static const char *supported_methods[] = { HOSTKEYS, AES BLOWFISH DES, AES BLOWFISH DES, - "hmac-sha1", - "hmac-sha1", + "hmac-sha1,hmac-sha2-256,hmac-sha2-512", + "hmac-sha1,hmac-sha2-256,hmac-sha2-512", ZLIB, ZLIB, "", @@ -274,87 +275,180 @@ char *ssh_find_matching(const char *available_d, const char *preferred_d){ return NULL; } +/** + * @internal + * @brief returns whether the first client key exchange algorithm matches + * the first server key exchange algorithm + * @returns whether the first client key exchange algorithm matches + * the first server key exchange algorithm + */ +static int is_first_kex_packet_follows_guess_wrong(const char *client_kex, + const char *server_kex) { + int is_wrong = 1; + char **server_kex_tokens = NULL; + char **client_kex_tokens = NULL; + + if ((client_kex == NULL) || (server_kex == NULL)) { + goto out; + } + + client_kex_tokens = tokenize(client_kex); + + if (client_kex_tokens == NULL) { + goto out; + } + + if (client_kex_tokens[0] == NULL) { + goto freeout; + } + + server_kex_tokens = tokenize(server_kex); + if (server_kex_tokens == NULL) { + goto freeout; + } + + is_wrong = (strcmp(client_kex_tokens[0], server_kex_tokens[0]) != 0); + + SAFE_FREE(server_kex_tokens[0]); + SAFE_FREE(server_kex_tokens); +freeout: + SAFE_FREE(client_kex_tokens[0]); + SAFE_FREE(client_kex_tokens); +out: + return is_wrong; +} + SSH_PACKET_CALLBACK(ssh_packet_kexinit){ - int server_kex=session->server; - ssh_string str = NULL; - char *strings[KEX_METHODS_SIZE]; - int i; + int i; + int server_kex=session->server; + ssh_string str = NULL; + char *strings[KEX_METHODS_SIZE]; + int rc = SSH_ERROR; - (void)type; - (void)user; - memset(strings, 0, sizeof(strings)); - if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED){ - SSH_LOG(SSH_LOG_WARNING, "Other side initiating key re-exchange"); - } else if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){ - ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state"); - goto error; - } - if (server_kex) { - if (buffer_get_data(packet,session->next_crypto->client_kex.cookie,16) != 16) { - ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet"); + uint8_t first_kex_packet_follows = 0; + uint32_t kexinit_reserved = 0; + + (void)type; + (void)user; + + memset(strings, 0, sizeof(strings)); + if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED){ + SSH_LOG(SSH_LOG_WARNING, "Other side initiating key re-exchange"); + } else if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){ + ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state"); goto error; - } - - if (hashbufin_add_cookie(session, session->next_crypto->client_kex.cookie) < 0) { - ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed"); - goto error; - } - } else { - if (buffer_get_data(packet,session->next_crypto->server_kex.cookie,16) != 16) { - ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet"); - goto error; - } - - if (hashbufin_add_cookie(session, session->next_crypto->server_kex.cookie) < 0) { - ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed"); - goto error; - } - } - - for (i = 0; i < KEX_METHODS_SIZE; i++) { - str = buffer_get_ssh_string(packet); - if (str == NULL) { - break; } - if (buffer_add_ssh_string(session->in_hashbuf, str) < 0) { - ssh_set_error(session, SSH_FATAL, "Error adding string in hash buffer"); - goto error; + if (server_kex) { + rc = buffer_get_data(packet,session->next_crypto->client_kex.cookie, 16); + if (rc != 16) { + ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet"); + goto error; + } + + rc = hashbufin_add_cookie(session, session->next_crypto->client_kex.cookie); + if (rc < 0) { + ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed"); + goto error; + } + } else { + rc = buffer_get_data(packet,session->next_crypto->server_kex.cookie, 16); + if (rc != 16) { + ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet"); + goto error; + } + + rc = hashbufin_add_cookie(session, session->next_crypto->server_kex.cookie); + if (rc < 0) { + ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed"); + goto error; + } } - strings[i] = ssh_string_to_char(str); - if (strings[i] == NULL) { - ssh_set_error_oom(session); - goto error; - } - ssh_string_free(str); - str = NULL; - } + for (i = 0; i < KEX_METHODS_SIZE; i++) { + str = buffer_get_ssh_string(packet); + if (str == NULL) { + break; + } - /* copy the server kex info into an array of strings */ - if (server_kex) { - for (i = 0; i < SSH_KEX_METHODS; i++) { - session->next_crypto->client_kex.methods[i] = strings[i]; - } - } else { /* client */ - for (i = 0; i < SSH_KEX_METHODS; i++) { - session->next_crypto->server_kex.methods[i] = strings[i]; - } - } + rc = buffer_add_ssh_string(session->in_hashbuf, str); + if (rc < 0) { + ssh_set_error(session, SSH_FATAL, "Error adding string in hash buffer"); + goto error; + } + + strings[i] = ssh_string_to_char(str); + if (strings[i] == NULL) { + ssh_set_error_oom(session); + goto error; + } + ssh_string_free(str); + str = NULL; + } + + /* copy the server kex info into an array of strings */ + if (server_kex) { + for (i = 0; i < SSH_KEX_METHODS; i++) { + session->next_crypto->client_kex.methods[i] = strings[i]; + } + } else { /* client */ + for (i = 0; i < SSH_KEX_METHODS; i++) { + session->next_crypto->server_kex.methods[i] = strings[i]; + } + } + + /* + * Handle the two final fields for the KEXINIT message (RFC 4253 7.1): + * + * boolean first_kex_packet_follows + * uint32 0 (reserved for future extension) + * + * Notably if clients set 'first_kex_packet_follows', it is expected + * that its value is included when computing the session ID (see + * 'make_sessionid'). + */ + if (server_kex) { + rc = buffer_get_u8(packet, &first_kex_packet_follows); + if (rc != 1) { + goto error; + } + + rc = buffer_add_u8(session->in_hashbuf, first_kex_packet_follows); + if (rc < 0) { + goto error; + } + + rc = buffer_add_u32(session->in_hashbuf, kexinit_reserved); + if (rc < 0) { + goto error; + } + + /* + * Remember whether 'first_kex_packet_follows' was set and the client + * guess was wrong: in this case the next SSH_MSG_KEXDH_INIT message + * must be ignored. + */ + if (first_kex_packet_follows) { + session->first_kex_follows_guess_wrong = + is_first_kex_packet_follows_guess_wrong(session->next_crypto->client_kex.methods[SSH_KEX], + session->next_crypto->server_kex.methods[SSH_KEX]); + } + } + + session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED; + session->dh_handshake_state = DH_STATE_INIT; + session->ssh_connection_callback(session); + return SSH_PACKET_USED; - session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED; - session->dh_handshake_state=DH_STATE_INIT; - session->ssh_connection_callback(session); - return SSH_PACKET_USED; error: - ssh_string_free(str); - for (i = 0; i < SSH_KEX_METHODS; i++) { - SAFE_FREE(strings[i]); - } + ssh_string_free(str); + for (i = 0; i < SSH_KEX_METHODS; i++) { + SAFE_FREE(strings[i]); + } - session->session_state = SSH_SESSION_STATE_ERROR; + session->session_state = SSH_SESSION_STATE_ERROR; - return SSH_PACKET_USED; + return SSH_PACKET_USED; } void ssh_list_kex(struct ssh_kex_struct *kex) { @@ -373,6 +467,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. @@ -385,6 +526,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) @@ -434,14 +582,15 @@ int ssh_send_kex(ssh_session session, int server_kex) { &session->next_crypto->client_kex); ssh_string str = NULL; int i; + int rc; - if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bP", + SSH2_MSG_KEXINIT, + 16, + kex->cookie); /* cookie */ + if (rc != SSH_OK) goto error; - } - if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) { - goto error; - } - if (hashbufout_add_cookie(session) < 0) { goto error; } @@ -464,10 +613,11 @@ int ssh_send_kex(ssh_session session, int server_kex) { str = NULL; } - if (buffer_add_u8(session->out_buffer, 0) < 0) { - goto error; - } - if (buffer_add_u32(session->out_buffer, 0) < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bd", + 0, + 0); + if (rc != SSH_OK) { goto error; } @@ -477,8 +627,8 @@ int ssh_send_kex(ssh_session session, int server_kex) { return 0; error: - buffer_reinit(session->out_buffer); - buffer_reinit(session->out_hashbuf); + ssh_buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_hashbuf); ssh_string_free(str); return -1; diff --git a/libssh/src/kex1.c b/libssh/src/kex1.c index 22899429..758054f8 100644 --- a/libssh/src/kex1.c +++ b/libssh/src/kex1.c @@ -417,7 +417,7 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){ if (buffer_add_u8(session->out_buffer, support_3DES ? SSH_CIPHER_3DES : SSH_CIPHER_DES) < 0) { goto error; } - if (buffer_add_data(session->out_buffer, session->next_crypto->server_kex.cookie, 8) < 0) { + if (ssh_buffer_add_data(session->out_buffer, session->next_crypto->server_kex.cookie, 8) < 0) { goto error; } @@ -431,10 +431,10 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){ bits, ssh_string_len(enc_session)); bits = htons(bits); /* the encrypted mpint */ - if (buffer_add_data(session->out_buffer, &bits, sizeof(uint16_t)) < 0) { + if (ssh_buffer_add_data(session->out_buffer, &bits, sizeof(uint16_t)) < 0) { goto error; } - if (buffer_add_data(session->out_buffer, ssh_string_data(enc_session), + if (ssh_buffer_add_data(session->out_buffer, ssh_string_data(enc_session), ssh_string_len(enc_session)) < 0) { goto error; } diff --git a/libssh/src/known_hosts.c b/libssh/src/known_hosts.c index 6e9eb915..8c05c8de 100644 --- a/libssh/src/known_hosts.c +++ b/libssh/src/known_hosts.c @@ -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 + * Copyright (c) 2009 by Andreas Schneider * * 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" @@ -239,9 +239,9 @@ static int check_public_key(ssh_session session, char **tokens) { /* TODO: fix the hardcoding */ tmpstring->size = htonl(len); #ifdef HAVE_LIBGCRYPT - bignum_bn2bin(tmpbn, len, string_data(tmpstring)); + bignum_bn2bin(tmpbn, len, ssh_string_data(tmpstring)); #elif defined HAVE_LIBCRYPTO - bignum_bn2bin(tmpbn, string_data(tmpstring)); + bignum_bn2bin(tmpbn, ssh_string_data(tmpstring)); #endif bignum_free(tmpbn); if (buffer_add_ssh_string(pubkey_buffer, tmpstring) < 0) { @@ -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= KNOWNHOSTS_MAXTYPES-1){ + tokens_free(tokens); + break; + } + } + } + tokens_free(tokens); + } while (1); + + array[i]=NULL; + SAFE_FREE(host); + SAFE_FREE(hostport); + if (file != NULL) { + fclose(file); + } + + /* Return the current state at end of file */ + return array; +} + /** @} */ /* vim: set ts=4 sw=4 et cindent: */ diff --git a/libssh/src/legacy.c b/libssh/src/legacy.c index 6e7bfffc..15f287a6 100644 --- a/libssh/src/legacy.c +++ b/libssh/src/legacy.c @@ -163,7 +163,7 @@ int channel_change_pty_size(ssh_channel channel,int cols,int rows){ } ssh_channel channel_forward_accept(ssh_session session, int timeout_ms){ - return ssh_forward_accept(session,timeout_ms); + return ssh_channel_accept_forward(session, timeout_ms, NULL); } int channel_close(ssh_channel channel){ @@ -171,12 +171,12 @@ int channel_close(ssh_channel channel){ } int channel_forward_cancel(ssh_session session, const char *address, int port){ - return ssh_forward_cancel(session, address, port); + return ssh_channel_cancel_forward(session, address, port); } int channel_forward_listen(ssh_session session, const char *address, int port, int *bound_port){ - return ssh_forward_listen(session, address, port, bound_port); + return ssh_channel_listen_forward(session, address, port, bound_port); } void channel_free(ssh_channel channel){ @@ -580,7 +580,7 @@ int ssh_publickey_to_file(ssh_session session, ssh_set_error(session, SSH_FATAL, "Invalid parameters"); return SSH_ERROR; } - pubkey_64 = bin_to_base64(string_data(pubkey), ssh_string_len(pubkey)); + pubkey_64 = bin_to_base64(ssh_string_data(pubkey), ssh_string_len(pubkey)); if (pubkey_64 == NULL) { return SSH_ERROR; } diff --git a/libssh/src/libcrypto.c b/libssh/src/libcrypto.c index bb1d96ad..479c8c18 100644 --- a/libssh/src/libcrypto.c +++ b/libssh/src/libcrypto.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "libssh/priv.h" #include "libssh/session.h" @@ -38,6 +39,8 @@ #include #include #include +#include + #ifdef HAVE_OPENSSL_AES_H #define HAS_AES #include @@ -62,6 +65,8 @@ struct ssh_mac_ctx_struct { union { SHACTX sha1_ctx; SHA256CTX sha256_ctx; + SHA384CTX sha384_ctx; + SHA512CTX sha512_ctx; } ctx; }; @@ -74,6 +79,12 @@ static int alloc_key(struct ssh_cipher_struct *cipher) { return 0; } +void ssh_reseed(void){ + struct timeval tv; + gettimeofday(&tv, NULL); + RAND_add(&tv, sizeof(tv), 0.0); +} + SHACTX sha1_init(void) { SHACTX c = malloc(sizeof(*c)); if (c == NULL) { @@ -172,6 +183,52 @@ void sha256(unsigned char *digest, int len, unsigned char *hash) { SHA256(digest, len, hash); } +SHA384CTX sha384_init(void){ + SHA384CTX c = malloc(sizeof(*c)); + if (c == NULL) { + return NULL; + } + SHA384_Init(c); + + return c; +} + +void sha384_update(SHA384CTX c, const void *data, unsigned long len){ + SHA384_Update(c,data,len); +} + +void sha384_final(unsigned char *md, SHA384CTX c) { + SHA384_Final(md, c); + SAFE_FREE(c); +} + +void sha384(unsigned char *digest, int len, unsigned char *hash) { + SHA384(digest, len, hash); +} + +SHA512CTX sha512_init(void){ + SHA512CTX c = malloc(sizeof(*c)); + if (c == NULL) { + return NULL; + } + SHA512_Init(c); + + return c; +} + +void sha512_update(SHA512CTX c, const void *data, unsigned long len){ + SHA512_Update(c,data,len); +} + +void sha512_final(unsigned char *md, SHA512CTX c) { + SHA512_Final(md, c); + SAFE_FREE(c); +} + +void sha512(unsigned char *digest, int len, unsigned char *hash) { + SHA512(digest, len, hash); +} + MD5CTX md5_init(void) { MD5CTX c = malloc(sizeof(*c)); if (c == NULL) { @@ -193,7 +250,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: @@ -203,7 +264,11 @@ ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){ ctx->ctx.sha256_ctx = sha256_init(); return ctx; case SSH_MAC_SHA384: + ctx->ctx.sha384_ctx = sha384_init(); + return ctx; case SSH_MAC_SHA512: + ctx->ctx.sha512_ctx = sha512_init(); + return ctx; default: SAFE_FREE(ctx); return NULL; @@ -219,7 +284,11 @@ void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) { sha256_update(ctx->ctx.sha256_ctx, data, len); break; case SSH_MAC_SHA384: + sha384_update(ctx->ctx.sha384_ctx, data, len); + break; case SSH_MAC_SHA512: + sha512_update(ctx->ctx.sha512_ctx, data, len); + break; default: break; } @@ -234,7 +303,11 @@ void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) { sha256_final(md,ctx->ctx.sha256_ctx); break; case SSH_MAC_SHA384: + sha384_final(md,ctx->ctx.sha384_ctx); + break; case SSH_MAC_SHA512: + sha512_final(md,ctx->ctx.sha512_ctx); + break; default: break; } @@ -257,6 +330,15 @@ HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) { case SSH_HMAC_SHA1: HMAC_Init(ctx, key, len, EVP_sha1()); break; + case SSH_HMAC_SHA256: + HMAC_Init(ctx, key, len, EVP_sha256()); + break; + case SSH_HMAC_SHA384: + HMAC_Init(ctx, key, len, EVP_sha384()); + break; + case SSH_HMAC_SHA512: + HMAC_Init(ctx, key, len, EVP_sha512()); + break; case SSH_HMAC_MD5: HMAC_Init(ctx, key, len, EVP_md5()); break; diff --git a/libssh/src/libgcrypt.c b/libssh/src/libgcrypt.c index 899bccdf..24d4a3c5 100644 --- a/libssh/src/libgcrypt.c +++ b/libssh/src/libgcrypt.c @@ -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); @@ -66,10 +69,69 @@ void sha1(unsigned char *digest, int len, unsigned char *hash) { gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len); } +SHA256CTX sha256_init(void) { + SHA256CTX ctx = NULL; + gcry_md_open(&ctx, GCRY_MD_SHA256, 0); + + return ctx; +} + +void sha256_update(SHACTX c, const void *data, unsigned long len) { + gcry_md_write(c, data, len); +} + +void sha256_final(unsigned char *md, SHACTX c) { + gcry_md_final(c); + memcpy(md, gcry_md_read(c, 0), SHA256_DIGEST_LEN); + gcry_md_close(c); +} + void sha256(unsigned char *digest, int len, unsigned char *hash){ gcry_md_hash_buffer(GCRY_MD_SHA256, hash, digest, len); } +SHA384CTX sha384_init(void) { + SHA384CTX ctx = NULL; + gcry_md_open(&ctx, GCRY_MD_SHA384, 0); + + return ctx; +} + +void sha384_update(SHACTX c, const void *data, unsigned long len) { + gcry_md_write(c, data, len); +} + +void sha384_final(unsigned char *md, SHACTX c) { + gcry_md_final(c); + memcpy(md, gcry_md_read(c, 0), SHA384_DIGEST_LEN); + gcry_md_close(c); +} + +void sha384(unsigned char *digest, int len, unsigned char *hash) { + gcry_md_hash_buffer(GCRY_MD_SHA384, hash, digest, len); +} + +SHA512CTX sha512_init(void) { + SHA512CTX ctx = NULL; + gcry_md_open(&ctx, GCRY_MD_SHA512, 0); + + return ctx; +} + +void sha512_update(SHACTX c, const void *data, unsigned long len) { + gcry_md_write(c, data, len); +} + +void sha512_final(unsigned char *md, SHACTX c) { + gcry_md_final(c); + memcpy(md, gcry_md_read(c, 0), SHA512_DIGEST_LEN); + gcry_md_close(c); +} + +void sha512(unsigned char *digest, int len, unsigned char *hash) { + gcry_md_hash_buffer(GCRY_MD_SHA512, hash, digest, len); +} + MD5CTX md5_init(void) { MD5CTX c = NULL; gcry_md_open(&c, GCRY_MD_MD5, 0); @@ -88,7 +150,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: @@ -121,13 +187,13 @@ void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) { len=SHA_DIGEST_LEN; break; case SSH_MAC_SHA256: - len=SHA256_DIGEST_LENGTH; + len=SHA256_DIGEST_LEN; break; case SSH_MAC_SHA384: - len=SHA384_DIGEST_LENGTH; + len=SHA384_DIGEST_LEN; break; case SSH_MAC_SHA512: - len=SHA512_DIGEST_LENGTH; + len=SHA512_DIGEST_LEN; break; } gcry_md_final(ctx->ctx); @@ -143,6 +209,15 @@ HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) { case SSH_HMAC_SHA1: gcry_md_open(&c, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC); break; + case SSH_HMAC_SHA256: + gcry_md_open(&c, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + break; + case SSH_HMAC_SHA384: + gcry_md_open(&c, GCRY_MD_SHA384, GCRY_MD_FLAG_HMAC); + break; + case SSH_HMAC_SHA512: + gcry_md_open(&c, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC); + break; case SSH_HMAC_MD5: gcry_md_open(&c, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC); break; @@ -403,8 +478,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 128, .set_encrypt_key = blowfish_set_key, .set_decrypt_key = blowfish_set_key, - .cbc_encrypt = blowfish_encrypt, - .cbc_decrypt = blowfish_decrypt + .encrypt = blowfish_encrypt, + .decrypt = blowfish_decrypt }, { .name = "aes128-ctr", @@ -414,8 +489,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 128, .set_encrypt_key = aes_set_key, .set_decrypt_key = aes_set_key, - .cbc_encrypt = aes_encrypt, - .cbc_decrypt = aes_encrypt + .encrypt = aes_encrypt, + .decrypt = aes_encrypt }, { .name = "aes192-ctr", @@ -425,8 +500,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 192, .set_encrypt_key = aes_set_key, .set_decrypt_key = aes_set_key, - .cbc_encrypt = aes_encrypt, - .cbc_decrypt = aes_encrypt + .encrypt = aes_encrypt, + .decrypt = aes_encrypt }, { .name = "aes256-ctr", @@ -436,8 +511,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 256, .set_encrypt_key = aes_set_key, .set_decrypt_key = aes_set_key, - .cbc_encrypt = aes_encrypt, - .cbc_decrypt = aes_encrypt + .encrypt = aes_encrypt, + .decrypt = aes_encrypt }, { .name = "aes128-cbc", @@ -447,8 +522,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 128, .set_encrypt_key = aes_set_key, .set_decrypt_key = aes_set_key, - .cbc_encrypt = aes_encrypt, - .cbc_decrypt = aes_decrypt + .encrypt = aes_encrypt, + .decrypt = aes_decrypt }, { .name = "aes192-cbc", @@ -458,8 +533,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 192, .set_encrypt_key = aes_set_key, .set_decrypt_key = aes_set_key, - .cbc_encrypt = aes_encrypt, - .cbc_decrypt = aes_decrypt + .encrypt = aes_encrypt, + .decrypt = aes_decrypt }, { .name = "aes256-cbc", @@ -469,8 +544,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 256, .set_encrypt_key = aes_set_key, .set_decrypt_key = aes_set_key, - .cbc_encrypt = aes_encrypt, - .cbc_decrypt = aes_decrypt + .encrypt = aes_encrypt, + .decrypt = aes_decrypt }, { .name = "3des-cbc", @@ -480,8 +555,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 192, .set_encrypt_key = des3_set_key, .set_decrypt_key = des3_set_key, - .cbc_encrypt = des3_encrypt, - .cbc_decrypt = des3_decrypt + .encrypt = des3_encrypt, + .decrypt = des3_decrypt }, { .name = "3des-cbc-ssh1", @@ -491,8 +566,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 192, .set_encrypt_key = des3_1_set_key, .set_decrypt_key = des3_1_set_key, - .cbc_encrypt = des3_1_encrypt, - .cbc_decrypt = des3_1_decrypt + .encrypt = des3_1_encrypt, + .decrypt = des3_1_decrypt }, { .name = "des-cbc-ssh1", @@ -502,8 +577,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 64, .set_encrypt_key = des1_set_key, .set_decrypt_key = des1_set_key, - .cbc_encrypt = des1_1_encrypt, - .cbc_decrypt = des1_1_decrypt + .encrypt = des1_1_encrypt, + .decrypt = des1_1_decrypt }, { .name = NULL, @@ -513,8 +588,8 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .keysize = 0, .set_encrypt_key = NULL, .set_decrypt_key = NULL, - .cbc_encrypt = NULL, - .cbc_decrypt = NULL + .encrypt = NULL, + .decrypt = NULL } }; diff --git a/libssh/src/log.c b/libssh/src/log.c index 4552b969..a72dd412 100644 --- a/libssh/src/log.c +++ b/libssh/src/log.c @@ -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 @@ -215,6 +215,10 @@ ssh_logging_callback ssh_get_log_callback(void) { */ void *ssh_get_log_userdata(void) { + if (ssh_log_userdata == NULL) { + return NULL; + } + return ssh_log_userdata; } diff --git a/libssh/src/messages.c b/libssh/src/messages.c index 2c99311d..5a6963e8 100644 --- a/libssh/src/messages.c +++ b/libssh/src/messages.c @@ -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 @@ -208,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)) { @@ -508,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); @@ -586,104 +585,34 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session, session->current_crypto ? session->current_crypto : session->next_crypto; ssh_buffer buffer; - ssh_string str; + ssh_string str=NULL; int rc; buffer = ssh_buffer_new(); if (buffer == NULL) { return NULL; } - - /* Add session id */ - str = ssh_string_new(crypto->digest_len); - if (str == NULL) { - ssh_buffer_free(buffer); - return NULL; - } - ssh_string_fill(str, crypto->session_id, crypto->digest_len); - - rc = buffer_add_ssh_string(buffer, str); - string_free(str); - if (rc < 0) { - ssh_buffer_free(buffer); - return NULL; - } - - /* Add the type */ - rc = buffer_add_u8(buffer, SSH2_MSG_USERAUTH_REQUEST); - if (rc < 0) { - ssh_buffer_free(buffer); - return NULL; - } - - /* Add the username */ - str = ssh_string_from_char(msg->auth_request.username); - if (str == NULL) { - ssh_buffer_free(buffer); - return NULL; - } - rc = buffer_add_ssh_string(buffer, str); - string_free(str); - if (rc < 0) { - ssh_buffer_free(buffer); - return NULL; - } - - /* Add the service name */ - str = ssh_string_from_char(service); - if (str == NULL) { - ssh_buffer_free(buffer); - return NULL; - } - rc = buffer_add_ssh_string(buffer, str); - string_free(str); - if (rc < 0) { - ssh_buffer_free(buffer); - return NULL; - } - - /* Add the method (publickey) */ - str = ssh_string_from_char("publickey"); - if (str == NULL) { - ssh_buffer_free(buffer); - return NULL; - } - rc = buffer_add_ssh_string(buffer, str); - string_free(str); - if (rc < 0) { - ssh_buffer_free(buffer); - return NULL; - } - - /* Has been signed (TRUE) */ - rc = buffer_add_u8(buffer, 1); - if (rc < 0) { - ssh_buffer_free(buffer); - return NULL; - } - - /* Add the public key algorithm */ - str = ssh_string_from_char(msg->auth_request.pubkey->type_c); - if (str == NULL) { - ssh_buffer_free(buffer); - return NULL; - } - rc = buffer_add_ssh_string(buffer, str); - string_free(str); - if (rc < 0) { - ssh_buffer_free(buffer); - return NULL; - } - - /* Add the publickey as blob */ rc = ssh_pki_export_pubkey_blob(msg->auth_request.pubkey, &str); if (rc < 0) { ssh_buffer_free(buffer); return NULL; } - rc = buffer_add_ssh_string(buffer, str); - string_free(str); - if (rc < 0) { + + rc = ssh_buffer_pack(buffer, + "dPbsssbsS", + crypto->digest_len, /* session ID string */ + (size_t)crypto->digest_len, crypto->session_id, + SSH2_MSG_USERAUTH_REQUEST, /* type */ + msg->auth_request.username, + service, + "publickey", /* method */ + 1, /* has to be signed (true) */ + msg->auth_request.pubkey->type_c, /* pubkey algorithm */ + str); /* public key as a blob */ + + ssh_string_free(str); + if (rc != SSH_OK) { + ssh_set_error_oom(session); ssh_buffer_free(buffer); return NULL; } @@ -698,11 +627,10 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session, * SSH Message */ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ - ssh_string str; ssh_message msg = NULL; char *service = NULL; char *method = NULL; - uint32_t method_size = 0; + int rc; (void)user; (void)type; @@ -713,35 +641,13 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ goto error; } msg->type = SSH_REQUEST_AUTH; + rc = ssh_buffer_unpack(packet, + "sss", + &msg->auth_request.username, + &service, + &method); - str = buffer_get_ssh_string(packet); - if (str == NULL) { - goto error; - } - msg->auth_request.username = ssh_string_to_char(str); - ssh_string_free(str); - if (msg->auth_request.username == NULL) { - goto error; - } - - str = buffer_get_ssh_string(packet); - if (str == NULL) { - goto error; - } - service = ssh_string_to_char(str); - ssh_string_free(str); - if (service == NULL) { - goto error; - } - - str = buffer_get_ssh_string(packet); - if (str == NULL) { - goto error; - } - method = ssh_string_to_char(str); - method_size = ssh_string_len(str); - ssh_string_free(str); - if (method == NULL) { + if (rc != SSH_OK) { goto error; } @@ -751,32 +657,23 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ msg->auth_request.username); - if (strncmp(method, "none", method_size) == 0) { + if (strcmp(method, "none") == 0) { msg->auth_request.method = SSH_AUTH_METHOD_NONE; goto end; } - if (strncmp(method, "password", method_size) == 0) { - ssh_string pass = NULL; + if (strcmp(method, "password") == 0) { uint8_t tmp; msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD; - buffer_get_u8(packet, &tmp); - pass = buffer_get_ssh_string(packet); - if (pass == NULL) { - goto error; - } - msg->auth_request.password = ssh_string_to_char(pass); - ssh_string_burn(pass); - ssh_string_free(pass); - pass = NULL; - if (msg->auth_request.password == NULL) { + rc = ssh_buffer_unpack(packet, "bs", &tmp, &msg->auth_request.password); + if (rc != SSH_OK) { goto error; } goto end; } - if (strncmp(method, "keyboard-interactive", method_size) == 0) { + if (strcmp(method, "keyboard-interactive") == 0) { ssh_string lang = NULL; ssh_string submethods = NULL; @@ -806,23 +703,20 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ goto end; } - if (strncmp(method, "publickey", method_size) == 0) { + if (strcmp(method, "publickey") == 0) { ssh_string algo = NULL; ssh_string pubkey_blob = NULL; uint8_t has_sign; - int rc; msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY; SAFE_FREE(method); - buffer_get_u8(packet, &has_sign); - algo = buffer_get_ssh_string(packet); - if (algo == NULL) { - goto error; - } - pubkey_blob = buffer_get_ssh_string(packet); - if (pubkey_blob == NULL) { - ssh_string_free(algo); - algo = NULL; + rc = ssh_buffer_unpack(packet, "bSS", + &has_sign, + &algo, + &pubkey_blob + ); + + if (rc != SSH_OK) { goto error; } ssh_string_free(algo); @@ -877,7 +771,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ goto end; } #ifdef WITH_GSSAPI - if (strncmp(method, "gssapi-with-mic", method_size) == 0) { + if (strcmp(method, "gssapi-with-mic") == 0) { uint32_t n_oid; ssh_string *oids; ssh_string oid; @@ -966,6 +860,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ uint32_t nanswers; uint32_t i; ssh_string tmp; + int rc; ssh_message msg = NULL; @@ -993,7 +888,11 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ msg->auth_request.username = NULL; #endif - buffer_get_u32(packet, &nanswers); + rc = ssh_buffer_unpack(packet, "d", &nanswers); + if (rc != SSH_OK) { + ssh_set_error_invalid(session); + goto error; + } if (session->kbdint == NULL) { SSH_LOG(SSH_LOG_PROTOCOL, "Warning: Got a keyboard-interactive " @@ -1007,7 +906,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ } } - nanswers = ntohl(nanswers); SSH_LOG(SSH_LOG_PACKET,"kbdint: %d answers",nanswers); if (nanswers > KBDINT_MAX_PROMPT) { ssh_set_error(session, SSH_FATAL, @@ -1071,9 +969,9 @@ error: SSH_PACKET_CALLBACK(ssh_packet_channel_open){ ssh_message msg = NULL; - ssh_string type_s = NULL, originator = NULL, destination = NULL; char *type_c = NULL; - uint32_t sender, window, packet_size, originator_port, destination_port; + uint32_t originator_port, destination_port; + int rc; (void)type; (void)user; @@ -1084,30 +982,18 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open){ } msg->type = SSH_REQUEST_CHANNEL_OPEN; - - type_s = buffer_get_ssh_string(packet); - if (type_s == NULL) { - ssh_set_error_oom(session); - goto error; - } - type_c = ssh_string_to_char(type_s); - if (type_c == NULL) { - ssh_set_error_oom(session); - goto error; + rc = ssh_buffer_unpack(packet, "s", &type_c); + if (rc != SSH_OK){ + goto error; } SSH_LOG(SSH_LOG_PACKET, "Clients wants to open a %s channel", type_c); - ssh_string_free(type_s); - type_s=NULL; - buffer_get_u32(packet, &sender); - buffer_get_u32(packet, &window); - buffer_get_u32(packet, &packet_size); - - msg->channel_request_open.sender = ntohl(sender); - msg->channel_request_open.window = ntohl(window); - msg->channel_request_open.packet_size = ntohl(packet_size); + ssh_buffer_unpack(packet,"ddd", + &msg->channel_request_open.sender, + &msg->channel_request_open.window, + &msg->channel_request_open.packet_size); if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED){ ssh_set_error(session,SSH_FATAL, "Invalid state when receiving channel open request (must be authenticated)"); @@ -1121,96 +1007,46 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open){ } if (strcmp(type_c,"direct-tcpip") == 0) { - destination = buffer_get_ssh_string(packet); - if (destination == NULL) { - ssh_set_error_oom(session); + rc = ssh_buffer_unpack(packet, + "sdsd", + &msg->channel_request_open.destination, + &destination_port, + &msg->channel_request_open.originator, + &originator_port); + if (rc != SSH_OK) { goto error; } - msg->channel_request_open.destination = ssh_string_to_char(destination); - if (msg->channel_request_open.destination == NULL) { - ssh_set_error_oom(session); - ssh_string_free(destination); - goto error; - } - ssh_string_free(destination); - - buffer_get_u32(packet, &destination_port); - msg->channel_request_open.destination_port = (uint16_t) ntohl(destination_port); - - originator = buffer_get_ssh_string(packet); - if (originator == NULL) { - ssh_set_error_oom(session); - goto error; - } - msg->channel_request_open.originator = ssh_string_to_char(originator); - if (msg->channel_request_open.originator == NULL) { - ssh_set_error_oom(session); - ssh_string_free(originator); - goto error; - } - ssh_string_free(originator); - - buffer_get_u32(packet, &originator_port); - msg->channel_request_open.originator_port = (uint16_t) ntohl(originator_port); + msg->channel_request_open.destination_port = (uint16_t) destination_port; + msg->channel_request_open.originator_port = (uint16_t) originator_port; msg->channel_request_open.type = SSH_CHANNEL_DIRECT_TCPIP; goto end; } if (strcmp(type_c,"forwarded-tcpip") == 0) { - destination = buffer_get_ssh_string(packet); - if (destination == NULL) { - ssh_set_error_oom(session); - goto error; - } - msg->channel_request_open.destination = ssh_string_to_char(destination); - if (msg->channel_request_open.destination == NULL) { - ssh_set_error_oom(session); - ssh_string_free(destination); - goto error; - } - ssh_string_free(destination); - - buffer_get_u32(packet, &destination_port); - msg->channel_request_open.destination_port = (uint16_t) ntohl(destination_port); - - originator = buffer_get_ssh_string(packet); - if (originator == NULL) { - ssh_set_error_oom(session); - goto error; - } - msg->channel_request_open.originator = ssh_string_to_char(originator); - if (msg->channel_request_open.originator == NULL) { - ssh_set_error_oom(session); - ssh_string_free(originator); - goto error; - } - ssh_string_free(originator); - - buffer_get_u32(packet, &originator_port); - msg->channel_request_open.originator_port = (uint16_t) ntohl(originator_port); - + rc = ssh_buffer_unpack(packet, "sdsd", + &msg->channel_request_open.destination, + &destination_port, + &msg->channel_request_open.originator, + &originator_port + ); + if (rc != SSH_OK){ + goto error; + } + msg->channel_request_open.destination_port = (uint16_t) destination_port; + msg->channel_request_open.originator_port = (uint16_t) originator_port; msg->channel_request_open.type = SSH_CHANNEL_FORWARDED_TCPIP; goto end; } if (strcmp(type_c,"x11") == 0) { - originator = buffer_get_ssh_string(packet); - if (originator == NULL) { - ssh_set_error_oom(session); - goto error; - } - msg->channel_request_open.originator = ssh_string_to_char(originator); - if (msg->channel_request_open.originator == NULL) { - ssh_set_error_oom(session); - ssh_string_free(originator); - goto error; - } - ssh_string_free(originator); - - buffer_get_u32(packet, &originator_port); - msg->channel_request_open.originator_port = (uint16_t) ntohl(originator_port); - + rc = ssh_buffer_unpack(packet, "sd", + &msg->channel_request_open.originator, + &originator_port); + if (rc != SSH_OK){ + goto error; + } + msg->channel_request_open.originator_port = (uint16_t) originator_port; msg->channel_request_open.type = SSH_CHANNEL_X11; goto end; } @@ -1222,8 +1058,6 @@ error: ssh_message_free(msg); msg=NULL; end: - if(type_s != NULL) - ssh_string_free(type_s); SAFE_FREE(type_c); if(msg != NULL) ssh_message_queue(session,msg); @@ -1249,28 +1083,15 @@ int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_c chan->remote_window = msg->channel_request_open.window; chan->state = SSH_CHANNEL_STATE_OPEN; - rc = buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); - if (rc < 0) { - return SSH_ERROR; - } - - rc = buffer_add_u32(session->out_buffer, htonl(chan->remote_channel)); - if (rc < 0) { - return SSH_ERROR; - } - - rc =buffer_add_u32(session->out_buffer, htonl(chan->local_channel)); - if (rc < 0) { - return SSH_ERROR; - } - - rc = buffer_add_u32(session->out_buffer, htonl(chan->local_window)); - if (rc < 0) { - return SSH_ERROR; - } - - rc = buffer_add_u32(session->out_buffer, htonl(chan->local_maxpacket)); - if (rc < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bdddd", + SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, + chan->remote_channel, + chan->local_channel, + chan->local_window, + chan->local_maxpacket); + if (rc != SSH_OK) { + ssh_set_error_oom(session); return SSH_ERROR; } @@ -1327,6 +1148,7 @@ ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) { int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet, const char *request, uint8_t want_reply) { ssh_message msg = NULL; + int rc; msg = ssh_message_new(session); if (msg == NULL) { @@ -1343,36 +1165,18 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, msg->channel_request.want_reply = want_reply; if (strcmp(request, "pty-req") == 0) { - ssh_string term = NULL; - char *term_c = NULL; - term = buffer_get_ssh_string(packet); - if (term == NULL) { - ssh_set_error_oom(session); - goto error; - } - term_c = ssh_string_to_char(term); - if (term_c == NULL) { - ssh_set_error_oom(session); - ssh_string_free(term); - goto error; - } - ssh_string_free(term); + rc = ssh_buffer_unpack(packet, "sddddS", + &msg->channel_request.TERM, + &msg->channel_request.width, + &msg->channel_request.height, + &msg->channel_request.pxwidth, + &msg->channel_request.pxheight, + &msg->channel_request.modes + ); msg->channel_request.type = SSH_CHANNEL_REQUEST_PTY; - msg->channel_request.TERM = term_c; - buffer_get_u32(packet, &msg->channel_request.width); - buffer_get_u32(packet, &msg->channel_request.height); - buffer_get_u32(packet, &msg->channel_request.pxwidth); - buffer_get_u32(packet, &msg->channel_request.pxheight); - - msg->channel_request.width = ntohl(msg->channel_request.width); - msg->channel_request.height = ntohl(msg->channel_request.height); - msg->channel_request.pxwidth = ntohl(msg->channel_request.pxwidth); - msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight); - msg->channel_request.modes = buffer_get_ssh_string(packet); - if (msg->channel_request.modes == NULL) { - SAFE_FREE(term_c); + if (rc != SSH_OK) { goto error; } goto end; @@ -1380,39 +1184,24 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, if (strcmp(request, "window-change") == 0) { msg->channel_request.type = SSH_CHANNEL_REQUEST_WINDOW_CHANGE; - - buffer_get_u32(packet, &msg->channel_request.width); - buffer_get_u32(packet, &msg->channel_request.height); - buffer_get_u32(packet, &msg->channel_request.pxwidth); - buffer_get_u32(packet, &msg->channel_request.pxheight); - - msg->channel_request.width = ntohl(msg->channel_request.width); - msg->channel_request.height = ntohl(msg->channel_request.height); - msg->channel_request.pxwidth = ntohl(msg->channel_request.pxwidth); - msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight); - + rc = ssh_buffer_unpack(packet, "dddd", + &msg->channel_request.width, + &msg->channel_request.height, + &msg->channel_request.pxwidth, + &msg->channel_request.pxheight); + if (rc != SSH_OK){ + goto error; + } goto end; } if (strcmp(request, "subsystem") == 0) { - ssh_string subsys = NULL; - char *subsys_c = NULL; - subsys = buffer_get_ssh_string(packet); - if (subsys == NULL) { - ssh_set_error_oom(session); - goto error; - } - subsys_c = ssh_string_to_char(subsys); - if (subsys_c == NULL) { - ssh_set_error_oom(session); - ssh_string_free(subsys); - goto error; - } - ssh_string_free(subsys); - + rc = ssh_buffer_unpack(packet, "s", + &msg->channel_request.subsystem); msg->channel_request.type = SSH_CHANNEL_REQUEST_SUBSYSTEM; - msg->channel_request.subsystem = subsys_c; - + if (rc != SSH_OK){ + goto error; + } goto end; } @@ -1422,82 +1211,37 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, } if (strcmp(request, "exec") == 0) { - ssh_string cmd = NULL; - cmd = buffer_get_ssh_string(packet); - if (cmd == NULL) { - ssh_set_error_oom(session); - goto error; - } + rc = ssh_buffer_unpack(packet, "s", + &msg->channel_request.command); msg->channel_request.type = SSH_CHANNEL_REQUEST_EXEC; - msg->channel_request.command = ssh_string_to_char(cmd); - ssh_string_free(cmd); - if (msg->channel_request.command == NULL) { + if (rc != SSH_OK) { goto error; } goto end; } if (strcmp(request, "env") == 0) { - ssh_string name = NULL; - ssh_string value = NULL; - name = buffer_get_ssh_string(packet); - if (name == NULL) { - ssh_set_error_oom(session); - goto error; - } - value = buffer_get_ssh_string(packet); - if (value == NULL) { - ssh_set_error_oom(session); - ssh_string_free(name); - goto error; - } - + rc = ssh_buffer_unpack(packet, "ss", + &msg->channel_request.var_name, + &msg->channel_request.var_value); msg->channel_request.type = SSH_CHANNEL_REQUEST_ENV; - msg->channel_request.var_name = ssh_string_to_char(name); - msg->channel_request.var_value = ssh_string_to_char(value); - if (msg->channel_request.var_name == NULL || - msg->channel_request.var_value == NULL) { - ssh_string_free(name); - ssh_string_free(value); + if (rc != SSH_OK) { goto error; } - ssh_string_free(name); - ssh_string_free(value); - goto end; } if (strcmp(request, "x11-req") == 0) { - ssh_string auth_protocol = NULL; - ssh_string auth_cookie = NULL; - - buffer_get_u8(packet, &msg->channel_request.x11_single_connection); - - auth_protocol = buffer_get_ssh_string(packet); - if (auth_protocol == NULL) { - ssh_set_error_oom(session); - goto error; - } - auth_cookie = buffer_get_ssh_string(packet); - if (auth_cookie == NULL) { - ssh_set_error_oom(session); - ssh_string_free(auth_protocol); - goto error; - } + rc = ssh_buffer_unpack(packet, "bssd", + &msg->channel_request.x11_single_connection, + &msg->channel_request.x11_auth_protocol, + &msg->channel_request.x11_auth_cookie, + &msg->channel_request.x11_screen_number); msg->channel_request.type = SSH_CHANNEL_REQUEST_X11; - msg->channel_request.x11_auth_protocol = ssh_string_to_char(auth_protocol); - msg->channel_request.x11_auth_cookie = ssh_string_to_char(auth_cookie); - if (msg->channel_request.x11_auth_protocol == NULL || - msg->channel_request.x11_auth_cookie == NULL) { - ssh_string_free(auth_protocol); - ssh_string_free(auth_cookie); + if (rc != SSH_OK) { goto error; } - ssh_string_free(auth_protocol); - ssh_string_free(auth_cookie); - - buffer_get_u32(packet, &msg->channel_request.x11_screen_number); goto end; } @@ -1515,6 +1259,7 @@ error: int ssh_message_channel_request_reply_success(ssh_message msg) { uint32_t channel; + int rc; if (msg == NULL) { return SSH_ERROR; @@ -1526,10 +1271,12 @@ int ssh_message_channel_request_reply_success(ssh_message msg) { SSH_LOG(SSH_LOG_PACKET, "Sending a channel_request success to channel %d", channel); - if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_SUCCESS) < 0) { - return SSH_ERROR; - } - if (buffer_add_u32(msg->session->out_buffer, htonl(channel)) < 0) { + rc = ssh_buffer_pack(msg->session->out_buffer, + "bd", + SSH2_MSG_CHANNEL_SUCCESS, + channel); + if (rc != SSH_OK){ + ssh_set_error_oom(msg->session); return SSH_ERROR; } @@ -1545,72 +1292,65 @@ int ssh_message_channel_request_reply_success(ssh_message msg) { #ifdef WITH_SERVER SSH_PACKET_CALLBACK(ssh_packet_global_request){ ssh_message msg = NULL; - ssh_string request_s=NULL; char *request=NULL; - ssh_string bind_addr_s=NULL; - char *bind_addr=NULL; - uint32_t bind_port; uint8_t want_reply; int rc = SSH_PACKET_USED; + int r; (void)user; (void)type; (void)packet; - request_s = buffer_get_ssh_string(packet); - if (request_s != NULL) { - request = ssh_string_to_char(request_s); - ssh_string_free(request_s); - } - - buffer_get_u8(packet, &want_reply); - SSH_LOG(SSH_LOG_PROTOCOL,"Received SSH_MSG_GLOBAL_REQUEST packet"); + r = ssh_buffer_unpack(packet, "sb", + &request, + &want_reply); + if (r != SSH_OK){ + goto error; + } msg = ssh_message_new(session); if (msg == NULL) { - ssh_string_free_char(request); - return SSH_PACKET_NOT_USED; + ssh_set_error_oom(session); + goto error; } msg->type = SSH_REQUEST_GLOBAL; - if (request && strcmp(request, "tcpip-forward") == 0) { - bind_addr_s = buffer_get_ssh_string(packet); - if (bind_addr_s != NULL) { - bind_addr = ssh_string_to_char(bind_addr_s); - ssh_string_free(bind_addr_s); + if (strcmp(request, "tcpip-forward") == 0) { + r = ssh_buffer_unpack(packet, "sd", + &msg->global_request.bind_address, + &msg->global_request.bind_port + ); + if (r != SSH_OK){ + goto error; } - - buffer_get_u32(packet, &bind_port); - bind_port = ntohl(bind_port); - msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD; msg->global_request.want_reply = want_reply; - msg->global_request.bind_address = bind_addr; - msg->global_request.bind_port = bind_port; - SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); + SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, + msg->global_request.bind_address, + msg->global_request.bind_port); if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) { - SSH_LOG(SSH_LOG_PROTOCOL, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); + SSH_LOG(SSH_LOG_PROTOCOL, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, + want_reply, msg->global_request.bind_address, + msg->global_request.bind_port); session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata); } else { ssh_message_reply_default(msg); } - } else if (request && strcmp(request, "cancel-tcpip-forward") == 0) { - bind_addr_s = buffer_get_ssh_string(packet); - if (bind_addr_s != NULL) { - bind_addr = ssh_string_to_char(bind_addr_s); - ssh_string_free(bind_addr_s); + } else if (strcmp(request, "cancel-tcpip-forward") == 0) { + r = ssh_buffer_unpack(packet, "sd", + &msg->global_request.bind_address, + &msg->global_request.bind_port); + if (r != SSH_OK){ + goto error; } - buffer_get_u32(packet, &bind_port); - bind_port = ntohl(bind_port); - msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD; msg->global_request.want_reply = want_reply; - msg->global_request.bind_address = bind_addr; - msg->global_request.bind_port = bind_port; - SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port); + SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, + msg->global_request.bind_address, + msg->global_request.bind_port); if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) { session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata); @@ -1624,9 +1364,12 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ SAFE_FREE(msg); SAFE_FREE(request); - SAFE_FREE(bind_addr); - return rc; +error: + SAFE_FREE(msg); + SAFE_FREE(request); + SSH_LOG(SSH_LOG_WARNING, "Invalid SSH_MSG_GLOBAL_REQUEST packet"); + return SSH_PACKET_NOT_USED; } #endif /* WITH_SERVER */ diff --git a/libssh/src/misc.c b/libssh/src/misc.c index 18a59d60..6daf60ab 100644 --- a/libssh/src/misc.c +++ b/libssh/src/misc.c @@ -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 + * Copyright (c) 2008-2009 by Andreas Schneider * * 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; diff --git a/libssh/src/options.c b/libssh/src/options.c index e02ad4df..f7f24553 100644 --- a/libssh/src/options.c +++ b/libssh/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 + * Copyright (c) 2009-2013 by Andreas Schneider * * 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 @@ -136,7 +136,7 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) { } } - for (i = 0; i < 10; ++i) { + for (i = 0; i < 10; i++) { if (src->opts.wanted_methods[i]) { new->opts.wanted_methods[i] = strdup(src->opts.wanted_methods[i]); if (new->opts.wanted_methods[i] == NULL) { @@ -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. @@ -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: @@ -703,6 +716,26 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type, return -1; } break; + case SSH_OPTIONS_HMAC_C_S: + v = value; + if (v == NULL || v[0] == '\0') { + ssh_set_error_invalid(session); + return -1; + } else { + if (ssh_options_set_algo(session, SSH_MAC_C_S, v) < 0) + return -1; + } + break; + case SSH_OPTIONS_HMAC_S_C: + v = value; + if (v == NULL || v[0] == '\0') { + ssh_set_error_invalid(session); + return -1; + } else { + if (ssh_options_set_algo(session, SSH_MAC_S_C, v) < 0) + return -1; + } + break; case SSH_OPTIONS_COMPRESSION_C_S: v = value; if (v == NULL || v[0] == '\0') { @@ -792,6 +825,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; @@ -1232,84 +1304,93 @@ int ssh_options_apply(ssh_session session) { * @addtogroup libssh_server * @{ */ -static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo, - const char *list) { - if (!verify_existing_algo(algo, list)) { - ssh_set_error(sshbind, SSH_REQUEST_DENIED, - "Setting method: no algorithm for method \"%s\" (%s)\n", - ssh_kex_get_description(algo), list); - return -1; - } - - SAFE_FREE(sshbind->wanted_methods[algo]); - sshbind->wanted_methods[algo] = strdup(list); - if (sshbind->wanted_methods[algo] == NULL) { - ssh_set_error_oom(sshbind); - return -1; - } - - 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 sshbind An allocated ssh bind 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). + * - SSH_BIND_OPTIONS_HOSTKEY: + * Set the path to an ssh host key, regardless + * of type. Only one key from per key type + * (RSA, DSA, ECDSA) is allowed in an ssh_bind + * at a time, and later calls to this function + * with this option for the same key type will + * override prior calls (const char *). * - * 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 IP address to bind (const char *). * - * SSH_BIND_OPTIONS_LOG_VERBOSITY_STR: - * Set the session logging verbosity (integer). + * - SSH_BIND_OPTIONS_BINDPORT: + * Set the port to bind (unsigned int *). * - * 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_BINDPORT_STR: + * Set the port to bind (const char *). * - * SSH_BIND_OPTIONS_BINDADDR: - * Set the bind address. + * - 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_BINDPORT: - * Set the bind port, default is 22. + * - 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_HOSTKEY: - * Set the server public key type: ssh-rsa or ssh-dss - * (string). + * - SSH_BIND_OPTIONS_DSAKEY: + * Set the path to the ssh host dsa key, SSHv2 + * only (const char *). * - * SSH_BIND_OPTIONS_DSAKEY: - * Set the path to the dsa ssh host key (string). + * - SSH_BIND_OPTIONS_RSAKEY: + * Set the path to the ssh host rsa key, SSHv2 + * only (const char *). * - * SSH_BIND_OPTIONS_RSAKEY: - * Set the path to the ssh host rsa key (string). + * - 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 (string). + * - 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; @@ -1321,8 +1402,57 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, ssh_set_error_invalid(sshbind); return -1; } else { - if (ssh_bind_options_set_algo(sshbind, SSH_HOSTKEYS, value) < 0) - return -1; + int key_type; + ssh_key key; + ssh_key *bind_key_loc = NULL; + char **bind_key_path_loc; + + rc = ssh_pki_import_privkey_file(value, NULL, NULL, NULL, &key); + if (rc != SSH_OK) { + return -1; + } + key_type = ssh_key_type(key); + switch (key_type) { + case SSH_KEYTYPE_DSS: + bind_key_loc = &sshbind->dsa; + bind_key_path_loc = &sshbind->dsakey; + break; + case SSH_KEYTYPE_ECDSA: +#ifdef HAVE_ECC + bind_key_loc = &sshbind->ecdsa; + bind_key_path_loc = &sshbind->ecdsakey; +#else + ssh_set_error(sshbind, + SSH_FATAL, + "ECDSA key used and libssh compiled " + "without ECDSA support"); +#endif + break; + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + bind_key_loc = &sshbind->rsa; + bind_key_path_loc = &sshbind->rsakey; + break; + default: + ssh_set_error(sshbind, + SSH_FATAL, + "Unsupported key type %d", key_type); + } + + if (bind_key_loc == NULL) { + ssh_key_free(key); + return -1; + } + + /* Set the location of the key on disk even though we don't + need it in case some other function wants it */ + rc = ssh_bind_set_key(sshbind, bind_key_path_loc, value); + if (rc < 0) { + ssh_key_free(key); + return -1; + } + ssh_key_free(*bind_key_loc); + *bind_key_loc = key; } break; case SSH_BIND_OPTIONS_BINDADDR: @@ -1376,7 +1506,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) { @@ -1389,35 +1519,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); diff --git a/libssh/src/packet.c b/libssh/src/packet.c index 3302847a..d16cd165 100644 --- a/libssh/src/packet.c +++ b/libssh/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 @@ -48,8 +48,6 @@ #include "libssh/auth.h" #include "libssh/gssapi.h" -#define MACSIZE SHA_DIGEST_LEN - static ssh_packet_callback default_packet_handlers[]= { ssh_packet_disconnect_callback, // SSH2_MSG_DISCONNECT 1 ssh_packet_ignore_callback, // SSH2_MSG_IGNORE 2 @@ -141,174 +139,225 @@ 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); + unsigned char mac[DIGEST_MAX_LEN] = {0}; + char buffer[16] = {0}; + size_t current_macsize = 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->current_crypto != NULL) { + current_macsize = hmac_digest_len(session->current_crypto->in_hmac); + } - 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 = ssh_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 = ssh_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 = ssh_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, current_macsize); + + rc = packet_hmac_verify(session, session->in_buffer, mac, session->current_crypto->in_hmac); + 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++; + if (session->raw_counter != NULL) { + session->raw_counter->in_bytes += payloadsize; + session->raw_counter->in_packets++; + } - 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_PACKET, "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){ @@ -393,34 +442,42 @@ void ssh_packet_process(ssh_session session, uint8_t type){ * @return SSH_ERROR on error, else SSH_OK */ int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){ - int r; + int rc; - r = buffer_add_u8(session->out_buffer, SSH2_MSG_UNIMPLEMENTED); - if (r < 0) { - return SSH_ERROR; - } - r = buffer_add_u32(session->out_buffer, htonl(seqnum)); - if (r < 0) { - return SSH_ERROR; - } - r = packet_send(session); + rc = ssh_buffer_pack(session->out_buffer, + "bd", + SSH2_MSG_UNIMPLEMENTED, + seqnum); + if (rc != SSH_OK) { + ssh_set_error_oom(session); + return SSH_ERROR; + } + rc = packet_send(session); - return r; + return rc; } /** @internal * @brief handles a SSH_MSG_UNIMPLEMENTED packet */ SSH_PACKET_CALLBACK(ssh_packet_unimplemented){ - uint32_t seq; + uint32_t seq; + int rc; + (void)session; /* unused */ - (void)type; - (void)user; - buffer_get_u32(packet,&seq); - seq=ntohl(seq); - SSH_LOG(SSH_LOG_RARE, - "Received SSH_MSG_UNIMPLEMENTED (sequence number %d)",seq); - return SSH_PACKET_USED; + (void)type; + (void)user; + + rc = ssh_buffer_unpack(packet, "d", &seq); + if (rc != SSH_OK) { + SSH_LOG(SSH_LOG_WARNING, + "Could not unpack SSH_MSG_UNIMPLEMENTED packet"); + } + + SSH_LOG(SSH_LOG_RARE, + "Received SSH_MSG_UNIMPLEMENTED (sequence number %d)",seq); + + return SSH_PACKET_USED; } /** @internal @@ -459,13 +516,17 @@ static int ssh_packet_write(ssh_session session) { static int packet_send2(ssh_session session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->out_cipher->blocksize : 8); + enum ssh_hmac_e hmac_type = (session->current_crypto ? + session->current_crypto->out_hmac : session->next_crypto->out_hmac); 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 +546,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 = ssh_buffer_add_data(session->out_buffer, padstring, padding); + if (rc < 0) { goto error; } #ifdef WITH_PCAP @@ -510,18 +570,23 @@ static int packet_send2(ssh_session session) { hmac = packet_encrypt(session, buffer_get_rest(session->out_buffer), buffer_get_rest_len(session->out_buffer)); if (hmac) { - if (buffer_add_data(session->out_buffer, hmac, 20) < 0) { + rc = ssh_buffer_add_data(session->out_buffer, hmac, hmac_digest_len(hmac_type)); + if (rc < 0) { goto error; } } rc = ssh_packet_write(session); session->send_seq++; + if (session->raw_counter != NULL) { + session->raw_counter->out_bytes += payloadsize; + session->raw_counter->out_packets++; + } SSH_LOG(SSH_LOG_PACKET, "packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]", ntohl(finallen), padding, compsize, payloadsize); - if (buffer_reinit(session->out_buffer) < 0) { + if (ssh_buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: diff --git a/libssh/src/packet1.c b/libssh/src/packet1.c index 7ac8318d..eac70084 100644 --- a/libssh/src/packet1.c +++ b/libssh/src/packet1.c @@ -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){ @@ -114,7 +114,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user memset(&session->in_packet, 0, sizeof(PACKET)); if (session->in_buffer) { - if (buffer_reinit(session->in_buffer) < 0) { + if (ssh_buffer_reinit(session->in_buffer) < 0) { goto error; } } else { @@ -155,7 +155,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user /* it is _not_ possible that to_be_read be < 8. */ packet = (char *)data + processed; - if (buffer_add_data(session->in_buffer,packet,to_be_read) < 0) { + if (ssh_buffer_add_data(session->in_buffer,packet,to_be_read) < 0) { goto error; } processed += to_be_read; @@ -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 @@ -236,7 +241,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user return processed; case PACKET_STATE_PROCESSING: - SSH_LOG(SSH_LOG_RARE, "Nested packet processing. Delaying."); + SSH_LOG(SSH_LOG_PACKET, "Nested packet processing. Delaying."); return 0; } @@ -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)); @@ -315,7 +322,7 @@ int packet_send1(ssh_session session) { session->send_seq++; - if (buffer_reinit(session->out_buffer) < 0) { + if (ssh_buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: diff --git a/libssh/src/packet_cb.c b/libssh/src/packet_cb.c index f5d4f055..a10dd1ab 100644 --- a/libssh/src/packet_cb.c +++ b/libssh/src/packet_cb.c @@ -43,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; } /** diff --git a/libssh/src/packet_crypt.c b/libssh/src/packet_crypt.c index 50b81893..914727e0 100644 --- a/libssh/src/packet_crypt.c +++ b/libssh/src/packet_crypt.c @@ -22,6 +22,7 @@ */ #include "config.h" +#include #include #include #include @@ -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; @@ -73,11 +77,10 @@ int packet_decrypt(ssh_session session, void *data,uint32_t len) { SAFE_FREE(out); return -1; } - crypto->cbc_decrypt(crypto,data,out,len); + crypto->decrypt(crypto,data,out,len); memcpy(data,out,len); - memset(out,0,len); - + BURN_BUFFER(out, len); SAFE_FREE(out); return 0; } @@ -88,6 +91,9 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) { char *out = NULL; unsigned int finallen; uint32_t seq; + enum ssh_hmac_e type; + + assert(len); if (!session->current_crypto) { return NULL; /* nothing to do here */ @@ -101,6 +107,7 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) { return NULL; } + type = session->current_crypto->out_hmac; seq = ntohl(session->send_seq); crypto = session->current_crypto->out_cipher; @@ -111,7 +118,7 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) { } if (session->version == 2) { - ctx = hmac_init(session->current_crypto->encryptMAC,20,SSH_HMAC_SHA1); + ctx = hmac_init(session->current_crypto->encryptMAC, hmac_digest_len(type), type); if (ctx == NULL) { SAFE_FREE(out); return NULL; @@ -120,18 +127,18 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) { hmac_update(ctx,data,len); hmac_final(ctx,session->current_crypto->hmacbuf,&finallen); #ifdef DEBUG_CRYPTO - ssh_print_hexa("mac: ",data,len); - if (finallen != 20) { + ssh_print_hexa("mac: ",data,hmac_digest_len(type)); + if (finallen != hmac_digest_len(type)) { printf("Final len is %d\n",finallen); } - ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, 20); + ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, hmac_digest_len(type)); #endif } - crypto->cbc_encrypt(crypto, data, out, len); + crypto->encrypt(crypto, data, out, len); memcpy(data, out, len); - memset(out, 0, len); + BURN_BUFFER(out, len); SAFE_FREE(out); if (session->version == 2) { @@ -154,13 +161,13 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) { * occurred. */ int packet_hmac_verify(ssh_session session, ssh_buffer buffer, - unsigned char *mac) { - unsigned char hmacbuf[EVP_MAX_MD_SIZE] = {0}; + unsigned char *mac, enum ssh_hmac_e type) { + unsigned char hmacbuf[DIGEST_MAX_LEN] = {0}; HMACCTX ctx; unsigned int len; uint32_t seq; - ctx = hmac_init(session->current_crypto->decryptMAC, 20, SSH_HMAC_SHA1); + ctx = hmac_init(session->current_crypto->decryptMAC, hmac_digest_len(type), type); if (ctx == NULL) { return -1; } diff --git a/libssh/src/pcap.c b/libssh/src/pcap.c index 6e688962..134bdf10 100644 --- a/libssh/src/pcap.c +++ b/libssh/src/pcap.c @@ -342,7 +342,7 @@ static int ssh_pcap_context_connect(ssh_pcap_context ctx){ int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction direction , void *data, uint32_t len, uint32_t origlen){ ssh_buffer ip; - int err; + int rc; if(ctx==NULL || ctx->file ==NULL) return SSH_ERROR; if(ctx->connected==0) @@ -353,147 +353,104 @@ int ssh_pcap_context_write(ssh_pcap_context ctx,enum ssh_pcap_direction directio ssh_set_error_oom(ctx->session); return SSH_ERROR; } - /* build an IP packet */ - /* V4, 20 bytes */ - err = buffer_add_u8(ip,4 << 4 | 5); - if (err < 0) { - goto error; - } - /* tos */ - err = buffer_add_u8(ip,0); - if (err < 0) { - goto error; - } - /* total len */ - err = buffer_add_u16(ip,htons(origlen + TCPIPHDR_LEN)); - if (err < 0) { - goto error; - } - /* IP id number */ - err = buffer_add_u16(ip,htons(ctx->file->ipsequence)); - if (err < 0) { - goto error; - } + + /* build an IP packet */ + rc = ssh_buffer_pack(ip, + "bbwwwbbw", + 4 << 4 | 5, /* V4, 20 bytes */ + 0, /* tos */ + origlen + TCPIPHDR_LEN, /* total len */ + ctx->file->ipsequence, /* IP id number */ + 0, /* fragment offset */ + 64, /* TTL */ + 6, /* protocol TCP=6 */ + 0); /* checksum */ + ctx->file->ipsequence++; - /* fragment offset */ - err = buffer_add_u16(ip,htons(0)); - if (err < 0) { - goto error; - } - /* TTL */ - err = buffer_add_u8(ip,64); - if (err < 0) { - goto error; - } - /* protocol TCP=6 */ - err = buffer_add_u8(ip,6); - if (err < 0) { - goto error; - } - /* checksum */ - err = buffer_add_u16(ip,0); - if (err < 0) { - goto error; - } + if (rc != SSH_OK){ + goto error; + } if(direction==SSH_PCAP_DIR_OUT){ - err = buffer_add_u32(ip,ctx->ipsource); - if (err < 0) { + rc = buffer_add_u32(ip,ctx->ipsource); + if (rc < 0) { goto error; } - err = buffer_add_u32(ip,ctx->ipdest); - if (err < 0) { + rc = buffer_add_u32(ip,ctx->ipdest); + if (rc < 0) { goto error; } } else { - err = buffer_add_u32(ip,ctx->ipdest); - if (err < 0) { + rc = buffer_add_u32(ip,ctx->ipdest); + if (rc < 0) { goto error; } - err = buffer_add_u32(ip,ctx->ipsource); - if (err < 0) { + rc = buffer_add_u32(ip,ctx->ipsource); + if (rc < 0) { goto error; } } /* TCP */ if(direction==SSH_PCAP_DIR_OUT){ - err = buffer_add_u16(ip,ctx->portsource); - if (err < 0) { + rc = buffer_add_u16(ip,ctx->portsource); + if (rc < 0) { goto error; } - err = buffer_add_u16(ip,ctx->portdest); - if (err < 0) { + rc = buffer_add_u16(ip,ctx->portdest); + if (rc < 0) { goto error; } } else { - err = buffer_add_u16(ip,ctx->portdest); - if (err < 0) { + rc = buffer_add_u16(ip,ctx->portdest); + if (rc < 0) { goto error; } - err = buffer_add_u16(ip,ctx->portsource); - if (err < 0) { + rc = buffer_add_u16(ip,ctx->portsource); + if (rc < 0) { goto error; } } /* sequence number */ if(direction==SSH_PCAP_DIR_OUT){ - err = buffer_add_u32(ip,ntohl(ctx->outsequence)); - if (err < 0) { + rc = ssh_buffer_pack(ip, "d", ctx->outsequence); + if (rc != SSH_OK) { goto error; } ctx->outsequence+=origlen; } else { - err = buffer_add_u32(ip,ntohl(ctx->insequence)); - if (err < 0) { + rc = ssh_buffer_pack(ip, "d", ctx->insequence); + if (rc != SSH_OK) { goto error; } ctx->insequence+=origlen; } /* ack number */ if(direction==SSH_PCAP_DIR_OUT){ - err = buffer_add_u32(ip,ntohl(ctx->insequence)); - if (err < 0) { + rc = ssh_buffer_pack(ip, "d", ctx->insequence); + if (rc != SSH_OK) { goto error; } } else { - err = buffer_add_u32(ip,ntohl(ctx->outsequence)); - if (err < 0) { + rc = ssh_buffer_pack(ip, "d", ctx->outsequence); + if (rc != SSH_OK) { goto error; } } - /* header len = 20 = 5 * 32 bits, at offset 4*/ - err = buffer_add_u8(ip,5 << 4); - if (err < 0) { + + rc = ssh_buffer_pack(ip, + "bbwwwP", + 5 << 4, /* header len = 20 = 5 * 32 bits, at offset 4*/ + TH_PUSH | TH_ACK, /* flags */ + 65535, /* window */ + 0, /* checksum */ + 0, /* urgent data ptr */ + (size_t)len, data); /* actual data */ + if (rc != SSH_OK) { goto error; } - /* flags */ - err = buffer_add_u8(ip,TH_PUSH | TH_ACK); - if (err < 0) { - goto error; - } - /* window */ - err = buffer_add_u16(ip,htons(65535)); - if (err < 0) { - goto error; - } - /* checksum */ - err = buffer_add_u16(ip,htons(0)); - if (err < 0) { - goto error; - } - /* urgent data ptr */ - err = buffer_add_u16(ip,0); - if (err < 0) { - goto error; - } - /* actual data */ - err = buffer_add_data(ip,data,len); - if (err < 0) { - goto error; - } - err=ssh_pcap_file_write_packet(ctx->file,ip,origlen + TCPIPHDR_LEN); + rc=ssh_pcap_file_write_packet(ctx->file,ip,origlen + TCPIPHDR_LEN); error: ssh_buffer_free(ip); - return err; + return rc; } /** @brief sets the pcap file used to trace the session diff --git a/libssh/src/pki.c b/libssh/src/pki.c index ec5a6883..af472ebb 100644 --- a/libssh/src/pki.c +++ b/libssh/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 + * Copyright (c) 2011-2013 Andreas Schneider * * 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. @@ -138,6 +157,11 @@ void ssh_key_clean (ssh_key key){ if(key->ecdsa) EC_KEY_free(key->ecdsa); #endif /* HAVE_OPENSSL_ECC */ #endif + if (key->ed25519_privkey != NULL){ + BURN_BUFFER(key->ed25519_privkey, sizeof(ed25519_privkey)); + SAFE_FREE(key->ed25519_privkey); + } + SAFE_FREE(key->ed25519_pubkey); key->flags=SSH_KEY_FLAG_EMPTY; key->type=SSH_KEYTYPE_UNKNOWN; key->ecdsa_nid = 0; @@ -188,6 +212,8 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) { return "ssh-rsa1"; case SSH_KEYTYPE_ECDSA: return "ssh-ecdsa"; + case SSH_KEYTYPE_ED25519: + return "ssh-ed25519"; case SSH_KEYTYPE_UNKNOWN: return NULL; } @@ -226,6 +252,8 @@ enum ssh_keytypes_e ssh_key_type_from_name(const char *name) { || strcmp(name, "ecdsa-sha2-nistp384") == 0 || strcmp(name, "ecdsa-sha2-nistp521") == 0) { return SSH_KEYTYPE_ECDSA; + } else if (strcmp(name, "ssh-ed25519") == 0){ + return SSH_KEYTYPE_ED25519; } return SSH_KEYTYPE_UNKNOWN; @@ -281,7 +309,7 @@ int ssh_key_cmp(const ssh_key k1, } if (k1->type != k2->type) { - ssh_pki_log("key types don't macth!"); + ssh_pki_log("key types don't match!"); return 1; } @@ -292,6 +320,10 @@ int ssh_key_cmp(const ssh_key k1, } } + if (k1->type == SSH_KEYTYPE_ED25519) { + return pki_ed25519_key_cmp(k1, k2, what); + } + return pki_key_compare(k1, k2, what); } @@ -331,6 +363,13 @@ 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_ED25519: + SAFE_FREE(sig->ed25519_sig); + break; case SSH_KEYTYPE_UNKNOWN: break; } @@ -476,6 +515,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,10 +759,36 @@ 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 + case SSH_KEYTYPE_ED25519: + { + ssh_string pubkey = buffer_get_ssh_string(buffer); + if (ssh_string_len(pubkey) != ED25519_PK_LEN) { + ssh_pki_log("Invalid public key length"); + ssh_string_burn(pubkey); + ssh_string_free(pubkey); + goto fail; + } + + key->ed25519_pubkey = malloc(ED25519_PK_LEN); + if (key->ed25519_pubkey == NULL) { + ssh_string_burn(pubkey); + ssh_string_free(pubkey); + goto fail; + } + + memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN); + ssh_string_burn(pubkey); + ssh_string_free(pubkey); + } + break; case SSH_KEYTYPE_UNKNOWN: + default: ssh_pki_log("Unknown public key protocol %d", type); goto fail; } @@ -752,7 +876,7 @@ int ssh_pki_import_pubkey_blob(const ssh_string key_blob, return SSH_ERROR; } - rc = buffer_add_data(buffer, ssh_string_data(key_blob), + rc = ssh_buffer_add_data(buffer, ssh_string_data(key_blob), ssh_string_len(key_blob)); if (rc < 0) { ssh_pki_log("Out of memory!"); @@ -917,10 +1041,20 @@ 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_ED25519: + rc = pki_key_generate_ed25519(key); + if (rc == SSH_ERROR) { + goto error; + } + break; case SSH_KEYTYPE_UNKNOWN: goto error; } @@ -999,11 +1133,11 @@ int ssh_pki_export_pubkey_blob(const ssh_key key, } /** - * @brief Convert a public key to a base64 hased key. + * @brief Convert a public key to a base64 encoded key. * * @param[in] key The key to hash * - * @param[out] b64_key A pointer to store the allocated base64 hashed key. You + * @param[out] b64_key A pointer to store the allocated base64 encoded key. You * need to free the buffer. * * @return SSH_OK on success, SSH_ERROR on error. @@ -1177,9 +1311,9 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob, return SSH_ERROR; } - rc = buffer_add_data(buf, - ssh_string_data(sig_blob), - ssh_string_len(sig_blob)); + rc = ssh_buffer_add_data(buf, + ssh_string_data(sig_blob), + ssh_string_len(sig_blob)); if (rc < 0) { ssh_buffer_free(buf); return SSH_ERROR; @@ -1236,12 +1370,19 @@ 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, ehash, elen); #endif + } else if (key->type == SSH_KEYTYPE_ED25519) { + rc = pki_signature_verify(session, sig, key, digest, dlen); } else { unsigned char hash[SHA_DIGEST_LEN] = {0}; @@ -1302,8 +1443,36 @@ ssh_string ssh_pki_do_sign(ssh_session session, 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", ehash, elen); +#endif + sig = pki_do_sign(privkey, ehash, elen); #endif + } else if (privkey->type == SSH_KEYTYPE_ED25519){ + ssh_buffer buf; + + buf = ssh_buffer_new(); + if (buf == NULL) { + ssh_string_free(session_id); + return NULL; + } + + ssh_buffer_set_secure(buf); + rc = ssh_buffer_pack(buf, + "SP", + session_id, + buffer_get_rest_len(sigbuf), buffer_get_rest(sigbuf)); + if (rc != SSH_OK) { + ssh_string_free(session_id); + ssh_buffer_free(buf); + return NULL; + } + + sig = pki_do_sign(privkey, + ssh_buffer_get_begin(buf), + ssh_buffer_get_len(buf)); + ssh_buffer_free(buf); } else { unsigned char hash[SHA_DIGEST_LEN] = {0}; SHACTX ctx; @@ -1395,10 +1564,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)) { @@ -1407,24 +1574,64 @@ 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 if (privkey->type == SSH_KEYTYPE_ED25519) { + sig = ssh_signature_new(); + if (sig == NULL){ + return NULL; + } + + sig->type = privkey->type; + sig->type_c = privkey->type_c; + + rc = pki_ed25519_sign(privkey, + sig, + crypto->secret_hash, + crypto->digest_len); + if (rc != SSH_OK){ + ssh_signature_free(sig); + sig = NULL; + } + } 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); diff --git a/libssh/src/pki_crypto.c b/libssh/src/pki_crypto.c index e87d7ace..5706fdf0 100644 --- a/libssh/src/pki_crypto.c +++ b/libssh/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 + * Copyright (c) 2009-2013 by Andreas Schneider * * 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 @@ -44,7 +44,7 @@ #include "libssh/session.h" #include "libssh/pki.h" #include "libssh/pki_priv.h" -#include "libssh/dh.h" +#include "libssh/bignum.h" struct pem_get_password_struct { ssh_auth_callback fn; @@ -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; @@ -212,6 +214,7 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e) ssh_key pki_key_dup(const ssh_key key, int demote) { ssh_key new; + int rc; new = ssh_key_new(); if (new == NULL) { @@ -343,13 +346,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; @@ -369,7 +372,14 @@ ssh_key pki_key_dup(const ssh_key key, int demote) } break; #endif + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_key_dup(new, key); + if (rc != SSH_OK) { + goto fail; + } + break; case SSH_KEYTYPE_UNKNOWN: + default: ssh_key_free(new); return NULL; } @@ -381,10 +391,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){ @@ -521,13 +541,135 @@ int pki_key_compare(const ssh_key k1, break; } #endif + case SSH_KEYTYPE_ED25519: + /* ed25519 keys handled globaly */ case SSH_KEYTYPE_UNKNOWN: + default: return 1; } 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_ED25519: + 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, @@ -629,6 +771,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, break; #endif + case SSH_KEYTYPE_ED25519: case SSH_KEYTYPE_UNKNOWN: BIO_free(mem); ssh_pki_log("Unkown or invalid private key type %d", type); @@ -817,7 +960,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key) break; case SSH_KEYTYPE_ECDSA: #ifdef HAVE_OPENSSL_ECC - rc = buffer_reinit(buffer); + rc = ssh_buffer_reinit(buffer); if (rc < 0) { ssh_buffer_free(buffer); return NULL; @@ -867,7 +1010,14 @@ ssh_string pki_publickey_to_blob(const ssh_key key) break; #endif + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_public_key_to_blob(buffer, key); + if (rc == SSH_ERROR){ + goto fail; + } + break; case SSH_KEYTYPE_UNKNOWN: + default: goto fail; } @@ -976,41 +1126,63 @@ 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; 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: @@ -1019,6 +1191,8 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) case SSH_KEYTYPE_ECDSA: #ifdef HAVE_OPENSSL_ECC { + ssh_string r; + ssh_string s; ssh_buffer b; int rc; @@ -1062,6 +1236,10 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) break; } #endif + case SSH_KEYTYPE_ED25519: + sig_blob = pki_ed25519_sig_to_blob(sig); + break; + default: case SSH_KEYTYPE_UNKNOWN: ssh_pki_log("Unknown signature key type: %s", sig->type_c); return NULL; @@ -1070,6 +1248,67 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) 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) @@ -1078,7 +1317,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, ssh_string r; ssh_string s; size_t len; - size_t rsalen; + int rc; sig = ssh_signature_new(); if (sig == NULL) { @@ -1142,29 +1381,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 @@ -1177,7 +1394,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, { /* build ecdsa siganature */ ssh_buffer b; uint32_t rlen; - int rc; b = ssh_buffer_new(); if (b == NULL) { @@ -1185,9 +1401,9 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, return NULL; } - rc = buffer_add_data(b, - ssh_string_data(sig_blob), - ssh_string_len(sig_blob)); + rc = ssh_buffer_add_data(b, + ssh_string_data(sig_blob), + ssh_string_len(sig_blob)); if (rc < 0) { ssh_buffer_free(b); ssh_signature_free(sig); @@ -1245,6 +1461,14 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, break; #endif + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_sig_from_blob(sig, sig_blob); + if (rc == SSH_ERROR){ + ssh_signature_free(sig); + return NULL; + } + break; + default: case SSH_KEYTYPE_UNKNOWN: ssh_pki_log("Unknown signature type"); ssh_signature_free(sig); @@ -1292,6 +1516,15 @@ int pki_signature_verify(ssh_session session, return SSH_ERROR; } break; + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_verify(key, sig, hash, hlen); + if (rc != SSH_OK){ + ssh_set_error(session, + SSH_FATAL, + "ed25519 signature verification error"); + return SSH_ERROR; + } + break; case SSH_KEYTYPE_ECDSA: #ifdef HAVE_OPENSSL_ECC rc = ECDSA_do_verify(hash, @@ -1308,6 +1541,7 @@ int pki_signature_verify(ssh_session session, break; #endif case SSH_KEYTYPE_UNKNOWN: + default: ssh_set_error(session, SSH_FATAL, "Unknown public key type"); return SSH_ERROR; } @@ -1319,6 +1553,7 @@ ssh_signature pki_do_sign(const ssh_key privkey, const unsigned char *hash, size_t hlen) { ssh_signature sig; + int rc; sig = ssh_signature_new(); if (sig == NULL) { @@ -1366,7 +1601,15 @@ ssh_signature pki_do_sign(const ssh_key privkey, break; #endif /* HAVE_OPENSSL_ECC */ + case SSH_KEYTYPE_ED25519: + rc = pki_ed25519_sign(privkey, sig, hash, hlen); + if (rc != SSH_OK){ + ssh_signature_free(sig); + return NULL; + } + break; case SSH_KEYTYPE_UNKNOWN: + default: ssh_signature_free(sig); return NULL; } @@ -1413,7 +1656,10 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key, } break; #endif + case SSH_KEYTYPE_ED25519: + /* ED25519 handled in caller */ case SSH_KEYTYPE_UNKNOWN: + default: ssh_signature_free(sig); return NULL; } diff --git a/libssh/src/pki_ed25519.c b/libssh/src/pki_ed25519.c new file mode 100644 index 00000000..7fb9827c --- /dev/null +++ b/libssh/src/pki_ed25519.c @@ -0,0 +1,305 @@ +/* + * pki_ed25519 .c - PKI infrastructure using ed25519 + * + * This file is part of the SSH Library + * + * Copyright (c) 2014 by Aris Adamantiadis + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "libssh/pki.h" +#include "libssh/pki_priv.h" +#include "libssh/ed25519.h" +#include "libssh/buffer.h" + +int pki_key_generate_ed25519(ssh_key key) +{ + int rc; + + key->ed25519_privkey = malloc(sizeof (ed25519_privkey)); + if (key->ed25519_privkey == NULL) { + goto error; + } + + key->ed25519_pubkey = malloc(sizeof (ed25519_privkey)); + if (key->ed25519_privkey == NULL) { + goto error; + } + + rc = crypto_sign_ed25519_keypair(*key->ed25519_pubkey, + *key->ed25519_privkey); + if (rc != 0) { + goto error; + } + + return SSH_OK; +error: + SAFE_FREE(key->ed25519_privkey); + SAFE_FREE(key->ed25519_pubkey); + + return SSH_ERROR; +} + +int pki_ed25519_sign(const ssh_key privkey, + ssh_signature sig, + const unsigned char *hash, + size_t hlen) +{ + int rc; + uint8_t *buffer; + unsigned long long dlen = 0; + + buffer = malloc(hlen + ED25519_SIG_LEN); + if (buffer == NULL) { + return SSH_ERROR; + } + + rc = crypto_sign_ed25519(buffer, + &dlen, + hash, + hlen, + *privkey->ed25519_privkey); + if (rc != 0) { + goto error; + } + sig->ed25519_sig = malloc(ED25519_SIG_LEN); + if (sig->ed25519_sig == NULL) { + goto error; + } + + /* This shouldn't happen */ + if (dlen - hlen != ED25519_SIG_LEN) { + goto error; + } + memcpy(sig->ed25519_sig, buffer, dlen - hlen); + SAFE_FREE(buffer); + + return SSH_OK; +error: + SAFE_FREE(buffer); + return SSH_ERROR; +} + +int pki_ed25519_verify(const ssh_key pubkey, + ssh_signature sig, + const unsigned char *hash, + size_t hlen) +{ + unsigned long long mlen = 0; + uint8_t *buffer; + uint8_t *buffer2; + int rc; + + if (pubkey == NULL || sig == NULL || + hash == NULL || sig->ed25519_sig == NULL) { + return SSH_ERROR; + } + + buffer = malloc(hlen + ED25519_SIG_LEN); + if (buffer == NULL) { + return SSH_ERROR; + } + + buffer2 = malloc(hlen + ED25519_SIG_LEN); + if (buffer2 == NULL) { + goto error; + } + + memcpy(buffer, sig->ed25519_sig, ED25519_SIG_LEN); + memcpy(buffer + ED25519_SIG_LEN, hash, hlen); + + rc = crypto_sign_ed25519_open(buffer2, + &mlen, + buffer, + hlen + ED25519_SIG_LEN, + *pubkey->ed25519_pubkey); + + BURN_BUFFER(buffer, hlen + ED25519_SIG_LEN); + BURN_BUFFER(buffer2, hlen); + SAFE_FREE(buffer); + SAFE_FREE(buffer2); + if (rc == 0) { + return SSH_OK; + } else { + return SSH_ERROR; + } +error: + SAFE_FREE(buffer); + SAFE_FREE(buffer2); + + return SSH_ERROR; +} + +/** + * @internal + * + * @brief Compare ed25519 keys if they are equal. + * + * @param[in] k1 The first key to compare. + * + * @param[in] k2 The second key to compare. + * + * @param[in] what What part or type of the key do you want to compare. + * + * @return 0 if equal, 1 if not. + */ +int pki_ed25519_key_cmp(const ssh_key k1, + const ssh_key k2, + enum ssh_keycmp_e what) +{ + int cmp; + + switch(what) { + case SSH_KEY_CMP_PRIVATE: + if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) { + return 1; + } + cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_SK_LEN); + if (cmp != 0) { + return 1; + } + /* FALL THROUGH */ + case SSH_KEY_CMP_PUBLIC: + if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) { + return 1; + } + cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_PK_LEN); + if (cmp != 0) { + return 1; + } + } + + return 0; +} + +/** + * @internal + * + * @brief duplicate an ed25519 key + * + * @param[out\ new preinitialized output ssh_ke + * + * @param[in] key key to copy + * + * @return SSH_ERROR on error, SSH_OK on success + */ +int pki_ed25519_key_dup(ssh_key new, const ssh_key key) +{ + if (key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL) { + return SSH_ERROR; + } + + new->ed25519_privkey = malloc(ED25519_SK_LEN); + if (new->ed25519_privkey == NULL) { + return SSH_ERROR; + } + + new->ed25519_pubkey = malloc(ED25519_PK_LEN); + if (new->ed25519_privkey == NULL || new->ed25519_pubkey == NULL){ + SAFE_FREE(new->ed25519_privkey); + return SSH_ERROR; + } + + memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN); + memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN); + + return SSH_OK; +} + +/** + * @internal + * + * @brief outputs an ed25519 public key in a blob buffer. + * + * @param[out] buffer output buffer + * + * @param[in] key key to output + * + * @return SSH_ERROR on error, SSH_OK on success + */ +int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key) +{ + int rc; + + if (key->ed25519_pubkey == NULL){ + return SSH_ERROR; + } + + rc = ssh_buffer_pack(buffer, + "dP", + (uint32_t)ED25519_PK_LEN, + (size_t)ED25519_PK_LEN, key->ed25519_pubkey); + + return rc; +} + +/** + * @internal + * + * @brief output a signature blob from an ed25519 signature + * + * @param[in] sig signature to convert + * + * @return Signature blob in SSH string, or NULL on error + */ +ssh_string pki_ed25519_sig_to_blob(ssh_signature sig) +{ + ssh_string sig_blob; + + if (sig->ed25519_sig == NULL) { + return NULL; + } + + sig_blob = ssh_string_new(ED25519_SIG_LEN); + if (sig_blob == NULL) { + return NULL; + } + ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN); + + return sig_blob; +} + +/** + * @internal + * + * @brief Convert a signature blob in an ed25519 signature. + * + * @param[out] sig a preinitialized signature + * + * @param[in] sig_blob a signature blob + * + * @return SSH_ERROR on error, SSH_OK on success + */ +int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob) +{ + size_t len; + + len = ssh_string_len(sig_blob); + if (len != ED25519_SIG_LEN){ + ssh_pki_log("Invalid ssh-ed25519 signature len: %zu", len); + return SSH_ERROR; + } + + sig->ed25519_sig = malloc(ED25519_SIG_LEN); + if (sig->ed25519_sig == NULL){ + return SSH_ERROR; + } + + memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN); + + return SSH_OK; +} diff --git a/libssh/src/pki_gcrypt.c b/libssh/src/pki_gcrypt.c index a44ed73a..2811acce 100644 --- a/libssh/src/pki_gcrypt.c +++ b/libssh/src/pki_gcrypt.c @@ -388,7 +388,7 @@ static ssh_buffer privatekey_string_to_buffer(const char *pkey, int type, } } else { if(len > 0) { - if (buffer_add_data(buffer, p, len) < 0) { + if (ssh_buffer_add_data(buffer, p, len) < 0) { ssh_buffer_free(buffer); SAFE_FREE(iv); return NULL; @@ -398,7 +398,7 @@ static ssh_buffer privatekey_string_to_buffer(const char *pkey, int type, get_next_line(p, len); while(len > 0 && strncmp(p, header_end, header_end_size) != 0) { - if (buffer_add_data(buffer, p, len) < 0) { + if (ssh_buffer_add_data(buffer, p, len) < 0) { ssh_buffer_free(buffer); SAFE_FREE(iv); return NULL; @@ -412,7 +412,7 @@ static ssh_buffer privatekey_string_to_buffer(const char *pkey, int type, return NULL; } - if (buffer_add_data(buffer, "\0", 1) < 0) { + if (ssh_buffer_add_data(buffer, "\0", 1) < 0) { ssh_buffer_free(buffer); SAFE_FREE(iv); return NULL; @@ -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, @@ -1141,7 +1154,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key) } rc = buffer_add_ssh_string(buffer, type_s); - string_free(type_s); + ssh_string_free(type_s); if (rc < 0) { ssh_buffer_free(buffer); return NULL; @@ -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: diff --git a/libssh/src/poll.c b/libssh/src/poll.c index 8e21e0d5..4e9f19f0 100644 --- a/libssh/src/poll.c +++ b/libssh/src/poll.c @@ -3,8 +3,8 @@ * * This file is part of the SSH Library * - * Copyright (c) 2009-2010 by Andreas Schneider - * Copyright (c) 2003-2009 by Aris Adamantiadis + * Copyright (c) 2009-2013 by Andreas Schneider + * 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; @@ -472,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; @@ -786,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); @@ -848,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; @@ -876,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 @@ -885,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 @@ -919,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 diff --git a/libssh/src/sc25519.c b/libssh/src/sc25519.c new file mode 100644 index 00000000..9576d416 --- /dev/null +++ b/libssh/src/sc25519.c @@ -0,0 +1,373 @@ +/* + * Public Domain, Authors: Daniel J. Bernstein, Niels Duif, Tanja Lange, + * Peter Schwabe, Bo-Yin Yang. + * Copied from supercop-20130419/crypto_sign/ed25519/ref/sc25519.c + */ + +#include "libssh/priv.h" +#include "libssh/sc25519.h" + +/*Arithmetic modulo the group order m = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989 */ + +static const uint32_t m[32] = { + 0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, + 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 +}; + +static const uint32_t mu[33] = { + 0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, + 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21, + 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F +}; + +static uint32_t lt(uint32_t a,uint32_t b) /* 16-bit inputs */ +{ + unsigned int x = a; + + x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */ + x >>= 31; /* 0: no; 1: yes */ + + return x; +} + +/* Reduce coefficients of r before calling reduce_add_sub */ +static void reduce_add_sub(sc25519 *r) +{ + uint32_t pb = 0; + uint32_t b; + uint32_t mask; + int i; + unsigned char t[32]; + + for (i = 0; i < 32; i++) { + pb += m[i]; + b = lt(r->v[i],pb); + t[i] = r->v[i]-pb+(b<<8); + pb = b; + } + mask = b - 1; + for (i = 0; i < 32; i++) { + r->v[i] ^= mask & (r->v[i] ^ t[i]); + } +} + +/* Reduce coefficients of x before calling barrett_reduce */ +static void barrett_reduce(sc25519 *r, const uint32_t x[64]) +{ + /* See HAC, Alg. 14.42 */ + int i,j; + uint32_t q2[66]; + uint32_t *q3 = q2 + 33; + uint32_t r1[33]; + uint32_t r2[33]; + uint32_t carry; + uint32_t pb = 0; + uint32_t b; + + for (i = 0; i < 66; i++) { + q2[i] = 0; + } + for (i = 0; i < 33; i++) { + r2[i] = 0; + } + + for (i = 0; i < 33; i++) { + for (j = 0; j < 33; j++) { + if (i + j >= 31) { + q2[i+j] += mu[i]*x[j+31]; + } + } + } + + carry = q2[31] >> 8; + q2[32] += carry; + carry = q2[32] >> 8; + q2[33] += carry; + + for (i = 0; i < 33; i++) { + r1[i] = x[i]; + } + + for (i = 0; i < 32; i++) { + for (j = 0; j < 33; j++) { + if (i + j < 33) { + r2[i+j] += m[i]*q3[j]; + } + } + } + + for (i = 0; i < 32; i++) { + carry = r2[i] >> 8; + r2[i+1] += carry; + r2[i] &= 0xff; + } + + for (i = 0; i < 32; i++) { + pb += r2[i]; + b = lt(r1[i],pb); + r->v[i] = r1[i]-pb+(b<<8); + pb = b; + } + + /* XXX: Can it really happen that r<0?, See HAC, Alg 14.42, Step 3 + * If so: Handle it here! + */ + + reduce_add_sub(r); + reduce_add_sub(r); +} + +void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]) +{ + int i; + uint32_t t[64]; + + for (i = 0; i < 32; i++) { + t[i] = x[i]; + } + for (i = 32; i < 64; i++) { + t[i] = 0; + } + + barrett_reduce(r, t); +} + +void shortsc25519_from16bytes(shortsc25519 *r, const unsigned char x[16]) +{ + int i; + + for (i = 0; i < 16; i++) { + r->v[i] = x[i]; + } +} + +void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]) +{ + int i; + uint32_t t[64]; + + for (i = 0; i < 64; i++) { + t[i] = x[i]; + } + + barrett_reduce(r, t); +} + +void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x) +{ + int i; + + for (i = 0; i < 16; i++) { + r->v[i] = x->v[i]; + } + for (i = 0; i < 16; i++) { + r->v[16+i] = 0; + } +} + +void sc25519_to32bytes(unsigned char r[32], const sc25519 *x) +{ + int i; + + for (i = 0; i < 32; i++) { + r[i] = x->v[i]; + } +} + +int sc25519_iszero_vartime(const sc25519 *x) +{ + int i; + + for (i = 0; i < 32; i++) { + if(x->v[i] != 0) { + return 0; + } + } + + return 1; +} + +int sc25519_isshort_vartime(const sc25519 *x) +{ + int i; + + for (i = 31; i > 15; i--) { + if (x->v[i] != 0) { + return 0; + } + } + + return 1; +} + +int sc25519_lt_vartime(const sc25519 *x, const sc25519 *y) +{ + int i; + + for (i = 31; i >= 0; i--) { + if (x->v[i] < y->v[i]) { + return 1; + } + if (x->v[i] > y->v[i]) { + return 0; + } + } + + return 0; +} + +void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y) +{ + int i, carry; + + for (i = 0; i < 32; i++) { + r->v[i] = x->v[i] + y->v[i]; + } + + for (i = 0;i < 31; i++) { + carry = r->v[i] >> 8; + r->v[i+1] += carry; + r->v[i] &= 0xff; + } + + reduce_add_sub(r); +} + +void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y) +{ + uint32_t b = 0; + uint32_t t; + int i; + + for (i = 0; i < 32; i++) { + t = x->v[i] - y->v[i] - b; + r->v[i] = t & 255; + b = (t >> 8) & 1; + } +} + +void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y) +{ + int i,j,carry; + uint32_t t[64]; + + for (i = 0; i < 64; i++) { + t[i] = 0; + } + + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + t[i+j] += x->v[i] * y->v[j]; + } + } + + /* Reduce coefficients */ + for (i = 0; i < 63; i++) { + carry = t[i] >> 8; + t[i+1] += carry; + t[i] &= 0xff; + } + + barrett_reduce(r, t); +} + +void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y) +{ + sc25519 t; + sc25519_from_shortsc(&t, y); + sc25519_mul(r, x, &t); +} + +void sc25519_window3(signed char r[85], const sc25519 *s) +{ + char carry; + int i; + + for (i = 0; i < 10; i++) { + r[8*i+0] = s->v[3*i+0] & 7; + r[8*i+1] = (s->v[3*i+0] >> 3) & 7; + r[8*i+2] = (s->v[3*i+0] >> 6) & 7; + r[8*i+2] ^= (s->v[3*i+1] << 2) & 7; + r[8*i+3] = (s->v[3*i+1] >> 1) & 7; + r[8*i+4] = (s->v[3*i+1] >> 4) & 7; + r[8*i+5] = (s->v[3*i+1] >> 7) & 7; + r[8*i+5] ^= (s->v[3*i+2] << 1) & 7; + r[8*i+6] = (s->v[3*i+2] >> 2) & 7; + r[8*i+7] = (s->v[3*i+2] >> 5) & 7; + } + r[8*i+0] = s->v[3*i+0] & 7; + r[8*i+1] = (s->v[3*i+0] >> 3) & 7; + r[8*i+2] = (s->v[3*i+0] >> 6) & 7; + r[8*i+2] ^= (s->v[3*i+1] << 2) & 7; + r[8*i+3] = (s->v[3*i+1] >> 1) & 7; + r[8*i+4] = (s->v[3*i+1] >> 4) & 7; + + /* Making it signed */ + carry = 0; + for (i = 0; i < 84; i++) { + r[i] += carry; + r[i+1] += r[i] >> 3; + r[i] &= 7; + carry = r[i] >> 2; + r[i] -= carry<<3; + } + + r[84] += carry; +} + +void sc25519_window5(signed char r[51], const sc25519 *s) +{ + char carry; + int i; + + for (i = 0; i < 6; i++) { + r[8*i+0] = s->v[5*i+0] & 31; + r[8*i+1] = (s->v[5*i+0] >> 5) & 31; + r[8*i+1] ^= (s->v[5*i+1] << 3) & 31; + r[8*i+2] = (s->v[5*i+1] >> 2) & 31; + r[8*i+3] = (s->v[5*i+1] >> 7) & 31; + r[8*i+3] ^= (s->v[5*i+2] << 1) & 31; + r[8*i+4] = (s->v[5*i+2] >> 4) & 31; + r[8*i+4] ^= (s->v[5*i+3] << 4) & 31; + r[8*i+5] = (s->v[5*i+3] >> 1) & 31; + r[8*i+6] = (s->v[5*i+3] >> 6) & 31; + r[8*i+6] ^= (s->v[5*i+4] << 2) & 31; + r[8*i+7] = (s->v[5*i+4] >> 3) & 31; + } + r[8*i+0] = s->v[5*i+0] & 31; + r[8*i+1] = (s->v[5*i+0] >> 5) & 31; + r[8*i+1] ^= (s->v[5*i+1] << 3) & 31; + r[8*i+2] = (s->v[5*i+1] >> 2) & 31; + + /* Making it signed */ + carry = 0; + for (i = 0; i < 50; i++) { + r[i] += carry; + r[i+1] += r[i] >> 5; + r[i] &= 31; + carry = r[i] >> 4; + r[i] -= carry<<5; + } + + r[50] += carry; +} + +void sc25519_2interleave2(unsigned char r[127], + const sc25519 *s1, + const sc25519 *s2) +{ + int i; + + for (i = 0; i < 31; i++) { + r[4*i] = ( s1->v[i] & 3) ^ (( s2->v[i] & 3) << 2); + r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2); + r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2); + r[4*i+3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2); + } + r[124] = ( s1->v[31] & 3) ^ (( s2->v[31] & 3) << 2); + r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2); + r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2); +} diff --git a/libssh/src/scp.c b/libssh/src/scp.c index db07aed4..0208ddc5 100644 --- a/libssh/src/scp.c +++ b/libssh/src/scp.c @@ -545,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; @@ -642,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; @@ -814,7 +814,7 @@ int ssh_scp_integer_mode(const char *mode){ */ char *ssh_scp_string_mode(int mode){ char buffer[16]; - snprintf(buffer,sizeof(buffer),"%.4d",mode); + snprintf(buffer,sizeof(buffer),"%.4o",mode); return strdup(buffer); } diff --git a/libssh/src/server.c b/libssh/src/server.c index 8629c8ba..3a38fc7b 100644 --- a/libssh/src/server.c +++ b/libssh/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 @@ -174,6 +174,15 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){ SSH_LOG(SSH_LOG_RARE,"Invalid state for SSH_MSG_KEXDH_INIT"); goto error; } + + /* If first_kex_packet_follows guess was wrong, ignore this message. */ + if (session->first_kex_follows_guess_wrong != 0) { + SSH_LOG(SSH_LOG_RARE, "first_kex_packet_follows guess was wrong, " + "ignoring first SSH_MSG_KEXDH_INIT message"); + session->first_kex_follows_guess_wrong = 0; + goto error; + } + switch(session->next_crypto->kex_type){ case SSH_KEX_DH_GROUP1_SHA1: case SSH_KEX_DH_GROUP14_SHA1: @@ -217,6 +226,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; } @@ -241,9 +251,9 @@ int ssh_get_key_params(ssh_session session, ssh_key *privkey){ static int dh_handshake_server(ssh_session session) { ssh_key privkey; - //ssh_string pubkey_blob = NULL; ssh_string sig_blob; ssh_string f; + int rc; if (dh_generate_y(session) < 0) { ssh_set_error(session, SSH_FATAL, "Could not create y number"); @@ -284,25 +294,26 @@ static int dh_handshake_server(ssh_session session) { return -1; } - if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY) < 0 || - buffer_add_ssh_string(session->out_buffer, - session->next_crypto->server_pubkey) < 0 || - buffer_add_ssh_string(session->out_buffer, f) < 0 || - buffer_add_ssh_string(session->out_buffer, sig_blob) < 0) { - ssh_set_error(session, SSH_FATAL, "Not enough space"); - buffer_reinit(session->out_buffer); - ssh_string_free(f); - ssh_string_free(sig_blob); - return -1; - } + rc = ssh_buffer_pack(session->out_buffer, + "bSSS", + SSH2_MSG_KEXDH_REPLY, + session->next_crypto->server_pubkey, + f, + sig_blob); ssh_string_free(f); ssh_string_free(sig_blob); + if(rc != SSH_OK){ + ssh_set_error_oom(session); + ssh_buffer_reinit(session->out_buffer); + return -1; + } + if (packet_send(session) == SSH_ERROR) { return -1; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return -1; } @@ -581,12 +592,8 @@ int ssh_handle_key_exchange(ssh_session session) { */ int ssh_auth_reply_default(ssh_session session,int partial) { char methods_c[128] = {0}; - ssh_string methods = NULL; int rc = SSH_ERROR; - if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_FAILURE) < 0) { - return rc; - } if (session->auth_methods == 0) { session->auth_methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD; @@ -622,63 +629,43 @@ int ssh_auth_reply_default(ssh_session session,int partial) { SSH_LOG(SSH_LOG_PACKET, "Sending a auth failure. methods that can continue: %s", methods_c); - methods = ssh_string_from_char(methods_c); - if (methods == NULL) { - goto error; + rc = ssh_buffer_pack(session->out_buffer, + "bsb", + SSH2_MSG_USERAUTH_FAILURE, + methods_c, + partial ? 1 : 0); + if (rc != SSH_OK){ + ssh_set_error_oom(session); + return SSH_ERROR; } - - if (buffer_add_ssh_string(session->out_buffer, methods) < 0) { - goto error; - } - - if (partial) { - if (buffer_add_u8(session->out_buffer, 1) < 0) { - goto error; - } - } else { - if (buffer_add_u8(session->out_buffer, 0) < 0) { - goto error; - } - } - rc = packet_send(session); -error: - ssh_string_free(methods); - return rc; } static int ssh_message_channel_request_open_reply_default(ssh_message msg) { - SSH_LOG(SSH_LOG_FUNCTIONS, "Refusing a channel"); + int rc; - if (buffer_add_u8(msg->session->out_buffer - , SSH2_MSG_CHANNEL_OPEN_FAILURE) < 0) { - goto error; - } - if (buffer_add_u32(msg->session->out_buffer, - htonl(msg->channel_request_open.sender)) < 0) { - goto error; - } - if (buffer_add_u32(msg->session->out_buffer, - htonl(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED)) < 0) { - goto error; - } - /* reason is an empty string */ - if (buffer_add_u32(msg->session->out_buffer, 0) < 0) { - goto error; - } - /* language too */ - if (buffer_add_u32(msg->session->out_buffer, 0) < 0) { - goto error; - } + SSH_LOG(SSH_LOG_FUNCTIONS, "Refusing a channel"); - return packet_send(msg->session); -error: - return SSH_ERROR; + rc = ssh_buffer_pack(msg->session->out_buffer, + "bdddd", + SSH2_MSG_CHANNEL_OPEN_FAILURE, + msg->channel_request_open.sender, + SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, + 0, /* reason is empty string */ + 0); /* language string */ + if (rc != SSH_OK){ + ssh_set_error_oom(msg->session); + return SSH_ERROR; + } + + rc = packet_send(msg->session); + return rc; } static int ssh_message_channel_request_reply_default(ssh_message msg) { uint32_t channel; + int rc; if (msg->channel_request.want_reply) { channel = msg->channel_request.channel->remote_channel; @@ -686,13 +673,14 @@ static int ssh_message_channel_request_reply_default(ssh_message msg) { SSH_LOG(SSH_LOG_PACKET, "Sending a default channel_request denied to channel %d", channel); - if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_FAILURE) < 0) { - return SSH_ERROR; + rc = ssh_buffer_pack(msg->session->out_buffer, + "bd", + SSH2_MSG_CHANNEL_FAILURE, + channel); + if (rc != SSH_OK){ + ssh_set_error_oom(msg->session); + return SSH_ERROR; } - if (buffer_add_u32(msg->session->out_buffer, htonl(channel)) < 0) { - return SSH_ERROR; - } - return packet_send(msg->session); } @@ -708,33 +696,32 @@ static int ssh_message_service_request_reply_default(ssh_message msg) { } int ssh_message_service_reply_success(ssh_message msg) { - struct ssh_string_struct *service; - ssh_session session; + ssh_session session; + int rc; - if (msg == NULL) { - return SSH_ERROR; - } - session = msg->session; + if (msg == NULL) { + return SSH_ERROR; + } + session = msg->session; - SSH_LOG(SSH_LOG_PACKET, - "Sending a SERVICE_ACCEPT for service %s", msg->service_request.service); - if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_ACCEPT) < 0) { - return -1; - } - service=ssh_string_from_char(msg->service_request.service); - if (service == NULL) { - return -1; - } + SSH_LOG(SSH_LOG_PACKET, + "Sending a SERVICE_ACCEPT for service %s", msg->service_request.service); - if (buffer_add_ssh_string(session->out_buffer, service) < 0) { - ssh_string_free(service); - return -1; - } - ssh_string_free(service); - return packet_send(msg->session); + rc = ssh_buffer_pack(session->out_buffer, + "bs", + SSH2_MSG_SERVICE_ACCEPT, + msg->service_request.service); + if (rc != SSH_OK){ + ssh_set_error_oom(session); + return SSH_ERROR; + } + rc = packet_send(msg->session); + return rc; } int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_port) { + int rc; + SSH_LOG(SSH_LOG_FUNCTIONS, "Accepting a global request"); if (msg->global_request.want_reply) { @@ -745,7 +732,9 @@ int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_por if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD && msg->global_request.bind_port == 0) { - if (buffer_add_u32(msg->session->out_buffer, htonl(bound_port)) < 0) { + rc = ssh_buffer_pack(msg->session->out_buffer, "d", bound_port); + if (rc != SSH_ERROR) { + ssh_set_error_oom(msg->session); goto error; } } @@ -876,9 +865,8 @@ int ssh_message_auth_set_methods(ssh_message msg, int methods) { int ssh_message_auth_interactive_request(ssh_message msg, const char *name, const char *instruction, unsigned int num_prompts, const char **prompts, char *echo) { - int r; + int rc; unsigned int i = 0; - ssh_string tmp = NULL; if(name == NULL || instruction == NULL) { return SSH_ERROR; @@ -887,71 +875,30 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name, return SSH_ERROR; } - if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_USERAUTH_INFO_REQUEST) < 0) { - return SSH_ERROR; - } - - /* name */ - tmp = ssh_string_from_char(name); - if (tmp == NULL) { - return SSH_ERROR; - } - - r = buffer_add_ssh_string(msg->session->out_buffer, tmp); - ssh_string_free(tmp); - if (r < 0) { - return SSH_ERROR; - } - - /* instruction */ - tmp = ssh_string_from_char(instruction); - if (tmp == NULL) { - return SSH_ERROR; - } - - r = buffer_add_ssh_string(msg->session->out_buffer, tmp); - ssh_string_free(tmp); - if (r < 0) { - return SSH_ERROR; - } - - /* language tag */ - tmp = ssh_string_from_char(""); - if (tmp == NULL) { - return SSH_ERROR; - } - - r = buffer_add_ssh_string(msg->session->out_buffer, tmp); - ssh_string_free(tmp); - if (r < 0) { - return SSH_ERROR; - } - - /* num prompts */ - if (buffer_add_u32(msg->session->out_buffer, ntohl(num_prompts)) < 0) { + rc = ssh_buffer_pack(msg->session->out_buffer, + "bsssd", + SSH2_MSG_USERAUTH_INFO_REQUEST, + name, + instruction, + "", /* language tag */ + num_prompts); + if (rc != SSH_OK){ + ssh_set_error_oom(msg->session); return SSH_ERROR; } for(i = 0; i < num_prompts; i++) { - /* prompt[i] */ - tmp = ssh_string_from_char(prompts[i]); - if (tmp == NULL) { - return SSH_ERROR; - } - - r = buffer_add_ssh_string(msg->session->out_buffer, tmp); - ssh_string_free(tmp); - if (r < 0) { - return SSH_ERROR; - } - - /* echo[i] */ - if (buffer_add_u8(msg->session->out_buffer, echo[i]) < 0) { + rc = ssh_buffer_pack(msg->session->out_buffer, + "sb", + prompts[i], + echo[1] ? 1 : 0); + if (rc != SSH_OK){ + ssh_set_error_oom(msg->session); return SSH_ERROR; } } - r = packet_send(msg->session); + rc = packet_send(msg->session); /* fill in the kbdint structure */ if (msg->session->kbdint == NULL) { @@ -994,7 +941,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); @@ -1017,7 +964,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name, msg->session->kbdint->echo = NULL; } - return r; + return rc; } int ssh_auth_reply_success(ssh_session session, int partial) { @@ -1058,17 +1005,23 @@ int ssh_message_auth_reply_success(ssh_message msg, int partial) { /* Answer OK to a pubkey auth request */ int ssh_message_auth_reply_pk_ok(ssh_message msg, ssh_string algo, ssh_string pubkey) { - if (msg == NULL) { - return SSH_ERROR; - } + int rc; + if (msg == NULL) { + return SSH_ERROR; + } - if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_USERAUTH_PK_OK) < 0 || - buffer_add_ssh_string(msg->session->out_buffer, algo) < 0 || - buffer_add_ssh_string(msg->session->out_buffer, pubkey) < 0) { - return SSH_ERROR; - } + rc = ssh_buffer_pack(msg->session->out_buffer, + "bSS", + SSH2_MSG_USERAUTH_PK_OK, + algo, + pubkey); + if(rc != SSH_OK){ + ssh_set_error_oom(msg->session); + return SSH_ERROR; + } - return packet_send(msg->session); + rc = packet_send(msg->session); + return rc; } int ssh_message_auth_reply_pk_ok_simple(ssh_message msg) { @@ -1223,27 +1176,14 @@ int ssh_execute_message_callbacks(ssh_session session){ 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) { + rc = ssh_buffer_pack(session->out_buffer, + "bsb", + SSH2_MSG_GLOBAL_REQUEST, + "keepalive@openssh.com", + 1); + if (rc != SSH_OK) { goto err; } @@ -1251,14 +1191,14 @@ int ssh_send_keepalive(ssh_session session) goto err; } - ssh_handle_packets(session, 0); + ssh_handle_packets(session, SSH_TIMEOUT_NONBLOCKING); SSH_LOG(SSH_LOG_PACKET, "Sent a keepalive"); return SSH_OK; err: ssh_set_error_oom(session); - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_ERROR; } diff --git a/libssh/src/session.c b/libssh/src/session.c index d4b3643f..a3b19ede 100644 --- a/libssh/src/session.c +++ b/libssh/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 @@ -226,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; @@ -255,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]) { @@ -272,11 +280,26 @@ void ssh_free(ssh_session session) { } } - /* burn connection, it could hang sensitive datas */ + /* burn connection, it could contain sensitive data */ BURN_BUFFER(session, sizeof(struct ssh_session_struct)); SAFE_FREE(session); } +/** + * @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 * @@ -291,6 +314,68 @@ const char* ssh_get_serverbanner(ssh_session session) { return session->serverbanner; } +/** + * @brief get the name of the input cipher 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 get the name of the input HMAC algorithm for the given session. + * + * @param[in] session The SSH session. + * + * @return Returns HMAC algorithm name or NULL if unknown. + */ +const char* ssh_get_hmac_in(ssh_session session) { + if ((session != NULL) && + (session->current_crypto != NULL)) { + return ssh_hmac_type_to_string(session->current_crypto->in_hmac); + } + return NULL; +} + +/** + * @brief get the name of the output HMAC algorithm for the given session. + * + * @param[in] session The SSH session. + * + * @return Returns HMAC algorithm name or NULL if unknown. + */ +const char* ssh_get_hmac_out(ssh_session session) { + if ((session != NULL) && + (session->current_crypto != NULL)) { + return ssh_hmac_type_to_string(session->current_crypto->out_hmac); + } + return NULL; +} + /** * @brief Disconnect impolitely from a remote host by closing the socket. * @@ -476,9 +561,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) { @@ -551,7 +634,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); @@ -607,6 +694,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. * @@ -660,8 +766,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); } @@ -674,33 +785,26 @@ void ssh_socket_exception_callback(int code, int errno_code, void *user){ * @return SSH_OK on success, SSH_ERROR otherwise. */ int ssh_send_ignore (ssh_session session, const char *data) { - ssh_string str; + int rc; if (ssh_socket_is_open(session->socket)) { - if (buffer_add_u8(session->out_buffer, SSH2_MSG_IGNORE) < 0) { + + rc = ssh_buffer_pack(session->out_buffer, + "bs", + SSH2_MSG_IGNORE, + data); + if (rc != SSH_OK){ + ssh_set_error_oom(session); goto error; } - - str = ssh_string_from_char(data); - if (str == NULL) { - goto error; - } - - if (buffer_add_ssh_string(session->out_buffer, str) < 0) { - ssh_string_free(str); - goto error; - } - packet_send(session); ssh_handle_packets(session, 0); - - ssh_string_free(str); } return SSH_OK; error: - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_ERROR; } @@ -716,34 +820,19 @@ error: * @return SSH_OK on success, SSH_ERROR otherwise. */ int ssh_send_debug (ssh_session session, const char *message, int always_display) { - ssh_string str; int rc; if (ssh_socket_is_open(session->socket)) { - if (buffer_add_u8(session->out_buffer, SSH2_MSG_DEBUG) < 0) { + rc = ssh_buffer_pack(session->out_buffer, + "bbsd", + SSH2_MSG_DEBUG, + always_display != 0 ? 1 : 0, + message, + 0); /* empty language tag */ + if (rc != SSH_OK) { + ssh_set_error_oom(session); goto error; } - - if (buffer_add_u8(session->out_buffer, always_display) < 0) { - goto error; - } - - str = ssh_string_from_char(message); - if (str == NULL) { - goto error; - } - - rc = buffer_add_ssh_string(session->out_buffer, str); - ssh_string_free(str); - if (rc < 0) { - goto error; - } - - /* Empty language tag */ - if (buffer_add_u32(session->out_buffer, 0) < 0) { - goto error; - } - packet_send(session); ssh_handle_packets(session, 0); } @@ -751,10 +840,49 @@ int ssh_send_debug (ssh_session session, const char *message, int always_display return SSH_OK; error: - buffer_reinit(session->out_buffer); + ssh_buffer_reinit(session->out_buffer); return SSH_ERROR; } + /** + * @brief Set the session data counters. + * + * This functions sets the counter structures to be used to calculate data + * which comes in and goes out through the session at different levels. + * + * @code + * struct ssh_counter_struct scounter = { + * .in_bytes = 0, + * .out_bytes = 0, + * .in_packets = 0, + * .out_packets = 0 + * }; + * + * struct ssh_counter_struct rcounter = { + * .in_bytes = 0, + * .out_bytes = 0, + * .in_packets = 0, + * .out_packets = 0 + * }; + * + * ssh_set_counters(session, &scounter, &rcounter); + * @endcode + * + * @param[in] session The SSH session. + * + * @param[in] scounter Counter for byte data handled by the session sockets. + * + * @param[in] rcounter Counter for byte and packet data handled by the session, + * prior compression and SSH overhead. + */ +void ssh_set_counters(ssh_session session, ssh_counter scounter, + ssh_counter rcounter) { + if (session != NULL) { + session->socket_counter = scounter; + session->raw_counter = rcounter; + } +} + /** @} */ /* vim: set ts=4 sw=4 et cindent: */ diff --git a/libssh/src/sftp.c b/libssh/src/sftp.c index 62460b4d..b57da645 100644 --- a/libssh/src/sftp.c +++ b/libssh/src/sftp.c @@ -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 + * Copyright (c) 2008-2009 by Andreas Schneider * * 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; @@ -332,7 +332,7 @@ sftp_packet sftp_packet_read(sftp_session sftp) { SAFE_FREE(packet); return NULL; } - buffer_add_data(packet->payload,buffer, r); + ssh_buffer_add_data(packet->payload, buffer, r); if (buffer_get_u32(packet->payload, &size) != sizeof(uint32_t)) { ssh_set_error(sftp->session, SSH_FATAL, "Short sftp packet!"); ssh_buffer_free(packet->payload); @@ -348,7 +348,7 @@ sftp_packet sftp_packet_read(sftp_session sftp) { SAFE_FREE(packet); return NULL; } - buffer_add_data(packet->payload, buffer, r); + ssh_buffer_add_data(packet->payload, buffer, r); buffer_get_u8(packet->payload, &packet->type); size=size-1; while (size>0){ @@ -361,7 +361,7 @@ sftp_packet sftp_packet_read(sftp_session sftp) { SAFE_FREE(packet); return NULL; } - if(buffer_add_data(packet->payload,buffer,r)==SSH_ERROR){ + if (ssh_buffer_add_data(packet->payload, buffer, r) == SSH_ERROR) { ssh_buffer_free(packet->payload); SAFE_FREE(packet); ssh_set_error_oom(sftp->session); @@ -421,6 +421,7 @@ static void sftp_message_free(sftp_message msg) { static sftp_message sftp_get_message(sftp_packet packet) { sftp_session sftp = packet->sftp; sftp_message msg = NULL; + int rc; msg = sftp_message_new(sftp); if (msg == NULL) { @@ -439,7 +440,8 @@ static sftp_message sftp_get_message(sftp_packet packet) { return NULL; } - if (buffer_get_u32(packet->payload, &msg->id) != sizeof(uint32_t)) { + rc = ssh_buffer_unpack(packet->payload, "d", &msg->id); + if (rc != SSH_OK) { ssh_set_error(packet->sftp->session, SSH_FATAL, "Invalid packet %d: no ID", packet->type); sftp_message_free(msg); @@ -451,7 +453,7 @@ static sftp_message sftp_get_message(sftp_packet packet) { msg->id, msg->packet_type); - if (buffer_add_data(msg->payload, buffer_get_rest(packet->payload), + if (ssh_buffer_add_data(msg->payload, buffer_get_rest(packet->payload), buffer_get_rest_len(packet->payload)) < 0) { ssh_set_error_oom(sftp->session); sftp_message_free(msg); @@ -497,11 +499,10 @@ void sftp_packet_free(sftp_packet packet) { int sftp_init(sftp_session sftp) { sftp_packet packet = NULL; ssh_buffer buffer = NULL; - ssh_string ext_name_s = NULL; - ssh_string ext_data_s = NULL; char *ext_name = NULL; char *ext_data = NULL; - uint32_t version = htonl(LIBSFTP_VERSION); + uint32_t version; + int rc; buffer = ssh_buffer_new(); if (buffer == NULL) { @@ -509,7 +510,8 @@ int sftp_init(sftp_session sftp) { return -1; } - if (buffer_add_u32(buffer, version) < 0) { + rc = ssh_buffer_pack(buffer, "d", LIBSFTP_VERSION); + if (rc != SSH_OK) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); return -1; @@ -533,68 +535,48 @@ int sftp_init(sftp_session sftp) { } /* TODO: are we sure there are 4 bytes ready? */ - buffer_get_u32(packet->payload, &version); - version = ntohl(version); + rc = ssh_buffer_unpack(packet->payload, "d", &version); + if (rc != SSH_OK){ + return -1; + } SSH_LOG(SSH_LOG_RARE, "SFTP server version %d", version); - - ext_name_s = buffer_get_ssh_string(packet->payload); - while (ext_name_s != NULL) { + rc = ssh_buffer_unpack(packet->payload, "s", &ext_name); + while (rc == SSH_OK) { int count = sftp->ext->count; - char **tmp; - ext_data_s = buffer_get_ssh_string(packet->payload); - if (ext_data_s == NULL) { - ssh_string_free(ext_name_s); + rc = ssh_buffer_unpack(packet->payload, "s", &ext_data); + if (rc == SSH_ERROR) { break; } - ext_name = ssh_string_to_char(ext_name_s); - ext_data = ssh_string_to_char(ext_data_s); - if (ext_name == NULL || ext_data == NULL) { - ssh_set_error_oom(sftp->session); - SAFE_FREE(ext_name); - SAFE_FREE(ext_data); - ssh_string_free(ext_name_s); - ssh_string_free(ext_data_s); - return -1; - } SSH_LOG(SSH_LOG_RARE, "SFTP server extension: %s, version: %s", ext_name, ext_data); count++; - tmp = realloc(sftp->ext->name, count * sizeof(char *)); - if (tmp == NULL) { + sftp->ext->name = realloc(sftp->ext->name, count * sizeof(char *)); + if (sftp->ext->name == NULL) { ssh_set_error_oom(sftp->session); SAFE_FREE(ext_name); SAFE_FREE(ext_data); - ssh_string_free(ext_name_s); - ssh_string_free(ext_data_s); return -1; } - tmp[count - 1] = ext_name; - sftp->ext->name = tmp; + sftp->ext->name[count - 1] = ext_name; - tmp = realloc(sftp->ext->data, count * sizeof(char *)); - if (tmp == NULL) { + sftp->ext->data = realloc(sftp->ext->data, count * sizeof(char *)); + if (sftp->ext->data == NULL) { ssh_set_error_oom(sftp->session); SAFE_FREE(ext_name); SAFE_FREE(ext_data); - ssh_string_free(ext_name_s); - ssh_string_free(ext_data_s); return -1; } - tmp[count - 1] = ext_data; - sftp->ext->data = tmp; + sftp->ext->data[count - 1] = ext_data; sftp->ext->count = count; - ssh_string_free(ext_name_s); - ssh_string_free(ext_data_s); - - ext_name_s = buffer_get_ssh_string(packet->payload); + rc = ssh_buffer_unpack(packet->payload, "s", &ext_name); } sftp_packet_free(packet); @@ -766,6 +748,7 @@ static inline uint32_t sftp_get_new_id(sftp_session session) { static sftp_status_message parse_status_msg(sftp_message msg){ sftp_status_message status; + int rc; if (msg->packet_type != SSH_FXP_STATUS) { ssh_set_error(msg->sftp->session, SSH_FATAL, @@ -781,34 +764,28 @@ static sftp_status_message parse_status_msg(sftp_message msg){ ZERO_STRUCTP(status); status->id = msg->id; - if (buffer_get_u32(msg->payload,&status->status) != 4){ + rc = ssh_buffer_unpack(msg->payload, "d", + &status->status); + if (rc != SSH_OK){ SAFE_FREE(status); ssh_set_error(msg->sftp->session, SSH_FATAL, "Invalid SSH_FXP_STATUS message"); return NULL; } - status->error = buffer_get_ssh_string(msg->payload); - status->lang = buffer_get_ssh_string(msg->payload); - if(status->error == NULL || status->lang == NULL){ - if(msg->sftp->version >=3){ + rc = ssh_buffer_unpack(msg->payload, "ss", + &status->errormsg, + &status->langmsg); + + if(rc != SSH_OK && msg->sftp->version >=3){ /* These are mandatory from version 3 */ - ssh_string_free(status->error); - /* status->lang never get allocated if something failed */ SAFE_FREE(status); ssh_set_error(msg->sftp->session, SSH_FATAL, "Invalid SSH_FXP_STATUS message"); return NULL; - } } - - status->status = ntohl(status->status); - if(status->error) - status->errormsg = ssh_string_to_char(status->error); - else + if (status->errormsg == NULL) status->errormsg = strdup("No error message in packet"); - if(status->lang) - status->langmsg = ssh_string_to_char(status->lang); - else + if (status->langmsg == NULL) status->langmsg = strdup(""); if (status->errormsg == NULL || status->langmsg == NULL) { ssh_set_error_oom(msg->sftp->session); @@ -824,8 +801,6 @@ static void status_msg_free(sftp_status_message status){ return; } - ssh_string_free(status->error); - ssh_string_free(status->lang); SAFE_FREE(status->errormsg); SAFE_FREE(status->langmsg); SAFE_FREE(status); @@ -886,7 +861,7 @@ sftp_dir sftp_opendir(sftp_session sftp, const char *path){ } id = sftp_get_new_id(sftp); - if (buffer_add_u32(payload, id) < 0 || + if (buffer_add_u32(payload, htonl(id)) < 0 || buffer_add_ssh_string(payload, path_s) < 0) { ssh_set_error_oom(sftp->session); ssh_buffer_free(payload); @@ -998,7 +973,7 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf, break; } attr->owner = ssh_string_to_char(owner); - string_free(owner); + ssh_string_free(owner); if (attr->owner == NULL) { break; } @@ -1008,7 +983,7 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf, break; } attr->group = ssh_string_to_char(group); - string_free(group); + ssh_string_free(group); if (attr->group == NULL) { break; } @@ -1191,148 +1166,135 @@ static char *sftp_parse_longname(const char *longname, ... more extended data (extended_type - extended_data pairs), so that number of pairs equals extended_count */ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, - int expectname) { - ssh_string longname; - ssh_string name; - sftp_attributes attr; - uint32_t flags = 0; - int ok = 0; + int expectname) { + sftp_attributes attr; + int rc; - attr = malloc(sizeof(struct sftp_attributes_struct)); - if (attr == NULL) { - ssh_set_error_oom(sftp->session); - return NULL; - } - ZERO_STRUCTP(attr); + attr = malloc(sizeof(struct sftp_attributes_struct)); + if (attr == NULL) { + ssh_set_error_oom(sftp->session); + return NULL; + } + ZERO_STRUCTP(attr); - /* This isn't really a loop, but it is like a try..catch.. */ - do { if (expectname) { - name = buffer_get_ssh_string(buf); - if (name == NULL) { - break; - } - attr->name = ssh_string_to_char(name); - ssh_string_free(name); - if (attr->name == NULL) { - break; - } - - SSH_LOG(SSH_LOG_RARE, "Name: %s", attr->name); - - longname = buffer_get_ssh_string(buf); - if (longname == NULL) { - break; - } - attr->longname = ssh_string_to_char(longname); - ssh_string_free(longname); - if (attr->longname == NULL) { - break; - } - - /* Set owner and group if we talk to openssh and have the longname */ - if (ssh_get_openssh_version(sftp->session)) { - attr->owner = sftp_parse_longname(attr->longname, SFTP_LONGNAME_OWNER); - if (attr->owner == NULL) { - break; + rc = ssh_buffer_unpack(buf, "ss", + &attr->name, + &attr->longname); + if (rc != SSH_OK){ + goto error; } + SSH_LOG(SSH_LOG_RARE, "Name: %s", attr->name); - attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP); - if (attr->group == NULL) { - break; + /* Set owner and group if we talk to openssh and have the longname */ + if (ssh_get_openssh_version(sftp->session)) { + attr->owner = sftp_parse_longname(attr->longname, SFTP_LONGNAME_OWNER); + if (attr->owner == NULL) { + goto error; + } + + attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP); + if (attr->group == NULL) { + goto error; + } } - } } - if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) { - break; + rc = ssh_buffer_unpack(buf, "d", &attr->flags); + if (rc != SSH_OK){ + goto error; } - flags = ntohl(flags); - attr->flags = flags; SSH_LOG(SSH_LOG_RARE, - "Flags: %.8lx\n", (long unsigned int) flags); + "Flags: %.8lx\n", (long unsigned int) attr->flags); - if (flags & SSH_FILEXFER_ATTR_SIZE) { - if(buffer_get_u64(buf, &attr->size) != sizeof(uint64_t)) { - break; - } - attr->size = ntohll(attr->size); - SSH_LOG(SSH_LOG_RARE, - "Size: %llu\n", - (long long unsigned int) attr->size); + if (attr->flags & SSH_FILEXFER_ATTR_SIZE) { + rc = ssh_buffer_unpack(buf, "q", &attr->size); + if(rc != SSH_OK) { + goto error; + } + SSH_LOG(SSH_LOG_RARE, + "Size: %llu\n", + (long long unsigned int) attr->size); } - if (flags & SSH_FILEXFER_ATTR_UIDGID) { - if (buffer_get_u32(buf, &attr->uid) != sizeof(uint32_t)) { - break; - } - if (buffer_get_u32(buf, &attr->gid) != sizeof(uint32_t)) { - break; - } - attr->uid = ntohl(attr->uid); - attr->gid = ntohl(attr->gid); + if (attr->flags & SSH_FILEXFER_ATTR_UIDGID) { + rc = ssh_buffer_unpack(buf, "dd", + &attr->uid, + &attr->gid); + if (rc != SSH_OK){ + goto error; + } } - if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) { - if (buffer_get_u32(buf, &attr->permissions) != sizeof(uint32_t)) { - break; - } - attr->permissions = ntohl(attr->permissions); + if (attr->flags & SSH_FILEXFER_ATTR_PERMISSIONS) { + rc = ssh_buffer_unpack(buf, "d", &attr->permissions); + if (rc != SSH_OK){ + goto error; + } - switch (attr->permissions & S_IFMT) { + switch (attr->permissions & S_IFMT) { case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: - attr->type = SSH_FILEXFER_TYPE_SPECIAL; - break; + attr->type = SSH_FILEXFER_TYPE_SPECIAL; + break; case S_IFLNK: - attr->type = SSH_FILEXFER_TYPE_SYMLINK; - break; + attr->type = SSH_FILEXFER_TYPE_SYMLINK; + break; case S_IFREG: - attr->type = SSH_FILEXFER_TYPE_REGULAR; - break; + attr->type = SSH_FILEXFER_TYPE_REGULAR; + break; case S_IFDIR: - attr->type = SSH_FILEXFER_TYPE_DIRECTORY; - break; + attr->type = SSH_FILEXFER_TYPE_DIRECTORY; + break; default: - attr->type = SSH_FILEXFER_TYPE_UNKNOWN; - break; - } + attr->type = SSH_FILEXFER_TYPE_UNKNOWN; + break; + } } - if (flags & SSH_FILEXFER_ATTR_ACMODTIME) { - if (buffer_get_u32(buf, &attr->atime) != sizeof(uint32_t)) { - break; - } - attr->atime = ntohl(attr->atime); - if (buffer_get_u32(buf, &attr->mtime) != sizeof(uint32_t)) { - break; - } - attr->mtime = ntohl(attr->mtime); + if (attr->flags & SSH_FILEXFER_ATTR_ACMODTIME) { + rc = ssh_buffer_unpack(buf, "dd", + &attr->atime, + &attr->mtime); + if (rc != SSH_OK){ + goto error; + } } - if (flags & SSH_FILEXFER_ATTR_EXTENDED) { - if (buffer_get_u32(buf, &attr->extended_count) != sizeof(uint32_t)) { - break; - } + if (attr->flags & SSH_FILEXFER_ATTR_EXTENDED) { + rc = ssh_buffer_unpack(buf, "d", &attr->extended_count); + if (rc != SSH_OK){ + goto error; + } - attr->extended_count = ntohl(attr->extended_count); - while (attr->extended_count && - (attr->extended_type = buffer_get_ssh_string(buf)) - && (attr->extended_data = buffer_get_ssh_string(buf))) { - attr->extended_count--; - } + if (attr->extended_count > 0){ + rc = ssh_buffer_unpack(buf, "ss", + &attr->extended_type, + &attr->extended_data); + if (rc != SSH_OK){ + goto error; + } + attr->extended_count--; + } + /* just ignore the remaining extensions */ - if (attr->extended_count) { - break; - } + while (attr->extended_count > 0){ + ssh_string tmp1,tmp2; + rc = ssh_buffer_unpack(buf, "SS", &tmp1, &tmp2); + if (rc != SSH_OK){ + goto error; + } + SAFE_FREE(tmp1); + SAFE_FREE(tmp2); + attr->extended_count--; + } } - ok = 1; - } while (0); - if (!ok) { - /* break issued somewhere */ + return attr; + + error: ssh_string_free(attr->extended_type); ssh_string_free(attr->extended_data); SAFE_FREE(attr->name); @@ -1340,55 +1302,53 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, SAFE_FREE(attr->owner); SAFE_FREE(attr->group); SAFE_FREE(attr); - ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure"); return NULL; - } - - /* everything went smoothly */ - return attr; } /* FIXME is this really needed as a public function? */ int buffer_add_attributes(ssh_buffer buffer, sftp_attributes attr) { uint32_t flags = (attr ? attr->flags : 0); + int rc; flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME); - if (buffer_add_u32(buffer, htonl(flags)) < 0) { + rc = ssh_buffer_pack(buffer, "d", flags); + if (rc != SSH_OK) { return -1; } - if (attr) { + if (attr != NULL) { if (flags & SSH_FILEXFER_ATTR_SIZE) { - if (buffer_add_u64(buffer, htonll(attr->size)) < 0) { + rc = ssh_buffer_pack(buffer, "q", attr->size); + if (rc != SSH_OK) { return -1; } } if (flags & SSH_FILEXFER_ATTR_UIDGID) { - if (buffer_add_u32(buffer,htonl(attr->uid)) < 0 || - buffer_add_u32(buffer,htonl(attr->gid)) < 0) { + rc = ssh_buffer_pack(buffer, "dd", attr->uid, attr->gid); + if (rc != SSH_OK) { return -1; } } if (flags & SSH_FILEXFER_ATTR_PERMISSIONS) { - if (buffer_add_u32(buffer, htonl(attr->permissions)) < 0) { + rc = ssh_buffer_pack(buffer, "d", attr->permissions); + if (rc != SSH_OK) { return -1; } } if (flags & SSH_FILEXFER_ATTR_ACMODTIME) { - if (buffer_add_u32(buffer, htonl(attr->atime)) < 0 || - buffer_add_u32(buffer, htonl(attr->mtime)) < 0) { + rc = ssh_buffer_pack(buffer, "dd", attr->atime, attr->mtime); + if (rc != SSH_OK) { return -1; } } } - return 0; } @@ -1433,7 +1393,7 @@ sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) { } id = sftp_get_new_id(sftp); - if (buffer_add_u32(payload, id) < 0 || + if (buffer_add_u32(payload, htonl(id)) < 0 || buffer_add_ssh_string(payload, dir->handle) < 0) { ssh_set_error_oom(sftp->session); ssh_buffer_free(payload); @@ -1557,7 +1517,7 @@ static int sftp_handle_close(sftp_session sftp, ssh_string handle) { } id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, handle) < 0) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); @@ -1681,7 +1641,7 @@ sftp_file sftp_open(sftp_session sftp, const char *file, int flags, sftp_flags |= SSH_FXF_EXCL; SSH_LOG(SSH_LOG_PACKET,"Opening file %s with sftp flags %x",file,sftp_flags); id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, filename) < 0) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); @@ -1751,6 +1711,7 @@ ssize_t sftp_read(sftp_file handle, void *buf, size_t count) { ssh_string datastring; ssh_buffer buffer; int id; + int rc; if (handle->eof) { return 0; @@ -1761,11 +1722,16 @@ ssize_t sftp_read(sftp_file handle, void *buf, size_t count) { ssh_set_error_oom(sftp->session); return -1; } + id = sftp_get_new_id(handle->sftp); - if (buffer_add_u32(buffer, id) < 0 || - buffer_add_ssh_string(buffer, handle->handle) < 0 || - buffer_add_u64(buffer, htonll(handle->offset)) < 0 || - buffer_add_u32(buffer,htonl(count)) < 0) { + + rc = ssh_buffer_pack(buffer, + "dSqd", + id, + handle->handle, + handle->offset, + count); + if (rc != SSH_OK){ ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); return -1; @@ -1847,6 +1813,7 @@ int sftp_async_read_begin(sftp_file file, uint32_t len){ sftp_session sftp = file->sftp; ssh_buffer buffer; uint32_t id; + int rc; buffer = ssh_buffer_new(); if (buffer == NULL) { @@ -1855,10 +1822,14 @@ int sftp_async_read_begin(sftp_file file, uint32_t len){ } id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || - buffer_add_ssh_string(buffer, file->handle) < 0 || - buffer_add_u64(buffer, htonll(file->offset)) < 0 || - buffer_add_u32(buffer, htonl(len)) < 0) { + + rc = ssh_buffer_pack(buffer, + "dSqd", + id, + file->handle, + file->offset, + len); + if (rc != SSH_OK) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); return -1; @@ -1961,11 +1932,11 @@ ssize_t sftp_write(sftp_file file, const void *buf, size_t count) { sftp_session sftp = file->sftp; sftp_message msg = NULL; sftp_status_message status; - ssh_string datastring; ssh_buffer buffer; uint32_t id; int len; int packetlen; + int rc; buffer = ssh_buffer_new(); if (buffer == NULL) { @@ -1973,25 +1944,20 @@ ssize_t sftp_write(sftp_file file, const void *buf, size_t count) { return -1; } - datastring = ssh_string_new(count); - if (datastring == NULL) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - return -1; - } - ssh_string_fill(datastring, buf, count); - id = sftp_get_new_id(file->sftp); - if (buffer_add_u32(buffer, id) < 0 || - buffer_add_ssh_string(buffer, file->handle) < 0 || - buffer_add_u64(buffer, htonll(file->offset)) < 0 || - buffer_add_ssh_string(buffer, datastring) < 0) { + + rc = ssh_buffer_pack(buffer, + "dSqdP", + id, + file->handle, + file->offset, + count, /* len of datastring */ + (size_t)count, buf); + if (rc != SSH_OK){ ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); - ssh_string_free(datastring); return -1; } - ssh_string_free(datastring); packetlen=buffer_get_rest_len(buffer); len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer); ssh_buffer_free(buffer); @@ -2083,9 +2049,9 @@ void sftp_rewind(sftp_file file) { int sftp_unlink(sftp_session sftp, const char *file) { sftp_status_message status = NULL; sftp_message msg = NULL; - ssh_string filename; ssh_buffer buffer; uint32_t id; + int rc; buffer = ssh_buffer_new(); if (buffer == NULL) { @@ -2093,27 +2059,22 @@ int sftp_unlink(sftp_session sftp, const char *file) { return -1; } - filename = ssh_string_from_char(file); - if (filename == NULL) { + id = sftp_get_new_id(sftp); + + rc = ssh_buffer_pack(buffer, + "ds", + id, + file); + if (rc != SSH_OK) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); return -1; } - id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || - buffer_add_ssh_string(buffer, filename) < 0) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - ssh_string_free(filename); - return -1; - } if (sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer) < 0) { ssh_buffer_free(buffer); - ssh_string_free(filename); return -1; } - ssh_string_free(filename); ssh_buffer_free(buffer); while (msg == NULL) { @@ -2160,9 +2121,9 @@ int sftp_unlink(sftp_session sftp, const char *file) { int sftp_rmdir(sftp_session sftp, const char *directory) { sftp_status_message status = NULL; sftp_message msg = NULL; - ssh_string filename; ssh_buffer buffer; uint32_t id; + int rc; buffer = ssh_buffer_new(); if (buffer == NULL) { @@ -2170,28 +2131,22 @@ int sftp_rmdir(sftp_session sftp, const char *directory) { return -1; } - filename = ssh_string_from_char(directory); - if (filename == NULL) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - return -1; - } - id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || - buffer_add_ssh_string(buffer, filename) < 0) { + + rc = ssh_buffer_pack(buffer, + "ds", + id, + directory); + if (rc != SSH_OK) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); - ssh_string_free(filename); return -1; } if (sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer) < 0) { ssh_buffer_free(buffer); - ssh_string_free(filename); return -1; } ssh_buffer_free(buffer); - ssh_string_free(filename); while (msg == NULL) { if (sftp_read_and_dispatch(sftp) < 0) { @@ -2258,7 +2213,7 @@ int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode) { attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS; id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, path) < 0 || buffer_add_attributes(buffer, &attr) < 0 || sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer) < 0) { @@ -2327,9 +2282,8 @@ int sftp_rename(sftp_session sftp, const char *original, const char *newname) { sftp_status_message status = NULL; sftp_message msg = NULL; ssh_buffer buffer; - ssh_string oldpath; - ssh_string newpath; uint32_t id; + int rc; buffer = ssh_buffer_new(); if (buffer == NULL) { @@ -2337,43 +2291,30 @@ int sftp_rename(sftp_session sftp, const char *original, const char *newname) { return -1; } - oldpath = ssh_string_from_char(original); - if (oldpath == NULL) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - return -1; - } - - newpath = ssh_string_from_char(newname); - if (newpath == NULL) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - ssh_string_free(oldpath); - return -1; - } - id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || - buffer_add_ssh_string(buffer, oldpath) < 0 || - buffer_add_ssh_string(buffer, newpath) < 0 || + + rc = ssh_buffer_pack(buffer, + "dss", + id, + original, + newname); + if (rc != SSH_OK) { + ssh_set_error_oom(sftp->session); + ssh_buffer_free(buffer); + return -1; + } + + if (sftp->version >= 4){ /* POSIX rename atomically replaces newpath, we should do the same * only available on >=v4 */ - sftp->version>=4 ? (buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE) < 0):0) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - ssh_string_free(oldpath); - ssh_string_free(newpath); - return -1; + buffer_add_u32(buffer, SSH_FXF_RENAME_OVERWRITE); } + if (sftp_packet_write(sftp, SSH_FXP_RENAME, buffer) < 0) { ssh_buffer_free(buffer); - ssh_string_free(oldpath); - ssh_string_free(newpath); return -1; } ssh_buffer_free(buffer); - ssh_string_free(oldpath); - ssh_string_free(newpath); while (msg == NULL) { if (sftp_read_and_dispatch(sftp) < 0) { @@ -2438,7 +2379,7 @@ int sftp_setstat(sftp_session sftp, const char *file, sftp_attributes attr) { } id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, path) < 0 || buffer_add_attributes(buffer, attr) < 0) { ssh_set_error_oom(sftp->session); @@ -2537,10 +2478,9 @@ int sftp_utimes(sftp_session sftp, const char *file, int sftp_symlink(sftp_session sftp, const char *target, const char *dest) { sftp_status_message status = NULL; sftp_message msg = NULL; - ssh_string target_s; - ssh_string dest_s; ssh_buffer buffer; uint32_t id; + int rc; if (sftp == NULL) return -1; @@ -2555,59 +2495,33 @@ int sftp_symlink(sftp_session sftp, const char *target, const char *dest) { return -1; } - target_s = ssh_string_from_char(target); - if (target_s == NULL) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - return -1; - } - - dest_s = ssh_string_from_char(dest); - if (dest_s == NULL) { - ssh_set_error_oom(sftp->session); - ssh_string_free(target_s); - ssh_buffer_free(buffer); - return -1; - } - id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - ssh_string_free(dest_s); - ssh_string_free(target_s); - return -1; - } + + /* TODO check for version number if they ever fix it. */ if (ssh_get_openssh_version(sftp->session)) { - /* TODO check for version number if they ever fix it. */ - if (buffer_add_ssh_string(buffer, target_s) < 0 || - buffer_add_ssh_string(buffer, dest_s) < 0) { - ssh_set_error_oom(sftp->session); - ssh_buffer_free(buffer); - ssh_string_free(dest_s); - ssh_string_free(target_s); - return -1; - } + rc = ssh_buffer_pack(buffer, + "dss", + id, + target, + dest); } else { - if (buffer_add_ssh_string(buffer, dest_s) < 0 || - buffer_add_ssh_string(buffer, target_s) < 0) { + rc = ssh_buffer_pack(buffer, + "dss", + id, + dest, + target); + } + if (rc != SSH_OK){ ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); - ssh_string_free(dest_s); - ssh_string_free(target_s); return -1; - } } if (sftp_packet_write(sftp, SSH_FXP_SYMLINK, buffer) < 0) { ssh_buffer_free(buffer); - ssh_string_free(dest_s); - ssh_string_free(target_s); return -1; } ssh_buffer_free(buffer); - ssh_string_free(dest_s); - ssh_string_free(target_s); while (msg == NULL) { if (sftp_read_and_dispatch(sftp) < 0) { @@ -2682,7 +2596,7 @@ char *sftp_readlink(sftp_session sftp, const char *path) { } id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, path_s) < 0) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); @@ -2737,9 +2651,8 @@ char *sftp_readlink(sftp_session sftp, const char *path) { } static sftp_statvfs_t sftp_parse_statvfs(sftp_session sftp, ssh_buffer buf) { - sftp_statvfs_t statvfs; - uint64_t tmp; - int ok = 0; + sftp_statvfs_t statvfs; + int rc; statvfs = malloc(sizeof(struct sftp_statvfs_struct)); if (statvfs == NULL) { @@ -2748,78 +2661,20 @@ static sftp_statvfs_t sftp_parse_statvfs(sftp_session sftp, ssh_buffer buf) { } ZERO_STRUCTP(statvfs); - /* try .. catch */ - do { - /* file system block size */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_bsize = ntohll(tmp); - - /* fundamental fs block size */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_frsize = ntohll(tmp); - - /* number of blocks (unit f_frsize) */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_blocks = ntohll(tmp); - - /* free blocks in file system */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_bfree = ntohll(tmp); - - /* free blocks for non-root */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_bavail = ntohll(tmp); - - /* total file inodes */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_files = ntohll(tmp); - - /* free file inodes */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_ffree = ntohll(tmp); - - /* free file inodes for to non-root */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_favail = ntohll(tmp); - - /* file system id */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_fsid = ntohll(tmp); - - /* bit mask of f_flag values */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_flag = ntohll(tmp); - - /* maximum filename length */ - if (buffer_get_u64(buf, &tmp) != sizeof(uint64_t)) { - break; - } - statvfs->f_namemax = ntohll(tmp); - - ok = 1; - } while(0); - - if (!ok) { + rc = ssh_buffer_unpack(buf, "qqqqqqqqqqq", + &statvfs->f_bsize, /* file system block size */ + &statvfs->f_frsize, /* fundamental fs block size */ + &statvfs->f_blocks, /* number of blocks (unit f_frsize) */ + &statvfs->f_bfree, /* free blocks in file system */ + &statvfs->f_bavail, /* free blocks for non-root */ + &statvfs->f_files, /* total file inodes */ + &statvfs->f_ffree, /* free file inodes */ + &statvfs->f_favail, /* free file inodes for to non-root */ + &statvfs->f_fsid, /* file system id */ + &statvfs->f_flag, /* bit mask of f_flag values */ + &statvfs->f_namemax/* maximum filename length */ + ); + if (rc != SSH_OK) { SAFE_FREE(statvfs); ssh_set_error(sftp->session, SSH_FATAL, "Invalid statvfs structure"); return NULL; @@ -2869,7 +2724,7 @@ sftp_statvfs_t sftp_statvfs(sftp_session sftp, const char *path) { } id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, ext) < 0 || buffer_add_ssh_string(buffer, pathstr) < 0) { ssh_set_error_oom(sftp->session); @@ -2948,7 +2803,7 @@ sftp_statvfs_t sftp_fstatvfs(sftp_file file) { } id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, ext) < 0 || buffer_add_ssh_string(buffer, file->handle) < 0) { ssh_set_error_oom(sftp->session); @@ -3037,7 +2892,7 @@ char *sftp_canonicalize_path(sftp_session sftp, const char *path) { } id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, pathstr) < 0) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); @@ -3115,7 +2970,7 @@ static sftp_attributes sftp_xstat(sftp_session sftp, const char *path, } id = sftp_get_new_id(sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, pathstr) < 0) { ssh_set_error_oom(sftp->session); ssh_buffer_free(buffer); @@ -3182,7 +3037,7 @@ sftp_attributes sftp_fstat(sftp_file file) { } id = sftp_get_new_id(file->sftp); - if (buffer_add_u32(buffer, id) < 0 || + if (buffer_add_u32(buffer, htonl(id)) < 0 || buffer_add_ssh_string(buffer, file->handle) < 0) { ssh_set_error_oom(file->sftp->session); ssh_buffer_free(buffer); diff --git a/libssh/src/sftpserver.c b/libssh/src/sftpserver.c index 0986b6ce..60498794 100644 --- a/libssh/src/sftpserver.c +++ b/libssh/src/sftpserver.c @@ -42,7 +42,7 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { sftp_packet packet; sftp_client_message msg; ssh_buffer payload; - ssh_string tmp; + int rc; msg = malloc(sizeof (struct sftp_client_message_struct)); if (msg == NULL) { @@ -64,7 +64,9 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { /* take a copy of the whole packet */ msg->complete_message = ssh_buffer_new(); - buffer_add_data(msg->complete_message, buffer_get_rest(payload), buffer_get_rest_len(payload)); + ssh_buffer_add_data(msg->complete_message, + buffer_get_rest(payload), + buffer_get_rest_len(payload)); buffer_get_u32(payload, &msg->id); @@ -79,25 +81,24 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { } break; case SSH_FXP_READ: - msg->handle = buffer_get_ssh_string(payload); - if (msg->handle == NULL) { + rc = ssh_buffer_unpack(payload, + "Sqd", + &msg->handle, + &msg->offset, + &msg->len); + if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } - buffer_get_u64(payload, &msg->offset); - buffer_get_u32(payload, &msg->len); break; case SSH_FXP_WRITE: - msg->handle = buffer_get_ssh_string(payload); - if (msg->handle == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; - } - buffer_get_u64(payload, &msg->offset); - msg->data = buffer_get_ssh_string(payload); - if (msg->data == NULL) { + rc = ssh_buffer_unpack(payload, + "SqS", + &msg->handle, + &msg->offset, + &msg->data); + if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; @@ -108,15 +109,10 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { case SSH_FXP_OPENDIR: case SSH_FXP_READLINK: case SSH_FXP_REALPATH: - tmp = buffer_get_ssh_string(payload); - if (tmp == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; - } - msg->filename = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (msg->filename == NULL) { + rc = ssh_buffer_unpack(payload, + "s", + &msg->filename); + if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; @@ -124,21 +120,11 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { break; case SSH_FXP_RENAME: case SSH_FXP_SYMLINK: - tmp = buffer_get_ssh_string(payload); - if (tmp == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; - } - msg->filename = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (msg->filename == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; - } - msg->data = buffer_get_ssh_string(payload); - if (msg->data == NULL) { + rc = ssh_buffer_unpack(payload, + "sS", + &msg->filename, + &msg->data); + if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; @@ -146,15 +132,10 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { break; case SSH_FXP_MKDIR: case SSH_FXP_SETSTAT: - tmp = buffer_get_ssh_string(payload); - if (tmp == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; - } - msg->filename=ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (msg->filename == NULL) { + rc = ssh_buffer_unpack(payload, + "s", + &msg->filename); + if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; @@ -182,38 +163,28 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { break; case SSH_FXP_LSTAT: case SSH_FXP_STAT: - tmp = buffer_get_ssh_string(payload); - if (tmp == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; - } - msg->filename = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (msg->filename == NULL) { + rc = ssh_buffer_unpack(payload, + "s", + &msg->filename); + if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } if(sftp->version > 3) { - buffer_get_u32(payload,&msg->flags); + ssh_buffer_unpack(payload, "d", &msg->flags); } break; case SSH_FXP_OPEN: - tmp=buffer_get_ssh_string(payload); - if (tmp == NULL) { + rc = ssh_buffer_unpack(payload, + "sd", + &msg->filename, + &msg->flags); + if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } - msg->filename = ssh_string_to_char(tmp); - ssh_string_free(tmp); - if (msg->filename == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; - } - buffer_get_u32(payload,&msg->flags); msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { ssh_set_error_oom(session); @@ -222,13 +193,15 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { } break; case SSH_FXP_FSTAT: - msg->handle = buffer_get_ssh_string(payload); - if (msg->handle == NULL) { + rc = ssh_buffer_unpack(payload, + "Sd", + &msg->handle, + &msg->flags); + if (rc != SSH_OK) { ssh_set_error_oom(session); sftp_client_message_free(msg); return NULL; } - buffer_get_u32(payload, &msg->flags); break; default: ssh_set_error(sftp->session, SSH_FATAL, @@ -237,9 +210,6 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) { return NULL; } - msg->flags = ntohl(msg->flags); - msg->offset = ntohll(msg->offset); - msg->len = ntohl(msg->len); sftp_packet_free(packet); return msg; @@ -407,7 +377,7 @@ int sftp_reply_names(sftp_client_message msg) { if (buffer_add_u32(out, msg->id) < 0 || buffer_add_u32(out, htonl(msg->attr_num)) < 0 || - buffer_add_data(out, buffer_get_rest(msg->attrbuf), + ssh_buffer_add_data(out, buffer_get_rest(msg->attrbuf), buffer_get_rest_len(msg->attrbuf)) < 0 || sftp_packet_write(msg->sftp, SSH_FXP_NAME, out) < 0) { ssh_buffer_free(out); @@ -466,7 +436,7 @@ int sftp_reply_data(sftp_client_message msg, const void *data, int len) { if (buffer_add_u32(out, msg->id) < 0 || buffer_add_u32(out, ntohl(len)) < 0 || - buffer_add_data(out, data, len) < 0 || + ssh_buffer_add_data(out, data, len) < 0 || sftp_packet_write(msg->sftp, SSH_FXP_DATA, out) < 0) { ssh_buffer_free(out); return -1; diff --git a/libssh/src/socket.c b/libssh/src/socket.c index c76ef5ae..498da77e 100644 --- a/libssh/src/socket.c +++ b/libssh/src/socket.c @@ -182,8 +182,8 @@ void ssh_socket_reset(ssh_socket s){ s->fd_out= SSH_INVALID_SOCKET; s->last_errno = -1; s->fd_is_socket = 1; - buffer_reinit(s->in_buffer); - buffer_reinit(s->out_buffer); + ssh_buffer_reinit(s->in_buffer); + ssh_buffer_reinit(s->out_buffer); s->read_wontblock = 0; s->write_wontblock = 0; s->data_except = 0; @@ -204,7 +204,7 @@ void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){ } /** - * @brief SSH poll callback. This callback will be used when an event + * @brief SSH poll callback. This callback will be used when an event * caught on the socket. * * @param p Poll object this callback belongs to. @@ -216,123 +216,131 @@ void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){ * @return 0 on success, < 0 when the poll object has been removed * from its poll context. */ -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]; - int r; - int err=0; - socklen_t errlen=sizeof(err); - /* Do not do anything if this socket was already closed */ - if(!ssh_socket_is_open(s)){ - return -1; - } - if(revents & POLLERR || revents & POLLHUP){ - /* Check if we are in a connecting state */ - if(s->state==SSH_SOCKET_CONNECTING){ - s->state=SSH_SOCKET_ERROR; - r = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen); +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[MAX_BUF_SIZE]; + int r; + int err = 0; + socklen_t errlen = sizeof(err); + /* Do not do anything if this socket was already closed */ + if (!ssh_socket_is_open(s)) { + return -1; + } + if (revents & POLLERR || revents & POLLHUP) { + /* Check if we are in a connecting state */ + if (s->state == SSH_SOCKET_CONNECTING) { + s->state = SSH_SOCKET_ERROR; + r = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen); if (r < 0) { err = errno; } - s->last_errno=err; - ssh_socket_close(s); - if(s->callbacks && s->callbacks->connected) - s->callbacks->connected(SSH_SOCKET_CONNECTED_ERROR,err, - s->callbacks->userdata); - return -1; - } - /* Then we are in a more standard kind of error */ - /* force a read to get an explanation */ - revents |= POLLIN; - } - if(revents & POLLIN){ - s->read_wontblock=1; - r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer)); - if(r<0){ - if(p != NULL) { - ssh_poll_remove_events(p, POLLIN); - } - if(s->callbacks && s->callbacks->exception){ - s->callbacks->exception( - SSH_SOCKET_EXCEPTION_ERROR, - s->last_errno,s->callbacks->userdata); - /* p may have been freed, so don't use it - * anymore in this function */ - p = NULL; - return -2; - } - } - if(r==0){ - if(p != NULL) { - ssh_poll_remove_events(p, POLLIN); - } - if(p != NULL) { - ssh_poll_remove_events(p, POLLIN); - } - if(s->callbacks && s->callbacks->exception){ - s->callbacks->exception( - SSH_SOCKET_EXCEPTION_EOF, - 0,s->callbacks->userdata); - /* p may have been freed, so don't use it - * anymore in this function */ - p = NULL; - return -2; - } - } - if(r>0){ - /* Bufferize the data and then call the callback */ - r = buffer_add_data(s->in_buffer,buffer,r); + s->last_errno = err; + ssh_socket_close(s); + if (s->callbacks && s->callbacks->connected) { + s->callbacks->connected(SSH_SOCKET_CONNECTED_ERROR, err, + s->callbacks->userdata); + } + return -1; + } + /* Then we are in a more standard kind of error */ + /* force a read to get an explanation */ + 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) { + if (p != NULL) { + ssh_poll_remove_events(p, POLLIN); + } + if (s->callbacks && s->callbacks->exception) { + s->callbacks->exception(SSH_SOCKET_EXCEPTION_ERROR, + s->last_errno, s->callbacks->userdata); + /* p may have been freed, so don't use it + * anymore in this function */ + p = NULL; + return -2; + } + } + if (r == 0) { + if (p != NULL) { + ssh_poll_remove_events(p, POLLIN); + } + if (p != NULL) { + ssh_poll_remove_events(p, POLLIN); + } + if (s->callbacks && s->callbacks->exception) { + s->callbacks->exception(SSH_SOCKET_EXCEPTION_EOF, + 0, s->callbacks->userdata); + /* p may have been freed, so don't use it + * anymore in this function */ + p = NULL; + return -2; + } + } + if (r > 0) { + if (s->session->socket_counter != NULL) { + s->session->socket_counter->in_bytes += r; + } + /* Bufferize the data and then call the callback */ + r = ssh_buffer_add_data(s->in_buffer, buffer, r); if (r < 0) { return -1; } - if(s->callbacks && s->callbacks->data){ - do { - r= s->callbacks->data(buffer_get_rest(s->in_buffer), - buffer_get_rest_len(s->in_buffer), - s->callbacks->userdata); - buffer_pass_bytes(s->in_buffer,r); - } while (r > 0); - /* p may have been freed, so don't use it - * anymore in this function */ - p = NULL; - } - } - } + if (s->callbacks && s->callbacks->data) { + do { + r = s->callbacks->data(buffer_get_rest(s->in_buffer), + buffer_get_rest_len(s->in_buffer), + s->callbacks->userdata); + buffer_pass_bytes(s->in_buffer, r); + } while ((r > 0) && (s->state == SSH_SOCKET_CONNECTED)); + /* p may have been freed, so don't use it + * anymore in this function */ + p = NULL; + } + } + } #ifdef _WIN32 - if(revents & POLLOUT || revents & POLLWRNORM){ + if (revents & POLLOUT || revents & POLLWRNORM) { #else - if(revents & POLLOUT){ + if (revents & POLLOUT) { #endif - /* First, POLLOUT is a sign we may be connected */ - 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); + /* First, POLLOUT is a sign we may be connected */ + if (s->state == SSH_SOCKET_CONNECTING) { + SSH_LOG(SSH_LOG_PACKET, "Received POLLOUT in connecting state"); + s->state = SSH_SOCKET_CONNECTED; + 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; - } - /* So, we can write data */ - s->write_wontblock=1; - if(p != NULL) { + if (s->callbacks && s->callbacks->connected) { + s->callbacks->connected(SSH_SOCKET_CONNECTED_OK, 0, + s->callbacks->userdata); + } + return 0; + } + /* So, we can write data */ + s->write_wontblock=1; + if (p != NULL) { ssh_poll_remove_events(p, POLLOUT); } - /* If buffered data is pending, write it */ - if(buffer_get_rest_len(s->out_buffer) > 0){ - ssh_socket_nonblocking_flush(s); - } else if(s->callbacks && s->callbacks->controlflow){ - /* Otherwise advertise the upper level that write can be done */ - s->callbacks->controlflow(SSH_SOCKET_FLOW_WRITEWONTBLOCK,s->callbacks->userdata); - } - /* TODO: Find a way to put back POLLOUT when buffering occurs */ - } - /* Return -1 if one of the poll handlers disappeared */ - return (s->poll_in == NULL || s->poll_out == NULL) ? -1 : 0; + /* If buffered data is pending, write it */ + if (buffer_get_rest_len(s->out_buffer) > 0) { + ssh_socket_nonblocking_flush(s); + } else if (s->callbacks && s->callbacks->controlflow) { + /* Otherwise advertise the upper level that write can be done */ + s->callbacks->controlflow(SSH_SOCKET_FLOW_WRITEWONTBLOCK, + s->callbacks->userdata); + } + /* TODO: Find a way to put back POLLOUT when buffering occurs */ + } + /* Return -1 if one of the poll handlers disappeared */ + return (s->poll_in == NULL || s->poll_out == NULL) ? -1 : 0; } /** @internal @@ -438,6 +446,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 +459,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 + } } /** @@ -594,7 +614,7 @@ void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) { */ int ssh_socket_write(ssh_socket s, const void *buffer, int len) { if(len > 0) { - if (buffer_add_data(s->out_buffer, buffer, len) < 0) { + if (ssh_buffer_add_data(s->out_buffer, buffer, len) < 0) { ssh_set_error_oom(s->session); return SSH_ERROR; } @@ -645,6 +665,9 @@ int ssh_socket_nonblocking_flush(ssh_socket s) { return SSH_ERROR; } buffer_pass_bytes(s->out_buffer, w); + if (s->session->socket_counter != NULL) { + s->session->socket_counter->out_bytes += w; + } } /* Is there some data pending? */ @@ -695,11 +718,11 @@ int ssh_socket_buffered_write_bytes(ssh_socket s){ int ssh_socket_get_status(ssh_socket s) { int r = 0; - if (buffer_get_len(s->in_buffer) > 0) { + if (ssh_buffer_get_len(s->in_buffer) > 0) { r |= SSH_READ_PENDING; } - if (buffer_get_len(s->out_buffer) > 0) { + if (ssh_buffer_get_len(s->out_buffer) > 0) { r |= SSH_WRITE_PENDING; } @@ -710,6 +733,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 +793,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; } diff --git a/libssh/src/string.c b/libssh/src/string.c index 5ef90b0e..9002478f 100644 --- a/libssh/src/string.c +++ b/libssh/src/string.c @@ -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)); } /** diff --git a/libssh/src/threads.c b/libssh/src/threads.c index 107c65d2..7f3a304e 100644 --- a/libssh/src/threads.c +++ b/libssh/src/threads.c @@ -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 */ diff --git a/libssh/src/threads/CMakeLists.txt b/libssh/src/threads/CMakeLists.txt index b95525e4..a32d601e 100644 --- a/libssh/src/threads/CMakeLists.txt +++ b/libssh/src/threads/CMakeLists.txt @@ -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) diff --git a/libssh/src/wrapper.c b/libssh/src/wrapper.c index 51688753..bcd941b3 100644 --- a/libssh/src/wrapper.c +++ b/libssh/src/wrapper.c @@ -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 @@ -48,6 +48,46 @@ #include "libssh/wrapper.h" #include "libssh/pki.h" +static struct ssh_hmac_struct ssh_hmac_tab[] = { + { "hmac-sha1", SSH_HMAC_SHA1 }, + { "hmac-sha2-256", SSH_HMAC_SHA256 }, + { "hmac-sha2-384", SSH_HMAC_SHA384 }, + { "hmac-sha2-512", SSH_HMAC_SHA512 }, + { "hmac-md5", SSH_HMAC_MD5 }, + { NULL, 0} +}; + +struct ssh_hmac_struct *ssh_get_hmactab(void) { + return ssh_hmac_tab; +} + +size_t hmac_digest_len(enum ssh_hmac_e type) { + switch(type) { + case SSH_HMAC_SHA1: + return SHA_DIGEST_LEN; + case SSH_HMAC_SHA256: + return SHA256_DIGEST_LEN; + case SSH_HMAC_SHA384: + return SHA384_DIGEST_LEN; + case SSH_HMAC_SHA512: + return SHA512_DIGEST_LEN; + case SSH_HMAC_MD5: + return MD5_DIGEST_LEN; + default: + return 0; + } +} + +const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type) +{ + int i = 0; + struct ssh_hmac_struct *ssh_hmactab = ssh_get_hmactab(); + while (ssh_hmactab[i].name && (ssh_hmactab[i].hmac_type != hmac_type)) { + i++; + } + return ssh_hmactab[i].name; +} + /* it allocates a new cipher structure based on its offset into the global table */ static struct ssh_cipher_struct *cipher_new(int offset) { struct ssh_cipher_struct *cipher = NULL; @@ -130,10 +170,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); @@ -167,6 +210,7 @@ static int crypt_set_algorithms2(ssh_session session){ const char *wanted; int i = 0; struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab(); + struct ssh_hmac_struct *ssh_hmactab=ssh_get_hmactab(); /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */ /* out */ @@ -190,6 +234,24 @@ static int crypt_set_algorithms2(ssh_session session){ } i = 0; + /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ + /* out */ + wanted = session->next_crypto->kex_methods[SSH_MAC_C_S]; + while (ssh_hmactab[i].name && strcmp(wanted, ssh_hmactab[i].name)) { + i++; + } + + if (ssh_hmactab[i].name == NULL) { + ssh_set_error(session, SSH_FATAL, + "crypt_set_algorithms2: no hmac algorithm function found for %s", + wanted); + return SSH_ERROR; + } + SSH_LOG(SSH_LOG_PACKET, "Set HMAC output algorithm to %s", wanted); + + session->next_crypto->out_hmac = ssh_hmactab[i].hmac_type; + i = 0; + /* in */ wanted = session->next_crypto->kex_methods[SSH_CRYPT_S_C]; while (ssh_ciphertab[i].name && strcmp(wanted, ssh_ciphertab[i].name)) { @@ -209,6 +271,24 @@ static int crypt_set_algorithms2(ssh_session session){ ssh_set_error_oom(session); return SSH_ERROR; } + i = 0; + + /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ + wanted = session->next_crypto->kex_methods[SSH_MAC_S_C]; + while (ssh_hmactab[i].name && strcmp(wanted, ssh_hmactab[i].name)) { + i++; + } + + if (ssh_hmactab[i].name == NULL) { + ssh_set_error(session, SSH_FATAL, + "crypt_set_algorithms2: no hmac algorithm function found for %s", + wanted); + return SSH_ERROR; + } + SSH_LOG(SSH_LOG_PACKET, "Set HMAC output algorithm to %s", wanted); + + session->next_crypto->in_hmac = ssh_hmactab[i].hmac_type; + i = 0; /* compression */ if (strcmp(session->next_crypto->kex_methods[SSH_COMP_C_S], "zlib") == 0) { @@ -267,6 +347,7 @@ int crypt_set_algorithms_server(ssh_session session){ char *method = NULL; int i = 0; struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab(); + struct ssh_hmac_struct *ssh_hmactab=ssh_get_hmactab(); if (session == NULL) { return SSH_ERROR; @@ -309,6 +390,40 @@ int crypt_set_algorithms_server(ssh_session session){ ssh_set_error_oom(session); return SSH_ERROR; } + i=0; + + /* HMAC algorithm selection */ + method = session->next_crypto->kex_methods[SSH_MAC_S_C]; + while (ssh_hmactab[i].name && strcmp(method, ssh_hmactab[i].name)) { + i++; + } + + if (ssh_hmactab[i].name == NULL) { + ssh_set_error(session, SSH_FATAL, + "crypt_set_algorithms_server: no hmac algorithm function found for %s", + method); + return SSH_ERROR; + } + SSH_LOG(SSH_LOG_PACKET, "Set HMAC output algorithm to %s", method); + + session->next_crypto->out_hmac = ssh_hmactab[i].hmac_type; + i=0; + + method = session->next_crypto->kex_methods[SSH_MAC_C_S]; + while (ssh_hmactab[i].name && strcmp(method, ssh_hmactab[i].name)) { + i++; + } + + if (ssh_hmactab[i].name == NULL) { + ssh_set_error(session, SSH_FATAL, + "crypt_set_algorithms_server: no hmac algorithm function found for %s", + method); + return SSH_ERROR; + } + SSH_LOG(SSH_LOG_PACKET, "Set HMAC input algorithm to %s", method); + + session->next_crypto->in_hmac = ssh_hmactab[i].hmac_type; + i=0; /* compression */ method = session->next_crypto->kex_methods[SSH_COMP_C_S]; diff --git a/libssh/tests/CMakeLists.txt b/libssh/tests/CMakeLists.txt index bb39755a..7cdb2c48 100644 --- a/libssh/tests/CMakeLists.txt +++ b/libssh/tests/CMakeLists.txt @@ -1,8 +1,8 @@ project(tests C) -if (BSD OR SOLARIS) +if (BSD OR SOLARIS OR OSX) find_package(Argp) -endif (BSD OR SOLARIS) +endif (BSD OR SOLARIS OR OSX) set(TORTURE_LIBRARY torture) @@ -38,6 +38,7 @@ set(TEST_TARGET_LIBRARIES ) add_subdirectory(unittests) + if (WITH_CLIENT_TESTING) add_subdirectory(client) endif (WITH_CLIENT_TESTING) @@ -46,3 +47,6 @@ if (WITH_BENCHMARKS) add_subdirectory(benchmarks) endif (WITH_BENCHMARKS) +if (WITH_SERVER) + add_subdirectory(pkd) +endif (WITH_SERVER) diff --git a/libssh/tests/client/torture_algorithms.c b/libssh/tests/client/torture_algorithms.c index 180efb71..8a466380 100644 --- a/libssh/tests/client/torture_algorithms.c +++ b/libssh/tests/client/torture_algorithms.c @@ -37,7 +37,7 @@ static void teardown(void **state) { ssh_free(*state); } -static void test_algorithm(ssh_session session, const char *algo) { +static void test_algorithm(ssh_session session, const char *algo, const char *hmac) { int rc; rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost"); @@ -49,6 +49,12 @@ static void test_algorithm(ssh_session session, const char *algo) { rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, algo); assert_true(rc == SSH_OK); + rc = ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, hmac); + assert_true(rc == SSH_OK); + + rc = ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, hmac); + assert_true(rc == SSH_OK); + rc = ssh_connect(session); assert_true(rc == SSH_OK); @@ -61,36 +67,100 @@ static void test_algorithm(ssh_session session, const char *algo) { ssh_disconnect(session); } -static void torture_algorithms_aes128_cbc(void **state) { - test_algorithm(*state, "aes128-cbc"); +static void torture_algorithms_aes128_cbc_hmac_sha1(void **state) { + test_algorithm(*state, "aes128-cbc", "hmac-sha1"); } -static void torture_algorithms_aes192_cbc(void **state) { - test_algorithm(*state, "aes192-cbc"); +static void torture_algorithms_aes128_cbc_hmac_sha2_256(void **state) { + test_algorithm(*state, "aes128-cbc", "hmac-sha2-256"); } -static void torture_algorithms_aes256_cbc(void **state) { - test_algorithm(*state, "aes256-cbc"); +static void torture_algorithms_aes128_cbc_hmac_sha2_512(void **state) { + test_algorithm(*state, "aes128-cbc", "hmac-sha2-512"); } -static void torture_algorithms_aes128_ctr(void **state) { - test_algorithm(*state, "aes128-ctr"); +static void torture_algorithms_aes192_cbc_hmac_sha1(void **state) { + test_algorithm(*state, "aes192-cbc", "hmac-sha1"); } -static void torture_algorithms_aes192_ctr(void **state) { - test_algorithm(*state, "aes192-ctr"); +static void torture_algorithms_aes192_cbc_hmac_sha2_256(void **state) { + test_algorithm(*state, "aes192-cbc", "hmac-sha2-256"); } -static void torture_algorithms_aes256_ctr(void **state) { - test_algorithm(*state, "aes256-ctr"); +static void torture_algorithms_aes192_cbc_hmac_sha2_512(void **state) { + test_algorithm(*state, "aes192-cbc", "hmac-sha2-512"); } -static void torture_algorithms_3des_cbc(void **state) { - test_algorithm(*state, "3des-cbc"); +static void torture_algorithms_aes256_cbc_hmac_sha1(void **state) { + test_algorithm(*state, "aes256-cbc", "hmac-sha1"); } -static void torture_algorithms_blowfish_cbc(void **state) { - test_algorithm(*state, "blowfish-cbc"); +static void torture_algorithms_aes256_cbc_hmac_sha2_256(void **state) { + test_algorithm(*state, "aes256-cbc", "hmac-sha2-256"); +} + +static void torture_algorithms_aes256_cbc_hmac_sha2_512(void **state) { + test_algorithm(*state, "aes256-cbc", "hmac-sha2-512"); +} + +static void torture_algorithms_aes128_ctr_hmac_sha1(void **state) { + test_algorithm(*state, "aes128-ctr", "hmac-sha1"); +} + +static void torture_algorithms_aes128_ctr_hmac_sha2_256(void **state) { + test_algorithm(*state, "aes128-ctr", "hmac-sha2-256"); +} + +static void torture_algorithms_aes128_ctr_hmac_sha2_512(void **state) { + test_algorithm(*state, "aes128-ctr", "hmac-sha2-512"); +} + +static void torture_algorithms_aes192_ctr_hmac_sha1(void **state) { + test_algorithm(*state, "aes192-ctr", "hmac-sha1"); +} + +static void torture_algorithms_aes192_ctr_hmac_sha2_256(void **state) { + test_algorithm(*state, "aes192-ctr", "hmac-sha2-256"); +} + +static void torture_algorithms_aes192_ctr_hmac_sha2_512(void **state) { + test_algorithm(*state, "aes192-ctr", "hmac-sha2-512"); +} + +static void torture_algorithms_aes256_ctr_hmac_sha1(void **state) { + test_algorithm(*state, "aes256-ctr", "hmac-sha1"); +} + +static void torture_algorithms_aes256_ctr_hmac_sha2_256(void **state) { + test_algorithm(*state, "aes256-ctr", "hmac-sha2-256"); +} + +static void torture_algorithms_aes256_ctr_hmac_sha2_512(void **state) { + test_algorithm(*state, "aes256-ctr", "hmac-sha2-512"); +} + +static void torture_algorithms_3des_cbc_hmac_sha1(void **state) { + test_algorithm(*state, "3des-cbc", "hmac-sha1"); +} + +static void torture_algorithms_3des_cbc_hmac_sha2_256(void **state) { + test_algorithm(*state, "3des-cbc", "hmac-sha2-256"); +} + +static void torture_algorithms_3des_cbc_hmac_sha2_512(void **state) { + test_algorithm(*state, "3des-cbc", "hmac-sha2-512"); +} + +static void torture_algorithms_blowfish_cbc_hmac_sha1(void **state) { + test_algorithm(*state, "blowfish-cbc", "hmac-sha1"); +} + +static void torture_algorithms_blowfish_cbc_hmac_sha2_256(void **state) { + test_algorithm(*state, "blowfish-cbc", "hmac-sha2-256"); +} + +static void torture_algorithms_blowfish_cbc_hmac_sha2_512(void **state) { + test_algorithm(*state, "blowfish-cbc", "hmac-sha2-512"); } static void torture_algorithms_zlib(void **state) { @@ -220,14 +290,30 @@ static void torture_algorithms_dh_group1(void **state) { int torture_run_tests(void) { int rc; const UnitTest tests[] = { - unit_test_setup_teardown(torture_algorithms_aes128_cbc, setup, teardown), - unit_test_setup_teardown(torture_algorithms_aes192_cbc, setup, teardown), - unit_test_setup_teardown(torture_algorithms_aes256_cbc, setup, teardown), - unit_test_setup_teardown(torture_algorithms_aes128_ctr, setup, teardown), - unit_test_setup_teardown(torture_algorithms_aes192_ctr, setup, teardown), - unit_test_setup_teardown(torture_algorithms_aes256_ctr, setup, teardown), - unit_test_setup_teardown(torture_algorithms_3des_cbc, setup, teardown), - unit_test_setup_teardown(torture_algorithms_blowfish_cbc, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes128_cbc_hmac_sha1, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes128_cbc_hmac_sha2_256, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes128_cbc_hmac_sha2_512, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes192_cbc_hmac_sha1, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes192_cbc_hmac_sha2_256, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes192_cbc_hmac_sha2_512, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes256_cbc_hmac_sha1, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes256_cbc_hmac_sha2_256, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes256_cbc_hmac_sha2_512, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes128_ctr_hmac_sha1, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes128_ctr_hmac_sha2_256, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes128_ctr_hmac_sha2_512, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes192_ctr_hmac_sha1, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes192_ctr_hmac_sha2_256, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes192_ctr_hmac_sha2_512, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes256_ctr_hmac_sha1, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes256_ctr_hmac_sha2_256, setup, teardown), + unit_test_setup_teardown(torture_algorithms_aes256_ctr_hmac_sha2_512, setup, teardown), + unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha1, setup, teardown), + unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha2_256, setup, teardown), + unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha2_512, setup, teardown), + unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha1, setup, teardown), + unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha2_256, setup, teardown), + unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha2_512, setup, teardown), unit_test_setup_teardown(torture_algorithms_zlib, setup, teardown), unit_test_setup_teardown(torture_algorithms_zlib_openssh, setup, teardown), unit_test_setup_teardown(torture_algorithms_dh_group1,setup,teardown), diff --git a/libssh/tests/client/torture_auth.c b/libssh/tests/client/torture_auth.c index 83bbd406..af36b79f 100644 --- a/libssh/tests/client/torture_auth.c +++ b/libssh/tests/client/torture_auth.c @@ -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); @@ -290,7 +305,7 @@ static void torture_auth_agent(void **state) { return; } if (!agent_is_running(session)){ - print_message("*** Agent not running. Test ignored"); + print_message("*** Agent not running. Test ignored\n"); return; } rc = ssh_options_set(session, SSH_OPTIONS_USER, user); @@ -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); @@ -321,7 +337,7 @@ static void torture_auth_agent_nonblocking(void **state) { return; } if (!agent_is_running(session)){ - print_message("*** Agent not running. Test ignored"); + print_message("*** Agent not running. Test ignored\n"); return; } rc = ssh_options_set(session, SSH_OPTIONS_USER, user); @@ -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(); diff --git a/libssh/tests/client/torture_connect.c b/libssh/tests/client/torture_connect.c index 0e23fcd7..31573ea3 100644 --- a/libssh/tests/client/torture_connect.c +++ b/libssh/tests/client/torture_connect.c @@ -24,6 +24,7 @@ #include "torture.h" #include #include +#include #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, (struct sockaddr *)&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(); diff --git a/libssh/tests/client/torture_forward.c b/libssh/tests/client/torture_forward.c index 1440552e..5754386f 100644 --- a/libssh/tests/client/torture_forward.c +++ b/libssh/tests/client/torture_forward.c @@ -41,15 +41,15 @@ static void setup(void **state) session = torture_ssh_session(host, user, password); - assert_false(session == NULL); + assert_non_null(session); *state = session; } static void teardown(void **state) { - ssh_session session = *state; + ssh_session session = (ssh_session) *state; - assert_false(session == NULL); + assert_non_null(session); if (ssh_is_connected(session)) { ssh_disconnect(session); @@ -59,14 +59,14 @@ static void teardown(void **state) static void torture_ssh_forward(void **state) { - ssh_session session = *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); + rc = ssh_channel_listen_forward(session, "127.0.0.1", 8080, &bound_port); assert_int_equal(rc, SSH_OK); #if 0 diff --git a/libssh/tests/client/torture_knownhosts.c b/libssh/tests/client/torture_knownhosts.c index fe827cbc..df99ae90 100644 --- a/libssh/tests/client/torture_knownhosts.c +++ b/libssh/tests/client/torture_knownhosts.c @@ -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(); diff --git a/libssh/tests/client/torture_request_env.c b/libssh/tests/client/torture_request_env.c index dbe7fb21..7c7338ed 100644 --- a/libssh/tests/client/torture_request_env.c +++ b/libssh/tests/client/torture_request_env.c @@ -61,7 +61,7 @@ static void torture_request_env(void **state) { ssh_session session = *state; ssh_channel c; - char buffer[4096]; + char buffer[4096] = {0}; int nbytes; int rc; int lang_found = 0; @@ -72,20 +72,20 @@ static void torture_request_env(void **state) rc = ssh_channel_open_session(c); assert_int_equal(rc, SSH_OK); - rc = ssh_channel_request_env(c, "LANG", "LIBSSH"); + 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), 0); + 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 - - if (strstr(buffer, "LANG=\"LIBSSH\"")) { + buffer[nbytes]='\0'; + if (strstr(buffer, "LC_LIBSSH=\"LIBSSH\"")) { lang_found = 1; break; } diff --git a/libssh/tests/client/torture_session.c b/libssh/tests/client/torture_session.c index f2e062b4..ef9ef653 100644 --- a/libssh/tests/client/torture_session.c +++ b/libssh/tests/client/torture_session.c @@ -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); diff --git a/libssh/tests/client/torture_sftp_read.c b/libssh/tests/client/torture_sftp_read.c index 8efaafe9..1e40e2cf 100644 --- a/libssh/tests/client/torture_sftp_read.c +++ b/libssh/tests/client/torture_sftp_read.c @@ -29,7 +29,7 @@ static void setup(void **state) { } static void teardown(void **state) { - struct torture_sftp *t = *state; + struct torture_sftp *t = (struct torture_sftp*) *state; assert_false(t == NULL); @@ -38,7 +38,7 @@ static void teardown(void **state) { } static void torture_sftp_read_blocking(void **state) { - struct torture_sftp *t = *state; + struct torture_sftp *t = (struct torture_sftp*) *state; char libssh_tmp_file[] = "/tmp/libssh_sftp_test_XXXXXX"; char buf[MAX_XFER_BUF_SIZE]; ssize_t bytesread; diff --git a/libssh/tests/pkd/CMakeLists.txt b/libssh/tests/pkd/CMakeLists.txt new file mode 100644 index 00000000..515dae10 --- /dev/null +++ b/libssh/tests/pkd/CMakeLists.txt @@ -0,0 +1,35 @@ +project(pkd C) + +if (WITH_SERVER AND UNIX AND NOT WIN32) + +include_directories( + ${LIBSSH_PUBLIC_INCLUDE_DIRS} + ${CMOCKA_INCLUDE_DIR} + ${OPENSSL_INCLUDE_DIRS} + ${GCRYPT_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR} +) + +set(pkd_hello_src + pkd_daemon.c + pkd_hello.c + pkd_keyutil.c + pkd_util.c +) + +set(pkd_libs + ${CMOCKA_LIBRARY} + ${LIBSSH_STATIC_LIBRARY} + ${LIBSSH_LINK_LIBRARIES} + ${LIBSSH_THREADS_STATIC_LIBRARY} + ${LIBSSH_THREADS_LINK_LIBRARIES} + ${ARGP_LIBRARIES} +) + +add_executable(pkd_hello ${pkd_hello_src}) +target_link_libraries(pkd_hello ${pkd_libs}) + +endif (WITH_SERVER AND UNIX AND NOT WIN32) diff --git a/libssh/tests/pkd/pkd_client.h b/libssh/tests/pkd/pkd_client.h new file mode 100644 index 00000000..c4a8a601 --- /dev/null +++ b/libssh/tests/pkd/pkd_client.h @@ -0,0 +1,69 @@ +/* + * pkd_client.h -- macros for generating client-specific command + * invocations for use with pkd testing + * + * (c) 2014 Jon Simons + */ + +#ifndef __PKD_CLIENT_H__ +#define __PKD_CLIENT_H__ + +/* OpenSSH */ + +#define OPENSSH_BINARY "ssh" +#define OPENSSH_KEYGEN "ssh-keygen" + +#define OPENSSH_CMD_START \ + OPENSSH_BINARY " " \ + "-o UserKnownHostsFile=/dev/null " \ + "-o StrictHostKeyChecking=no " \ + "-i " CLIENT_ID_FILE " " \ + "1> %s.out " \ + "2> %s.err " \ + "-vvv " + +#define OPENSSH_CMD_END "-p 1234 localhost ls" + +#define OPENSSH_CMD \ + OPENSSH_CMD_START OPENSSH_CMD_END + +#define OPENSSH_KEX_CMD(kexalgo) \ + OPENSSH_CMD_START "-o KexAlgorithms=" kexalgo " " OPENSSH_CMD_END + +#define OPENSSH_CIPHER_CMD(ciphers) \ + OPENSSH_CMD_START "-c " ciphers " " OPENSSH_CMD_END + +#define OPENSSH_MAC_CMD(macs) \ + OPENSSH_CMD_START "-o MACs=" macs " " OPENSSH_CMD_END + + +/* Dropbear */ + +#define DROPBEAR_BINARY "dbclient" +#define DROPBEAR_KEYGEN "dropbearkey" + +#define DROPBEAR_CMD_START \ + DROPBEAR_BINARY " " \ + "-y -y " \ + "-i " CLIENT_ID_FILE " " \ + "-v " \ + "1> %s.out " \ + "2> %s.err " + +#define DROPBEAR_CMD_END "-p 1234 localhost ls" + +#define DROPBEAR_CMD \ + DROPBEAR_CMD_START DROPBEAR_CMD_END + +#if 0 /* dbclient does not expose control over kex algo */ +#define DROPBEAR_KEX_CMD(kexalgo) \ + DROPBEAR_CMD +#endif + +#define DROPBEAR_CIPHER_CMD(ciphers) \ + DROPBEAR_CMD_START "-c " ciphers " " DROPBEAR_CMD_END + +#define DROPBEAR_MAC_CMD(macs) \ + DROPBEAR_CMD_START "-m " macs " " DROPBEAR_CMD_END + +#endif /* __PKD_CLIENT_H__ */ diff --git a/libssh/tests/pkd/pkd_daemon.c b/libssh/tests/pkd/pkd_daemon.c new file mode 100644 index 00000000..07736fa6 --- /dev/null +++ b/libssh/tests/pkd/pkd_daemon.c @@ -0,0 +1,500 @@ +/* + * pkd_daemon.c -- a sample public-key testing daemon using libssh + * + * Uses public key authentication to establish an exec channel and + * echo back payloads to the user. + * + * (c) 2014 Jon Simons + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pkd_daemon.h" + +#include // for cmocka +#include + +static int pkdout_enabled; +static int pkderr_enabled; + +static void pkdout(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2); +static void pkderr(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2); + +static void pkdout(const char *fmt, ...) { + va_list vargs; + if (pkdout_enabled) { + va_start(vargs, fmt); + vfprintf(stdout, fmt, vargs); + va_end(vargs); + } +} + +static void pkderr(const char *fmt, ...) { + va_list vargs; + if (pkderr_enabled) { + va_start(vargs, fmt); + vfprintf(stderr, fmt, vargs); + va_end(vargs); + } +} + +/* + * pkd state: only one thread can run pkd at a time --------------------- + */ + +static struct { + int rc; + pthread_t tid; + int keep_going; + int pkd_ready; +} ctx; + +static struct { + int server_fd; + int req_exec_received; + int close_received; + int eof_received; +} pkd_state; + +static void pkd_sighandler(int signum) { + (void) signum; +} + +static int pkd_init_libssh() { + int rc = ssh_threads_set_callbacks(ssh_threads_get_pthread()); + return (rc == SSH_OK) ? 0 : 1; +} + +static int pkd_init_server_fd(short port) { + int rc = 0; + int yes = 1; + struct sockaddr_in addr; + + int server_fd = socket(PF_INET, SOCK_STREAM, 0); + if (server_fd < 0) { + rc = -1; + goto out; + } + + rc = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + if (rc != 0) { + goto outclose; + } + + memset(&addr, 0x0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + rc = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)); + if (rc != 0) { + goto outclose; + } + + rc = listen(server_fd, 128); + if (rc == 0) { + goto out; + } + +outclose: + close(server_fd); + server_fd = -1; +out: + pkd_state.server_fd = server_fd; + return rc; +} + +static int pkd_accept_fd() { + int fd = -1; + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + + do { + fd = accept(pkd_state.server_fd, (struct sockaddr *) &addr, &len); + } while ((ctx.keep_going != 0) && (fd < 0) && (errno == EINTR)); + + return fd; +} + +static void pkd_eof(ssh_session session, + ssh_channel channel, + void *userdata) { + (void) session; + (void) channel; + (void) userdata; + pkdout("pkd_eof\n"); + pkd_state.eof_received = 1; +} + +static void pkd_chan_close(ssh_session session, + ssh_channel channel, + void *userdata) { + (void) session; + (void) channel; + (void) userdata; + pkdout("pkd_chan_close\n"); + pkd_state.close_received = 1; +} + +static int pkd_req_exec(ssh_session s, + ssh_channel c, + const char *cmd, + void *userdata) { + (void) s; + (void) c; + (void) cmd; + (void) userdata; + /* assumes pubkey authentication has already succeeded */ + pkdout("pkd_req_exec\n"); + pkd_state.req_exec_received = 1; + return 0; +} + +/* assumes there is only ever a single channel */ +static struct ssh_channel_callbacks_struct pkd_channel_cb = { + .channel_eof_function = pkd_eof, + .channel_close_function = pkd_chan_close, + .channel_exec_request_function = pkd_req_exec, +}; + +static int pkd_auth_pubkey_cb(ssh_session s, + const char *user, + ssh_key key, + char state, + void *userdata) { + (void) s; + (void) user; + (void) key; + (void) state; + (void) userdata; + pkdout("pkd_auth_pubkey_cb keytype %s, state: %d\n", + ssh_key_type_to_char(ssh_key_type(key)), state); + if ((state == SSH_PUBLICKEY_STATE_NONE) || + (state == SSH_PUBLICKEY_STATE_VALID)) { + return SSH_AUTH_SUCCESS; + } + return SSH_AUTH_DENIED; +} + +static int pkd_service_request_cb(ssh_session session, + const char *service, + void *userdata) { + (void) session; + (void) userdata; + pkdout("pkd_service_request_cb: %s\n", service); + return (0 == (strcmp(service, "ssh-userauth"))) ? 0 : -1; +} + +static ssh_channel pkd_channel_openreq_cb(ssh_session s, + void *userdata) { + ssh_channel c = NULL; + ssh_channel *out = (ssh_channel *) userdata; + + /* assumes pubkey authentication has already succeeded */ + pkdout("pkd_channel_openreq_cb\n"); + + c = ssh_channel_new(s); + if (c == NULL) { + pkderr("ssh_channel_new: %s\n", ssh_get_error(s)); + return NULL; + } + + ssh_callbacks_init(&pkd_channel_cb); + pkd_channel_cb.userdata = userdata; + if (ssh_set_channel_callbacks(c, &pkd_channel_cb) != SSH_OK) { + pkderr("ssh_set_channel_callbacks: %s\n", ssh_get_error(s)); + ssh_channel_free(c); + c = NULL; + } + + *out = c; + + return c; +} + +static struct ssh_server_callbacks_struct pkd_server_cb = { + .auth_pubkey_function = pkd_auth_pubkey_cb, + .service_request_function = pkd_service_request_cb, + .channel_open_request_session_function = pkd_channel_openreq_cb, +}; + +static int pkd_exec_hello(int fd, struct pkd_daemon_args *args) { + int rc = -1; + ssh_bind b = NULL; + ssh_session s = NULL; + ssh_event e = NULL; + ssh_channel c = NULL; + enum ssh_bind_options_e opts = -1; + + int level = args->opts.libssh_log_level; + enum pkd_hostkey_type_e type = args->type; + const char *hostkeypath = args->hostkeypath; + + pkd_state.eof_received = 0; + pkd_state.close_received = 0; + pkd_state.req_exec_received = 0; + + b = ssh_bind_new(); + if (b == NULL) { + pkderr("ssh_bind_new\n"); + goto outclose; + } + + if (type == PKD_RSA) { + opts = SSH_BIND_OPTIONS_RSAKEY; + } else if (type == PKD_DSA) { + opts = SSH_BIND_OPTIONS_DSAKEY; + } else if (type == PKD_ECDSA) { + opts = SSH_BIND_OPTIONS_ECDSAKEY; + } else { + pkderr("unknown kex algorithm: %d\n", type); + rc = -1; + goto outclose; + } + + rc = ssh_bind_options_set(b, opts, hostkeypath); + if (rc != 0) { + pkderr("ssh_bind_options_set: %s\n", ssh_get_error(b)); + goto outclose; + } + + rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_LOG_VERBOSITY, &level); + if (rc != 0) { + pkderr("ssh_bind_options_set log verbosity: %s\n", ssh_get_error(b)); + goto outclose; + } + + s = ssh_new(); + if (s == NULL) { + pkderr("ssh_new\n"); + goto outclose; + } + + /* + * ssh_bind_accept loads host key as side-effect. If this + * succeeds, the given 'fd' will be closed upon 'ssh_free(s)'. + */ + rc = ssh_bind_accept_fd(b, s, fd); + if (rc != SSH_OK) { + pkderr("ssh_bind_accept_fd: %s\n", ssh_get_error(b)); + goto outclose; + } + + /* accept only publickey-based auth */ + ssh_set_auth_methods(s, SSH_AUTH_METHOD_PUBLICKEY); + + /* initialize callbacks */ + ssh_callbacks_init(&pkd_server_cb); + pkd_server_cb.userdata = &c; + rc = ssh_set_server_callbacks(s, &pkd_server_cb); + if (rc != SSH_OK) { + pkderr("ssh_set_server_callbacks: %s\n", ssh_get_error(s)); + goto out; + } + + /* first do key exchange */ + rc = ssh_handle_key_exchange(s); + if (rc != SSH_OK) { + pkderr("ssh_handle_key_exchange: %s\n", ssh_get_error(s)); + goto out; + } + + /* setup and pump event to carry out exec channel */ + e = ssh_event_new(); + if (e == NULL) { + pkderr("ssh_event_new\n"); + goto out; + } + + rc = ssh_event_add_session(e, s); + if (rc != SSH_OK) { + pkderr("ssh_event_add_session\n"); + goto out; + } + + /* poll until exec channel established */ + while ((ctx.keep_going != 0) && + (rc != SSH_ERROR) && (pkd_state.req_exec_received == 0)) { + rc = ssh_event_dopoll(e, -1 /* infinite timeout */); + } + + if (rc == SSH_ERROR) { + pkderr("ssh_event_dopoll\n"); + goto out; + } else if (c == NULL) { + pkderr("poll loop exited but exec channel not ready\n"); + rc = -1; + goto out; + } + + rc = ssh_channel_write(c, "hello\n", 6); /* XXX: customizable payloads */ + if (rc != 6) { + pkderr("ssh_channel_write partial (%d)\n", rc); + } + + rc = ssh_channel_request_send_exit_status(c, 0); + if (rc != SSH_OK) { + pkderr("ssh_channel_request_send_exit_status: %s\n", + ssh_get_error(s)); + goto out; + } + + rc = ssh_channel_send_eof(c); + if (rc != SSH_OK) { + pkderr("ssh_channel_send_eof: %s\n", ssh_get_error(s)); + goto out; + } + + rc = ssh_channel_close(c); + if (rc != SSH_OK) { + pkderr("ssh_channel_close: %s\n", ssh_get_error(s)); + goto out; + } + + while ((ctx.keep_going != 0) && + (pkd_state.eof_received == 0) && + (pkd_state.close_received == 0) && + (ssh_channel_is_closed(c) == 0)) { + rc = ssh_event_dopoll(e, 1000 /* milliseconds */); + if (rc == SSH_ERROR) { + pkderr("ssh_event_dopoll for eof + close: %s\n", ssh_get_error(s)); + break; + } else { + rc = 0; + } + } + goto out; + +outclose: + close(fd); +out: + if (c != NULL) { + ssh_channel_free(c); + } + if (e != NULL) { + ssh_event_remove_session(e, s); + ssh_event_free(e); + } + if (s != NULL) { + ssh_disconnect(s); + ssh_free(s); + } + if (b != NULL) { + ssh_bind_free(b); + } + return rc; +} + +/* + * main loop ------------------------------------------------------------ + */ + +static void *pkd_main(void *args) { + int rc = -1; + struct pkd_daemon_args *a = (struct pkd_daemon_args *) args; + + struct sigaction act = { .sa_handler = pkd_sighandler, }; + + pkd_state.server_fd = -1; + pkd_state.req_exec_received = 0; + pkd_state.close_received = 0; + pkd_state.eof_received = 0; + + /* SIGUSR1 is used to interrupt 'pkd_accept_fd'. */ + rc = sigaction(SIGUSR1, &act, NULL); + if (rc != 0) { + pkderr("sigaction: %d\n", rc); + goto out; + } + + rc = pkd_init_libssh(); + if (rc != 0) { + pkderr("pkd_init_libssh: %d\n", rc); + goto out; + } + + rc = pkd_init_server_fd(1234); + if (rc != 0) { + pkderr("pkd_init_server_fd: %d\n", rc); + goto out; + } + + ctx.pkd_ready = 1; + + while (ctx.keep_going != 0) { + int fd = pkd_accept_fd(); + if (fd < 0) { + if (ctx.keep_going != 0) { + pkderr("pkd_accept_fd"); + rc = -1; + } else { + rc = 0; + } + break; + } + + rc = pkd_exec_hello(fd, a); + if (rc != 0) { + pkderr("pkd_exec_hello: %d\n", rc); + break; + } + } + + close(pkd_state.server_fd); + pkd_state.server_fd = -1; +out: + ctx.rc = rc; + + return NULL; +} + +/* + * pkd start and stop used by setup/teardown test scaffolding ----------- + */ + +int pkd_start(struct pkd_daemon_args *args) { + int rc = 0; + + pkdout_enabled = args->opts.log_stdout; + pkderr_enabled = args->opts.log_stderr; + + /* Initialize the pkd context. */ + ctx.rc = -1; + ctx.keep_going = 1; + ctx.pkd_ready = 0; + rc = pthread_create(&ctx.tid, NULL, &pkd_main, args); + assert_int_equal(rc, 0); + + /* Busy-spin until pkd thread is ready. */ + while (ctx.pkd_ready == 0); + + return rc; +} + +void pkd_stop(struct pkd_result *out) { + int rc = 0; + + ctx.keep_going = 0; + + rc = pthread_kill(ctx.tid, SIGUSR1); + assert_int_equal(rc, 0); + + rc = pthread_join(ctx.tid, NULL); + assert_int_equal(rc, 0); + + assert_non_null(out); + out->ok = (ctx.rc == 0); + + return; +} diff --git a/libssh/tests/pkd/pkd_daemon.h b/libssh/tests/pkd/pkd_daemon.h new file mode 100644 index 00000000..c42573c1 --- /dev/null +++ b/libssh/tests/pkd/pkd_daemon.h @@ -0,0 +1,40 @@ +/* + * pkd_daemon.h -- tests use this interface to start, stop pkd + * instances and get results + * + * (c) 2014 Jon Simons + */ + +#ifndef __PKD_DAEMON_H__ +#define __PKD_DAEMON_H__ + +enum pkd_hostkey_type_e { + PKD_RSA, + PKD_DSA, + PKD_ECDSA +}; + +struct pkd_daemon_args { + enum pkd_hostkey_type_e type; + const char *hostkeypath; + + struct { + int list; + + int log_stdout; + int log_stderr; + int libssh_log_level; + + const char *testname; + unsigned int iterations; + } opts; +}; + +struct pkd_result { + int ok; +}; + +int pkd_start(struct pkd_daemon_args *args); +void pkd_stop(struct pkd_result *out); + +#endif /* __PKD_DAEMON_H__ */ diff --git a/libssh/tests/pkd/pkd_hello.c b/libssh/tests/pkd/pkd_hello.c new file mode 100644 index 00000000..2183f897 --- /dev/null +++ b/libssh/tests/pkd/pkd_hello.c @@ -0,0 +1,534 @@ +/* + * pkd_hello.c -- + * + * (c) 2014 Jon Simons + */ + +#include // for cmocka +#include // for cmocka +#include +#include +#include // for cmocka +#include + +#include "libssh/priv.h" + +#include "pkd_client.h" +#include "pkd_daemon.h" +#include "pkd_keyutil.h" +#include "pkd_util.h" + +#define DEFAULT_ITERATIONS 10 +static struct pkd_daemon_args pkd_dargs; + +#ifdef HAVE_ARGP_H +#include +#define PROGNAME "pkd_hello" +#define ARGP_PROGNAME "libssh " PROGNAME +const char *argp_program_version = ARGP_PROGNAME " 2014-04-12"; +const char *argp_program_bug_address = "Jon Simons "; +//static char **cmdline; +static char doc[] = \ + "\nExample usage:\n\n" + " " PROGNAME "\n" + " Run all tests with default number of iterations.\n" + " " PROGNAME " --list\n" + " List available individual test names.\n" + " " PROGNAME " -i 1000 -t torture_pkd_rsa_ecdh_sha2_nistp256\n" + " Run only the torture_pkd_rsa_ecdh_sha2_nistp256 testcase 1000 times.\n" + " " PROGNAME " -v -v -v -v -e -o\n" + " Run all tests with maximum libssh and pkd logging.\n" +; + +static struct argp_option options[] = { + { "stderr", 'e', NULL, 0, + "Emit pkd stderr messages", 0 }, + { "list", 'l', NULL, 0, + "List available individual test names", 0 }, + { "iterations", 'i', "number", 0, + "Run each test for the given number of iterations (default is 10)", 0 }, + { "stdout", 'o', NULL, 0, + "Emit pkd stdout messages", 0 }, + { "test", 't', "testname", 0, + "Run tests matching the given testname", 0 }, + { "verbose", 'v', NULL, 0, + "Increase libssh verbosity (can be used multiple times)", 0 }, + { NULL, 0, NULL, 0, + NULL, 0 }, +}; + +static error_t parse_opt(int key, char *arg, struct argp_state *state) { + (void) arg; + (void) state; + + switch(key) { + case 'e': + pkd_dargs.opts.log_stderr = 1; + break; + case 'l': + pkd_dargs.opts.list = 1; + break; + case 'i': + pkd_dargs.opts.iterations = atoi(arg); + break; + case 'o': + pkd_dargs.opts.log_stdout = 1; + break; + case 't': + pkd_dargs.opts.testname = arg; + break; + case 'v': + pkd_dargs.opts.libssh_log_level += 1; + break; + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static struct argp parser = { + options, + parse_opt, + NULL, + doc, + NULL, + NULL, + NULL +}; +#endif /* HAVE_ARGP_H */ + +static struct pkd_state *torture_pkd_setup(enum pkd_hostkey_type_e type, + const char *hostkeypath) { + int rc = 0; + + pkd_dargs.type = type; + pkd_dargs.hostkeypath = hostkeypath; + + rc = pkd_start(&pkd_dargs); + assert_int_equal(rc, 0); + + return NULL; +} + +static void torture_pkd_teardown(void **state) { + struct pkd_result result = { .ok = 0 }; + + (void) state; + + pkd_stop(&result); + assert_int_equal(result.ok, 1); +} + +/* + * one setup for each server keytype ------------------------------------ + */ + +static void torture_pkd_setup_noop(void **state) { + *state = (void *) torture_pkd_setup(PKD_RSA, NULL /*path*/); +} + +static void torture_pkd_setup_rsa(void **state) { + setup_rsa_key(); + *state = (void *) torture_pkd_setup(PKD_RSA, LIBSSH_RSA_TESTKEY); +} + +static void torture_pkd_setup_dsa(void **state) { + setup_dsa_key(); + *state = (void *) torture_pkd_setup(PKD_DSA, LIBSSH_DSA_TESTKEY); +} + +static void torture_pkd_setup_ecdsa_256(void **state) { + setup_ecdsa_keys(); + *state = (void *) torture_pkd_setup(PKD_ECDSA, LIBSSH_ECDSA_256_TESTKEY); +} + +static void torture_pkd_setup_ecdsa_384(void **state) { + setup_ecdsa_keys(); + *state = (void *) torture_pkd_setup(PKD_ECDSA, LIBSSH_ECDSA_384_TESTKEY); +} + +static void torture_pkd_setup_ecdsa_521(void **state) { + setup_ecdsa_keys(); + *state = (void *) torture_pkd_setup(PKD_ECDSA, LIBSSH_ECDSA_521_TESTKEY); +} + +/* + * Test matrices: f(clientname, testname, ssh-command, setup-function, teardown-function). + */ + +#define PKDTESTS_DEFAULT(f, client, cmd) \ + /* Default passes by server key type. */ \ + f(client, rsa_default, cmd, setup_rsa, teardown) \ + f(client, dsa_default, cmd, setup_dsa, teardown) \ + f(client, ecdsa_256_default, cmd, setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_default, cmd, setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_default, cmd, setup_ecdsa_521, teardown) + +#define PKDTESTS_KEX(f, client, kexcmd) \ + /* Kex algorithms. */ \ + f(client, rsa_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_rsa, teardown) \ + f(client, rsa_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_rsa, teardown) \ + f(client, rsa_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_rsa, teardown) \ + f(client, rsa_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_rsa, teardown) \ + f(client, dsa_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_dsa, teardown) \ + f(client, dsa_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_dsa, teardown) \ + f(client, dsa_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_dsa, teardown) \ + f(client, dsa_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_dsa, teardown) \ + f(client, ecdsa_256_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_curve25519_sha256, kexcmd("curve25519-sha256@libssh.org"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256 "), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_diffie_hellman_group1_sha1, kexcmd("diffie-hellman-group1-sha1"), setup_ecdsa_521, teardown) + +#define PKDTESTS_CIPHER(f, client, ciphercmd) \ + /* Ciphers. */ \ + f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \ + f(client, rsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_rsa, teardown) \ + f(client, rsa_aes128_ctr, ciphercmd("aes128-ctr"), setup_rsa, teardown) \ + f(client, rsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_rsa, teardown) \ + f(client, rsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_rsa, teardown) \ + f(client, rsa_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_rsa, teardown) \ + f(client, dsa_3des_cbc, ciphercmd("3des-cbc"), setup_dsa, teardown) \ + f(client, dsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_dsa, teardown) \ + f(client, dsa_aes128_ctr, ciphercmd("aes128-ctr"), setup_dsa, teardown) \ + f(client, dsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_dsa, teardown) \ + f(client, dsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_dsa, teardown) \ + f(client, dsa_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_dsa, teardown) \ + f(client, ecdsa_256_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_521, teardown) + +#define PKDTESTS_CIPHER_AES192(f, client, ciphercmd) \ + /* Ciphers. */ \ + f(client, rsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_rsa, teardown) \ + f(client, rsa_aes192_ctr, ciphercmd("aes192-ctr"), setup_rsa, teardown) \ + f(client, dsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_dsa, teardown) \ + f(client, dsa_aes192_ctr, ciphercmd("aes192-ctr"), setup_dsa, teardown) \ + f(client, ecdsa_256_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) + +#define PKDTESTS_MAC(f, client, maccmd) \ + /* MACs. */ \ + f(client, rsa_hmac_sha1, maccmd("hmac-sha1"), setup_rsa, teardown) \ + f(client, dsa_hmac_sha1, maccmd("hmac-sha1"), setup_dsa, teardown) \ + f(client, ecdsa_256_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_521, teardown) \ + f(client, rsa_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_rsa, teardown) \ + f(client, dsa_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_dsa, teardown) \ + f(client, ecdsa_256_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_521, teardown) \ + f(client, rsa_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_rsa, teardown) \ + f(client, dsa_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_dsa, teardown) \ + f(client, ecdsa_256_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_384_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_521_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_521, teardown) + +static void torture_pkd_client_noop(void **state) { + struct pkd_state *pstate = (struct pkd_state *) (*state); + (void) pstate; + return; +} + +static void torture_pkd_runtest(const char *testname, + const char *testcmd) +{ + int i, rc; + char logfile[1024] = { 0 }; + int iterations = + (pkd_dargs.opts.iterations != 0) ? pkd_dargs.opts.iterations + : DEFAULT_ITERATIONS; + + for (i = 0; i < iterations; i++) { + rc = system_checked(testcmd); + assert_int_equal(rc, 0); + } + + /* Asserts did not trip: cleanup logs. */ + snprintf(&logfile[0], sizeof(logfile), "%s.out", testname); + unlink(logfile); + snprintf(&logfile[0], sizeof(logfile), "%s.err", testname); + unlink(logfile); +} + +/* + * Though each keytest function body is the same, separate functions are + * defined here to result in distinct output when running the tests. + */ + +#define emit_keytest(client, testname, sshcmd, setup, teardown) \ + static void torture_pkd_## client ## _ ## testname(void **state) { \ + const char *tname = "torture_pkd_" #client "_" #testname; \ + char testcmd[1024] = { 0 }; \ + (void) state; \ + snprintf(&testcmd[0], sizeof(testcmd), sshcmd, tname, tname); \ + torture_pkd_runtest(tname, testcmd); \ + } + +/* + * Actual test functions are emitted here. + */ + +#define CLIENT_ID_FILE OPENSSH_DSA_TESTKEY +PKDTESTS_DEFAULT(emit_keytest, openssh_dsa, OPENSSH_CMD) +PKDTESTS_KEX(emit_keytest, openssh_dsa, OPENSSH_KEX_CMD) +PKDTESTS_CIPHER(emit_keytest, openssh_dsa, OPENSSH_CIPHER_CMD) +PKDTESTS_CIPHER_AES192(emit_keytest, openssh_dsa, OPENSSH_CIPHER_CMD) +PKDTESTS_MAC(emit_keytest, openssh_dsa, OPENSSH_MAC_CMD) +#undef CLIENT_ID_FILE + +#define CLIENT_ID_FILE OPENSSH_RSA_TESTKEY +PKDTESTS_DEFAULT(emit_keytest, openssh_rsa, OPENSSH_CMD) +PKDTESTS_KEX(emit_keytest, openssh_rsa, OPENSSH_KEX_CMD) +PKDTESTS_CIPHER(emit_keytest, openssh_rsa, OPENSSH_CIPHER_CMD) +PKDTESTS_CIPHER_AES192(emit_keytest, openssh_rsa, OPENSSH_CIPHER_CMD) +PKDTESTS_MAC(emit_keytest, openssh_rsa, OPENSSH_MAC_CMD) +#undef CLIENT_ID_FILE + +#define CLIENT_ID_FILE OPENSSH_ECDSA256_TESTKEY +PKDTESTS_DEFAULT(emit_keytest, openssh_e256, OPENSSH_CMD) +PKDTESTS_KEX(emit_keytest, openssh_e256, OPENSSH_KEX_CMD) +PKDTESTS_CIPHER(emit_keytest, openssh_e256, OPENSSH_CIPHER_CMD) +PKDTESTS_CIPHER_AES192(emit_keytest, openssh_e256, OPENSSH_CIPHER_CMD) +PKDTESTS_MAC(emit_keytest, openssh_e256, OPENSSH_MAC_CMD) +#undef CLIENT_ID_FILE + +/* Could add these passes, too: */ +//#define CLIENT_ID_FILE OPENSSH_ECDSA384_TESTKEY +//#define CLIENT_ID_FILE OPENSSH_ECDSA521_TESTKEY + +#define CLIENT_ID_FILE OPENSSH_ED25519_TESTKEY +PKDTESTS_DEFAULT(emit_keytest, openssh_ed, OPENSSH_CMD) +PKDTESTS_KEX(emit_keytest, openssh_ed, OPENSSH_KEX_CMD) +PKDTESTS_CIPHER(emit_keytest, openssh_ed, OPENSSH_CIPHER_CMD) +PKDTESTS_CIPHER_AES192(emit_keytest, openssh_ed, OPENSSH_CIPHER_CMD) +PKDTESTS_MAC(emit_keytest, openssh_ed, OPENSSH_MAC_CMD) +#undef CLIENT_ID_FILE + +#define CLIENT_ID_FILE DROPBEAR_RSA_TESTKEY +PKDTESTS_DEFAULT(emit_keytest, dropbear, DROPBEAR_CMD) +PKDTESTS_CIPHER(emit_keytest, dropbear, DROPBEAR_CIPHER_CMD) +PKDTESTS_MAC(emit_keytest, dropbear, DROPBEAR_MAC_CMD) +#undef CLIENT_ID_FILE + +/* + * Define an array of testname strings mapped to their associated + * test function. Enables running tests individually by name from + * the command line. + */ + +#define emit_testmap(client, testname, sshcmd, setup, teardown) \ + { "torture_pkd_" #client "_" #testname, \ + { emit_unit_test(client, testname, sshcmd, setup, teardown) } }, + +#define emit_unit_test(client, testname, sshcmd, setup, teardown) \ + unit_test_setup_teardown(torture_pkd_ ## client ## _ ## testname, \ + torture_pkd_ ## setup, \ + torture_pkd_ ## teardown) + +#define emit_unit_test_comma(client, testname, sshcmd, setup, teardown) \ + emit_unit_test(client, testname, sshcmd, setup, teardown), + +struct { + const char *testname; + const UnitTest test[3]; /* requires setup + test + teardown */ +} testmap[] = { + /* OpenSSH */ + PKDTESTS_DEFAULT(emit_testmap, openssh_dsa, OPENSSH_CMD) + PKDTESTS_KEX(emit_testmap, openssh_dsa, OPENSSH_KEX_CMD) + PKDTESTS_CIPHER(emit_testmap, openssh_dsa, OPENSSH_CIPHER_CMD) + PKDTESTS_CIPHER_AES192(emit_testmap, openssh_dsa, OPENSSH_CIPHER_CMD) + PKDTESTS_MAC(emit_testmap, openssh_dsa, OPENSSH_MAC_CMD) + + PKDTESTS_DEFAULT(emit_testmap, openssh_rsa, OPENSSH_CMD) + PKDTESTS_KEX(emit_testmap, openssh_rsa, OPENSSH_KEX_CMD) + PKDTESTS_CIPHER(emit_testmap, openssh_rsa, OPENSSH_CIPHER_CMD) + PKDTESTS_CIPHER_AES192(emit_testmap, openssh_rsa, OPENSSH_CIPHER_CMD) + PKDTESTS_MAC(emit_testmap, openssh_rsa, OPENSSH_MAC_CMD) + + PKDTESTS_DEFAULT(emit_testmap, openssh_e256, OPENSSH_CMD) + PKDTESTS_KEX(emit_testmap, openssh_e256, OPENSSH_KEX_CMD) + PKDTESTS_CIPHER(emit_testmap, openssh_e256, OPENSSH_CIPHER_CMD) + PKDTESTS_CIPHER_AES192(emit_testmap, openssh_e256, OPENSSH_CIPHER_CMD) + PKDTESTS_MAC(emit_testmap, openssh_e256, OPENSSH_MAC_CMD) + + PKDTESTS_DEFAULT(emit_testmap, openssh_ed, OPENSSH_CMD) + PKDTESTS_KEX(emit_testmap, openssh_ed, OPENSSH_KEX_CMD) + PKDTESTS_CIPHER(emit_testmap, openssh_ed, OPENSSH_CIPHER_CMD) + PKDTESTS_CIPHER_AES192(emit_testmap, openssh_ed, OPENSSH_CIPHER_CMD) + PKDTESTS_MAC(emit_testmap, openssh_ed, OPENSSH_MAC_CMD) + + /* Dropbear */ + PKDTESTS_DEFAULT(emit_testmap, dropbear, DROPBEAR_CMD) + PKDTESTS_CIPHER(emit_testmap, dropbear, DROPBEAR_CIPHER_CMD) + PKDTESTS_MAC(emit_testmap, dropbear, DROPBEAR_MAC_CMD) + + /* Noop */ + emit_testmap(client, noop, "", setup_noop, teardown) + + /* NULL tail entry */ + { NULL, { { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 } } } +}; + +static int pkd_run_tests(void) { + int rc = -1; + int tindex = 0; + + const UnitTest openssh_tests[] = { + PKDTESTS_DEFAULT(emit_unit_test_comma, openssh_dsa, OPENSSH_CMD) + PKDTESTS_KEX(emit_unit_test_comma, openssh_dsa, OPENSSH_KEX_CMD) + PKDTESTS_CIPHER(emit_unit_test_comma, openssh_dsa, OPENSSH_CIPHER_CMD) + PKDTESTS_CIPHER_AES192(emit_unit_test_comma, openssh_dsa, OPENSSH_CIPHER_CMD) + PKDTESTS_MAC(emit_unit_test_comma, openssh_dsa, OPENSSH_MAC_CMD) + + PKDTESTS_DEFAULT(emit_unit_test_comma, openssh_rsa, OPENSSH_CMD) + PKDTESTS_KEX(emit_unit_test_comma, openssh_rsa, OPENSSH_KEX_CMD) + PKDTESTS_CIPHER(emit_unit_test_comma, openssh_rsa, OPENSSH_CIPHER_CMD) + PKDTESTS_CIPHER_AES192(emit_unit_test_comma, openssh_rsa, OPENSSH_CIPHER_CMD) + PKDTESTS_MAC(emit_unit_test_comma, openssh_rsa, OPENSSH_MAC_CMD) + + PKDTESTS_DEFAULT(emit_unit_test_comma, openssh_e256, OPENSSH_CMD) + PKDTESTS_KEX(emit_unit_test_comma, openssh_e256, OPENSSH_KEX_CMD) + PKDTESTS_CIPHER(emit_unit_test_comma, openssh_e256, OPENSSH_CIPHER_CMD) + PKDTESTS_CIPHER_AES192(emit_unit_test_comma, openssh_e256, OPENSSH_CIPHER_CMD) + PKDTESTS_MAC(emit_unit_test_comma, openssh_e256, OPENSSH_MAC_CMD) + + PKDTESTS_DEFAULT(emit_unit_test_comma, openssh_ed, OPENSSH_CMD) + PKDTESTS_KEX(emit_unit_test_comma, openssh_ed, OPENSSH_KEX_CMD) + PKDTESTS_CIPHER(emit_unit_test_comma, openssh_ed, OPENSSH_CIPHER_CMD) + PKDTESTS_CIPHER_AES192(emit_unit_test_comma, openssh_ed, OPENSSH_CIPHER_CMD) + PKDTESTS_MAC(emit_unit_test_comma, openssh_ed, OPENSSH_MAC_CMD) + }; + + const UnitTest dropbear_tests[] = { + PKDTESTS_DEFAULT(emit_unit_test_comma, dropbear, DROPBEAR_CMD) + PKDTESTS_CIPHER(emit_unit_test_comma, dropbear, DROPBEAR_CIPHER_CMD) + PKDTESTS_MAC(emit_unit_test_comma, dropbear, DROPBEAR_MAC_CMD) + }; + + const UnitTest noop_tests[] = { + emit_unit_test(client, noop, "", setup_noop, teardown) + }; + + /* Test list is populated depending on which clients are enabled. */ + UnitTest all_tests[(sizeof(openssh_tests) / sizeof(openssh_tests[0])) + + (sizeof(dropbear_tests) / sizeof(dropbear_tests[0])) + + (sizeof(noop_tests) / sizeof(noop_tests[0]))]; + memset(&all_tests[0], 0x0, sizeof(all_tests)); + + /* Generate client keys and populate test list for each enabled client. */ + if (is_openssh_client_enabled()) { + setup_openssh_client_keys(); + memcpy(&all_tests[tindex], &openssh_tests[0], sizeof(openssh_tests)); + tindex += (sizeof(openssh_tests) / sizeof(openssh_tests[0])); + } + + if (is_dropbear_client_enabled()) { + setup_dropbear_client_rsa_key(); + memcpy(&all_tests[tindex], &dropbear_tests[0], sizeof(dropbear_tests)); + tindex += (sizeof(dropbear_tests) / sizeof(dropbear_tests[0])); + } + + memcpy(&all_tests[tindex], &noop_tests[0], sizeof(noop_tests)); + tindex += (sizeof(noop_tests) / sizeof(noop_tests[0])); + + if (pkd_dargs.opts.testname == NULL) { + rc = _run_tests(all_tests, tindex); + } else { + int i = 0; + const UnitTest *found = NULL; + const char *testname = pkd_dargs.opts.testname; + + while (testmap[i].testname != NULL) { + if (strcmp(testmap[i].testname, testname) == 0) { + found = &testmap[i].test[0]; + break; + } + i += 1; + } + + if (found != NULL) { + rc = _run_tests(found, 3); + } else { + fprintf(stderr, "Did not find test '%s'\n", testname); + } + } + + /* Clean up client keys for each enabled client. */ + if (is_dropbear_client_enabled()) { + cleanup_dropbear_client_rsa_key(); + } + + if (is_openssh_client_enabled()) { + cleanup_openssh_client_keys(); + } + + /* Clean up any server keys that were generated. */ + cleanup_rsa_key(); + cleanup_dsa_key(); + cleanup_ecdsa_keys(); + + return rc; +} + +int main(int argc, char **argv) { + int i = 0; + int rc = 0; + + unsetenv("SSH_AUTH_SOCK"); + + rc = ssh_init(); + if (rc != 0) { + rc = SSH_ERROR; + goto out; + } + +#ifdef HAVE_ARGP_H + argp_parse(&parser, argc, argv, 0, 0, NULL); +#else /* HAVE_ARGP_H */ + (void) argc; (void) argv; +#endif /* HAVE_ARGP_H */ + + if (pkd_dargs.opts.list != 0) { + while (testmap[i].testname != NULL) { + printf("%s\n", testmap[i++].testname); + } + } else { + rc = pkd_run_tests(); + } + + rc = ssh_finalize(); + if (rc != 0) { + fprintf(stderr, "ssh_finalize: %d\n", rc); + } +out: + return rc; +} diff --git a/libssh/tests/pkd/pkd_keyutil.c b/libssh/tests/pkd/pkd_keyutil.c new file mode 100644 index 00000000..e1e1ecb8 --- /dev/null +++ b/libssh/tests/pkd/pkd_keyutil.c @@ -0,0 +1,138 @@ +/* + * pkd_keyutil.c -- pkd test key utilities + * + * (c) 2014 Jon Simons + */ + +#include // for cmocka +#include // for cmocka +#include // for cmocka +#include + +#include +#include +#include +#include + +#include "pkd_client.h" +#include "pkd_keyutil.h" +#include "pkd_util.h" + +void setup_rsa_key() { + int rc = 0; + if (access(LIBSSH_RSA_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t rsa -q -N \"\" -f " + LIBSSH_RSA_TESTKEY); + } + assert_int_equal(rc, 0); +} + +void setup_dsa_key() { + int rc = 0; + if (access(LIBSSH_DSA_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t dsa -q -N \"\" -f " + LIBSSH_DSA_TESTKEY); + } + assert_int_equal(rc, 0); +} + +void setup_ecdsa_keys() { + int rc = 0; + + if (access(LIBSSH_ECDSA_256_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t ecdsa -b 256 -q -N \"\" -f " + LIBSSH_ECDSA_256_TESTKEY); + assert_int_equal(rc, 0); + } + if (access(LIBSSH_ECDSA_384_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t ecdsa -b 384 -q -N \"\" -f " + LIBSSH_ECDSA_384_TESTKEY); + assert_int_equal(rc, 0); + } + if (access(LIBSSH_ECDSA_521_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t ecdsa -b 521 -q -N \"\" -f " + LIBSSH_ECDSA_521_TESTKEY); + assert_int_equal(rc, 0); + } +} + +static void cleanup_key(const char *privkey, const char *pubkey) { + unlink(privkey); + unlink(pubkey); +} + +void cleanup_rsa_key() { + cleanup_key(LIBSSH_RSA_TESTKEY, LIBSSH_RSA_TESTKEY ".pub"); +} + +void cleanup_dsa_key() { + cleanup_key(LIBSSH_DSA_TESTKEY, LIBSSH_DSA_TESTKEY ".pub"); +} + +void cleanup_ecdsa_keys() { + cleanup_key(LIBSSH_ECDSA_256_TESTKEY, LIBSSH_ECDSA_256_TESTKEY ".pub"); + cleanup_key(LIBSSH_ECDSA_384_TESTKEY, LIBSSH_ECDSA_384_TESTKEY ".pub"); + cleanup_key(LIBSSH_ECDSA_521_TESTKEY, LIBSSH_ECDSA_521_TESTKEY ".pub"); +} + +void setup_openssh_client_keys() { + int rc = 0; + + if (access(OPENSSH_DSA_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t dsa -q -N \"\" -f " + OPENSSH_DSA_TESTKEY); + } + assert_int_equal(rc, 0); + + if (access(OPENSSH_RSA_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t rsa -q -N \"\" -f " + OPENSSH_RSA_TESTKEY); + } + assert_int_equal(rc, 0); + + if (access(OPENSSH_ECDSA256_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t ecdsa -b 256 -q -N \"\" -f " + OPENSSH_ECDSA256_TESTKEY); + } + assert_int_equal(rc, 0); + + if (access(OPENSSH_ECDSA384_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t ecdsa -b 384 -q -N \"\" -f " + OPENSSH_ECDSA384_TESTKEY); + } + assert_int_equal(rc, 0); + + if (access(OPENSSH_ECDSA521_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t ecdsa -b 521 -q -N \"\" -f " + OPENSSH_ECDSA521_TESTKEY); + } + assert_int_equal(rc, 0); + + if (access(OPENSSH_ED25519_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t ed25519 -q -N \"\" -f " + OPENSSH_ED25519_TESTKEY); + } + assert_int_equal(rc, 0); +} + +void cleanup_openssh_client_keys() { + cleanup_key(OPENSSH_DSA_TESTKEY, OPENSSH_DSA_TESTKEY ".pub"); + cleanup_key(OPENSSH_RSA_TESTKEY, OPENSSH_RSA_TESTKEY ".pub"); + cleanup_key(OPENSSH_ECDSA256_TESTKEY, OPENSSH_ECDSA256_TESTKEY ".pub"); + cleanup_key(OPENSSH_ECDSA384_TESTKEY, OPENSSH_ECDSA384_TESTKEY ".pub"); + cleanup_key(OPENSSH_ECDSA521_TESTKEY, OPENSSH_ECDSA521_TESTKEY ".pub"); + cleanup_key(OPENSSH_ED25519_TESTKEY, OPENSSH_ED25519_TESTKEY ".pub"); +} + +void setup_dropbear_client_rsa_key() { + int rc = 0; + if (access(DROPBEAR_RSA_TESTKEY, F_OK) != 0) { + rc = system_checked(DROPBEAR_KEYGEN " -t rsa -f " + DROPBEAR_RSA_TESTKEY " 1>/dev/null 2>/dev/null"); + } + assert_int_equal(rc, 0); +} + +void cleanup_dropbear_client_rsa_key() { + unlink(DROPBEAR_RSA_TESTKEY); +} diff --git a/libssh/tests/pkd/pkd_keyutil.h b/libssh/tests/pkd/pkd_keyutil.h new file mode 100644 index 00000000..8e9de009 --- /dev/null +++ b/libssh/tests/pkd/pkd_keyutil.h @@ -0,0 +1,40 @@ +/* + * pkd_keyutil.h -- + * + * (c) 2014 Jon Simons + */ + +#ifndef __PKD_KEYUTIL_H__ +#define __PKD_KEYUTIL_H__ + +/* Server keys. */ +#define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa" +#define LIBSSH_RSA_TESTKEY "libssh_testkey.id_rsa" +#define LIBSSH_ECDSA_256_TESTKEY "libssh_testkey.id_ecdsa256" +#define LIBSSH_ECDSA_384_TESTKEY "libssh_testkey.id_ecdsa384" +#define LIBSSH_ECDSA_521_TESTKEY "libssh_testkey.id_ecdsa521" + +void setup_dsa_key(void); +void setup_rsa_key(void); +void setup_ecdsa_keys(void); +void cleanup_dsa_key(void); +void cleanup_rsa_key(void); +void cleanup_ecdsa_keys(void); + +/* Client keys. */ +#define OPENSSH_DSA_TESTKEY "openssh_testkey.id_dsa" +#define OPENSSH_RSA_TESTKEY "openssh_testkey.id_rsa" +#define OPENSSH_ECDSA256_TESTKEY "openssh_testkey.id_ecdsa256" +#define OPENSSH_ECDSA384_TESTKEY "openssh_testkey.id_ecdsa384" +#define OPENSSH_ECDSA521_TESTKEY "openssh_testkey.id_ecdsa521" +#define OPENSSH_ED25519_TESTKEY "openssh_testkey.id_ed25519" + +#define DROPBEAR_RSA_TESTKEY "dropbear_testkey.id_rsa" + +void setup_openssh_client_keys(void); +void cleanup_openssh_client_keys(void); + +void setup_dropbear_client_rsa_key(void); +void cleanup_dropbear_client_rsa_key(void); + +#endif /* __PKD_KEYUTIL_H__ */ diff --git a/libssh/tests/pkd/pkd_util.c b/libssh/tests/pkd/pkd_util.c new file mode 100644 index 00000000..963b58d6 --- /dev/null +++ b/libssh/tests/pkd/pkd_util.c @@ -0,0 +1,46 @@ +/* + * pkd_util.c -- pkd utilities + * + * (c) 2014 Jon Simons + */ + +#include +#include +#include +#include + +#include "pkd_client.h" +#include "pkd_util.h" + +/** + * @brief runs system(3); exits if that is interrupted with SIGINT/QUIT + * @returns 0 upon success, non-zero otherwise + */ +int system_checked(const char *cmd) { + int rc = system(cmd); + + if (WIFSIGNALED(rc) && + ((WTERMSIG(rc) == SIGINT) || (WTERMSIG(rc) == SIGQUIT))) { + exit(1); + } + + if (rc == -1) { + return -1; + } + + return WEXITSTATUS(rc); +} + +static int bin_exists(const char *binary) { + char bin[1024] = { 0 }; + snprintf(&bin[0], sizeof(bin), "type %s 1>/dev/null 2>/dev/null", binary); + return (system_checked(bin) == 0); +} + +int is_openssh_client_enabled(void) { + return (bin_exists(OPENSSH_BINARY) && bin_exists(OPENSSH_KEYGEN)); +} + +int is_dropbear_client_enabled(void) { + return (bin_exists(DROPBEAR_BINARY) && bin_exists(DROPBEAR_KEYGEN)); +} diff --git a/libssh/tests/pkd/pkd_util.h b/libssh/tests/pkd/pkd_util.h new file mode 100644 index 00000000..aedbbe9f --- /dev/null +++ b/libssh/tests/pkd/pkd_util.h @@ -0,0 +1,16 @@ +/* + * pkd_keyutil.h -- + * + * (c) 2014 Jon Simons + */ + +#ifndef __PKD_UTIL_H__ +#define __PKD_UTIL_H__ + +int system_checked(const char *cmd); + +/* Is client 'X' enabled? */ +int is_openssh_client_enabled(void); +int is_dropbear_client_enabled(void); + +#endif /* __PKD_UTIL_H__ */ diff --git a/libssh/tests/test_ssh_bind_accept_fd.c b/libssh/tests/test_ssh_bind_accept_fd.c new file mode 100644 index 00000000..7611cf4c --- /dev/null +++ b/libssh/tests/test_ssh_bind_accept_fd.c @@ -0,0 +1,139 @@ +/* Test the ability to use ssh_bind_accept_fd. + * + * Expected behavior: Prints "SUCCESS!" + * + * Faulty behavior observed before change: Connection timeout + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct options { + const char *server_keyfile; +} options; + +const char HOST[] = "127.0.0.1"; +const int PORT = 3333; + +int get_connection() { + int rc, server_socket, client_conn = -1; + struct sockaddr_in server_socket_addr; + struct sockaddr_storage client_conn_addr; + socklen_t client_conn_addr_size = sizeof(client_conn_addr); + + server_socket = socket(PF_INET, SOCK_STREAM, 0); + if (server_socket < 0) { + goto out; + } + + server_socket_addr.sin_family = AF_INET; + server_socket_addr.sin_port = htons(PORT); + if (inet_pton(AF_INET, HOST, &server_socket_addr.sin_addr) != 1) { + goto out; + } + + rc = bind(server_socket, (struct sockaddr *)&server_socket_addr, + sizeof(server_socket_addr)); + if (rc < 0) { + goto out; + } + + if (listen(server_socket, 0) < 0) { + goto out; + } + + client_conn = accept(server_socket, + (struct sockaddr *)&client_conn_addr, + &client_conn_addr_size); + + out: + return client_conn; +} + +void ssh_server() { + ssh_bind bind; + ssh_session session; + + int client_conn = get_connection(); + if (client_conn < 0) { + err(1, "get_connection"); + } + + bind = ssh_bind_new(); + if (!bind) { + errx(1, "ssh_bind_new"); + } + + if (ssh_bind_options_set(bind, SSH_BIND_OPTIONS_DSAKEY, + options.server_keyfile) != SSH_OK) { + errx(1, "ssh_bind_options_set(SSH_BIND_OPTIONS_DSAKEY"); + } + + session = ssh_new(); + if (!session) { + errx(1, "ssh_new"); + } + + if (ssh_bind_accept_fd(bind, session, client_conn) != SSH_OK) { + errx(1, "ssh_bind_accept: %s", ssh_get_error(bind)); + } + + if (ssh_handle_key_exchange(session) != SSH_OK) { + errx(1, "ssh_handle_key_exchange: %s", ssh_get_error(session)); + } + + printf("SUCCESS!\n"); +} + +void ssh_client() { + ssh_session session; + + session = ssh_new(); + if (!session) { + errx(1, "ssh_new"); + } + + if (ssh_options_set(session, SSH_OPTIONS_HOST, HOST) < 0) { + errx(1, "ssh_options_set(SSH_OPTIONS_HOST)"); + } + if (ssh_options_set(session, SSH_OPTIONS_PORT, &PORT) < 0) { + errx(1, "ssh_options_set(SSH_OPTIONS_PORT)"); + } + + if (ssh_connect(session) != SSH_OK) { + errx(1, "ssh_connect: %s", ssh_get_error(session)); + } +} + +int main(int argc, const char *argv[]) { + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + exit(1); + } + + options.server_keyfile = argv[1]; + + pid_t pid = fork(); + if (pid < 0) { + errx(1, "fork"); + } + if (pid == 0) { + /* Allow the server to get set up */ + sleep(3); + + ssh_client(); + } else { + ssh_server(); + } + + return 0; +} diff --git a/libssh/tests/torture.c b/libssh/tests/torture.c index c7031fcb..0b8eb3da 100644 --- a/libssh/tests/torture.c +++ b/libssh/tests/torture.c @@ -3,7 +3,7 @@ * * This file is part of the SSH Library * - * Copyright (c) 2008-2009 by Andreas Schneider + * Copyright (c) 2008-2009 by Andreas Schneider * * 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,9 +25,11 @@ #include #include +#include +#include +#include + #ifndef _WIN32 -# include -# include # include # include #endif @@ -38,6 +40,162 @@ #include "torture.h" +#define TORTURE_TESTKEY_PASSWORD "libssh-rocks" + +static const char torture_rsa_testkey[] = + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEArAOREUWlBXJAKZ5hABYyxnRayDZP1bJeLbPVK+npxemrhHyZ\n" + "gjdbY3ADot+JRyWjvll2w2GI+3blt0j+x/ZWwjMKu/QYcycYp5HL01goxOxuusZb\n" + "i+KiHRGB6z0EMdXM7U82U7lA/j//HyZppyDjUDniWabXQJge8ksGXGTiFeAJ/687\n" + "uV+JJcjGPxAGFQxzyjitf/FrL9S0WGKZbyqeGDzyeBZ1NLIuaiOORyLGSW4duHLD\n" + "N78EmsJnwqg2gJQmRSaD4BNZMjtbfiFcSL9Uw4XQFTsWugUDEY1AU4c5g11nhzHz\n" + "Bi9qMOt5DzrZQpD4j0gA2LOHpHhoOdg1ZuHrGQIDAQABAoIBAFJTaqy/jllq8vZ4\n" + "TKiD900wBvrns5HtSlHJTe80hqQoT+Sa1cWSxPR0eekL32Hjy9igbMzZ83uWzh7I\n" + "mtgNODy9vRdznfgO8CfTCaBfAzQsjFpr8QikMT6EUI/LpiRL1UaGsNOlSEvnSS0Z\n" + "b1uDzAdrjL+nsEHEDJud+K9jwSkCRifVMy7fLfaum+YKpdeEz7K2Mgm5pJ/Vg+9s\n" + "vI2V1q7HAOI4eUVTgJNHXy5ediRJlajQHf/lNUzHKqn7iH+JRl01gt62X8roG62b\n" + "TbFylbheqMm9awuSF2ucOcx+guuwhkPir8BEMb08j3hiK+TfwPdY0F6QH4OhiKK7\n" + "MTqTVgECgYEA0vmmu5GOBtwRmq6gVNCHhdLDQWaxAZqQRmRbzxVhFpbv0GjbQEF7\n" + "tttq3fjDrzDf6CE9RtZWw2BUSXVq+IXB/bXb1kgWU2xWywm+OFDk9OXQs8ui+MY7\n" + "FiP3yuq3YJob2g5CCsVQWl2CHvWGmTLhE1ODll39t7Y1uwdcDobJN+ECgYEA0LlR\n" + "hfMjydWmwqooU9TDjXNBmwufyYlNFTH351amYgFUDpNf35SMCP4hDosUw/zCTDpc\n" + "+1w04BJJfkH1SNvXSOilpdaYRTYuryDvGmWC66K2KX1nLErhlhs17CwzV997nYgD\n" + "H3OOU4HfqIKmdGbjvWlkmY+mLHyG10bbpOTbujkCgYAc68xHejSWDCT9p2KjPdLW\n" + "LYZGuOUa6y1L+QX85Vlh118Ymsczj8Z90qZbt3Zb1b9b+vKDe255agMj7syzNOLa\n" + "/MseHNOyq+9Z9gP1hGFekQKDIy88GzCOYG/fiT2KKJYY1kuHXnUdbiQgSlghODBS\n" + "jehD/K6DOJ80/FVKSH/dAQKBgQDJ+apTzpZhJ2f5k6L2jDq3VEK2ACedZEm9Kt9T\n" + "c1wKFnL6r83kkuB3i0L9ycRMavixvwBfFDjuY4POs5Dh8ip/mPFCa0hqISZHvbzi\n" + "dDyePJO9zmXaTJPDJ42kfpkofVAnfohXFQEy+cguTk848J+MmMIKfyE0h0QMabr9\n" + "86BUsQKBgEVgoi4RXwmtGovtMew01ORPV9MOX3v+VnsCgD4/56URKOAngiS70xEP\n" + "ONwNbTCWuuv43HGzJoVFiAMGnQP1BAJ7gkHkjSegOGKkiw12EPUWhFcMg+GkgPhc\n" + "pOqNt/VMBPjJ/ysHJqmLfQK9A35JV6Cmdphe+OIl28bcKhAOz8Dw\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char torture_rsa_testkey_pub[] = + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsA5ERRaUFckApnmEAFjLGdFrIN" + "k/Vsl4ts9Ur6enF6auEfJmCN1tjcAOi34lHJaO+WXbDYYj7duW3SP7H9lbCMwq79B" + "hzJxinkcvTWCjE7G66xluL4qIdEYHrPQQx1cztTzZTuUD+P/8fJmmnIONQOeJZptd" + "AmB7ySwZcZOIV4An/rzu5X4klyMY/EAYVDHPKOK1/8Wsv1LRYYplvKp4YPPJ4FnU0" + "si5qI45HIsZJbh24csM3vwSawmfCqDaAlCZFJoPgE1kyO1t+IVxIv1TDhdAVOxa6B" + "QMRjUBThzmDXWeHMfMGL2ow63kPOtlCkPiPSADYs4ekeGg52DVm4esZ " + "aris@aris-air\n"; + +static const char torture_dsa_testkey[] = + "-----BEGIN DSA PRIVATE KEY-----\n" + "MIIBuwIBAAKBgQCUyvVPEkn3UnZDjzCzSzSHpTltzr0Ec+1mz/JACjHMBJ9C/W/P\n" + "wvH3yjkfoFhhREvoY7IPnwAu5bcxw8TkISq7YROQ409PqwwPvy0N3GUp/+kKS268\n" + "BIJ+VKN513XRf7eL1e4aHUJ+al9x1JxTmc6T0GBq1lyu+CTUUyh25aNDFwIVAK84\n" + "j20GmU+zewjQwsIXuVb6C/PHAoGAXhuIVsJxUQJ5nWQRLf7o3XEGQ+EcVmHOzMB1\n" + "xCsHjYnpEhhco+r/HDZSD31kzDeAZUycz31WqGL8yXr+OZRLqEsGC7dwEAzPiXDu\n" + "l0zHcl0yiKPrRrLgNJHeKcT6JflBngK7jQRIVUg3F3104fbVa2rwaniLl4GSBZPX\n" + "MpUdng8CgYB4roDQBfgf8AoSAJAb7y8OVvxt5cT7iqaRMQX2XgtW09Nu9RbUIVS7\n" + "n2mw3iqZG0xnG3iv1oL9gwNXMLlf+gLmsqU3788jaEZ9IhZ8VdgHAoHm6UWM7b2u\n" + "ADmhirI6dRZUVO+/iMGUvDxa66OI4hDV055pbwQhtxupUatThyDzIgIVAI1Hd8/i\n" + "Pzsg7bTzoNvjQL+Noyiy\n" + "-----END DSA PRIVATE KEY-----\n"; + +static const char torture_dsa_testkey_pub[] = + "ssh-dss AAAAB3NzaC1kc3MAAACBAJTK9U8SSfdSdkOPMLNLNIelOW3OvQRz7WbP8k" + "AKMcwEn0L9b8/C8ffKOR+gWGFES+hjsg+fAC7ltzHDxOQhKrthE5DjT0+rDA+/LQ3c" + "ZSn/6QpLbrwEgn5Uo3nXddF/t4vV7hodQn5qX3HUnFOZzpPQYGrWXK74JNRTKHblo0" + "MXAAAAFQCvOI9tBplPs3sI0MLCF7lW+gvzxwAAAIBeG4hWwnFRAnmdZBEt/ujdcQZD" + "4RxWYc7MwHXEKweNiekSGFyj6v8cNlIPfWTMN4BlTJzPfVaoYvzJev45lEuoSwYLt3" + "AQDM+JcO6XTMdyXTKIo+tGsuA0kd4pxPol+UGeAruNBEhVSDcXfXTh9tVravBqeIuX" + "gZIFk9cylR2eDwAAAIB4roDQBfgf8AoSAJAb7y8OVvxt5cT7iqaRMQX2XgtW09Nu9R" + "bUIVS7n2mw3iqZG0xnG3iv1oL9gwNXMLlf+gLmsqU3788jaEZ9IhZ8VdgHAoHm6UWM" + "7b2uADmhirI6dRZUVO+/iMGUvDxa66OI4hDV055pbwQhtxupUatThyDzIg== " + "aris@aris-air\n"; + +static const char torture_rsa_testkey_pp[] = + "-----BEGIN RSA PRIVATE KEY-----\n" + "Proc-Type: 4,ENCRYPTED\n" + "DEK-Info: AES-128-CBC,5375534F40903DD66B3851A0DA03F6FA\n" + "\n" + "m5YYTNOMd1xCKfifwCX4R1iLJoAc4cn1aFiL7f2kBbfE2jF1LTQBJV1h1CqYZfAB\n" + "WtM/7FkQPnKXqsMndP+v+1Xc+PYigE3AezJj/0g7xn/zIBwGjkLAp435AdL5i6Fg\n" + "OhOL8LyolRrcGn17jE4S4iGbzw8PVyfzNzdj0Emwql5F6M7pgLbInRNKM/TF4z2h\n" + "b6Pi9Bw43dwaJ7wiiy/vo/v4MyXsJBoeKbc4VCmxiYFvAYCvVFlDkyIw/QnR3MKQ\n" + "g/Zsk7Pw3aOioxk6LJpZ5x0tO23nXDG1aOZHWykI0BpJV+LIpD2oSYOHJyVO83XT\n" + "RQUMSTXc2K2+ejs0XQoLt/GxDDHe+8W8fWQK3C7Lyvl9oKjmb5sTWi3mdSv0C+zR\n" + "n5KSVbUKNXrjix7qPKkv5rWqb84CKVnCMb7tWaPLR19nQqKVYBIs6v0OTTvS6Le7\n" + "lz4lxBkcUy6vi0tWH9MvLuT+ugdHLJZ4UXBthCgV58pM1o+L+WMIl+SZXckiCAO3\n" + "7ercA57695IA6iHskmr3eazJsYFEVFdR/cm+IDy2FPkKmJMjXeIWuh3yASBk7LBR\n" + "EQq3CC7AioO+Vj8m/fEIiNZJSQ6p0NmgnPoO3rTYT/IobmE99/Ht6oNLmFX4Pr7e\n" + "F4CGWKzwxWpCnw2vVolCFByASmZycbJvrIonZBKY1toU28lRm4tCM6eCNISVLMeE\n" + "VtQ+1PH9/2KZspZl+SX/kjV3egggy0TFKRU8EcYPJFC3Vpy+shEai35KBVo44Z18\n" + "apza7exm3igNEqOqe07hLs3Bjhvk1oS+WhMbAG9ARTOKuyBOJh/ZV9tFMNZ6v+q5\n" + "TofgNcIhNYNascymU1io18xTW9c3RRcmRKqIWnj4EH8o7Aojv/l+zvdV7/GVlR4W\n" + "pR9cuJEiyiEjS46axoc6dSOtdnvag+BpFQb+lGY97F9nNGyBdtLD5ASVh5OVG4fu\n" + "Pf0O7Bdj1kIuBhV8axE/slf6UHANiodeqkR9B24+0Cy+miPiHazzUkbdSJ4r03g5\n" + "J1Y5S8qbl9++sqhQMLMUkeK4pDWh1aocA9bDA2RcBNuXGiZeRFUiqxcBS+iO418n\n" + "DFyWz4UfI/m1IRSjoo/PEpgu5GmosUzs3Dl4nAcf/REBEX6M/kKKxHTLjE8DxDsz\n" + "fn/vfsXV3s0tbN7YyJdP8aU+ApZntw1OF2TS2qS8CPWHTcCGGTab5WEGC3xFXKp0\n" + "uyonCxV7vNLOiIiHdQX+1bLu7ps7GBH92xGkPg7FrNNcMc07soP7jjjB578n9Gpl\n" + "cIDBdgovTRFHiWu3yRspVt0zPfMJB/hqn+IAp98wfvjl8OZM1ZZkejnwXnQil5ZU\n" + "wjEBEtx+nX56vdxipzKoHh5yDXmPbNajBYkg3rXJrLFh3Tsf0CzHcLdHNz/qJ9LO\n" + "wH16grjR1Q0CzCW3FAv0Q0euqkXac+TfuIg3HiTPrBPnJQW1uivrx1F5tpO/uboG\n" + "h28LwqJLYh+1T0V//uiy3SMATpYKvzg2byGct9VUib8QVop8LvVF/n42RaxtTCfw\n" + "JSvUyxoaZUjQkT7iF94HsF+FVVJdI55UjgnMiZ0d5vKffWyTHYcYHkFYaSloAMWN\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char torture_dsa_testkey_pp[] = + "-----BEGIN DSA PRIVATE KEY-----\n" + "Proc-Type: 4,ENCRYPTED\n" + "DEK-Info: AES-128-CBC,266023B64B1B814BCD0D0E477257F06D\n" + "\n" + "QJQErZrvYsfeMNMnU+6yVHH5Zze/zUFdPip7Bon4T1wCGlVasn4x/GQcMm1+mgmb\n" + "PCK/qJ5qw9nCepLYJq2xh8gohbwF/XKxeaNGcRA2+ancTooDUjeRTlk1WRtS1+bq\n" + "LBkwhxLXW26lIuQUHzfi93rRqQI2LC4McngY7L7WVJer7sH7hk5//4Gf6zHtPEl+\n" + "Tr2ub1zNrVbh6e1Bitw7DaGZNX6XEWpyTTsAd42sQWh6o23MC6GyfS1YFsPGHzGe\n" + "WYQbWn2AZ1mK32z2mLZfVg41qu9RKG20iCyaczZ2YmuYyOkoLHijOAHC8vZbHwYC\n" + "+lN9Yc8/BoMuMMwDTMDaJD0TsBX02hi9YI7Gu88PMCJO+SRe5400MonUMXTwCa91\n" + "Tt3RhYpBzx2XGOq5199+oLdTJAaXHJcuB6viKNdSLBuhx6RAEJXZnVexchaHs4Q6\n" + "HweIv6Et8MjVoqwkaQDmcIGA73qZ0lbUJFZAu2YDJ6TpHc1lHZes763HoMYfuvkX\n" + "HTSuHZ7edjoWqwnl/vkc3+nG//IEj8LqAacx0i4krDcQpGuQ6BnPfwPFco2NQQpw\n" + "wHBOL6HrOnD+gGs6DUFwzA==\n" + "-----END DSA PRIVATE KEY-----\n"; + +static const char torture_ecdsa256_testkey[] = + "-----BEGIN EC PRIVATE KEY-----\n" + "MHcCAQEEIBCDeeYYAtX3EnsP0ratwVpNTaA/4K1N6VvHMiUZlVdhoAoGCCqGSM49\n" + "AwEHoUQDQgAEx+9ud88Q5GWtLd+yMtYaapC85g+2ZLp7VtFHA0EbNHqBUQxoh+Ik\n" + "89Mlr7AUxcFPd+kCo+NE6yq/mNQcL7E6iQ==\n" + "-----END EC PRIVATE KEY-----\n"; + +static const char torture_ecdsa256_testkey_pub[] = + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNT" + "YAAABBBMfvbnfPEORlrS3fsjLWGmqQvOYPtmS6e1bRRwNBGzR6gVEMaIfiJPPTJa+w" + "FMXBT3fpAqPjROsqv5jUHC+xOok= aris@kalix86\n"; + +static const char torture_ecdsa384_testkey[] = + "-----BEGIN EC PRIVATE KEY-----\n" + "MIGkAgEBBDBY8jEa5DtRy4AVeTWhPJ/TK257behiC3uafEi6YA2oHORibqX55EDN\n" + "wz29MT40mQSgBwYFK4EEACKhZANiAARXc4BN6BrVo1QMi3+i/B85Lu7SMuzBi+1P\n" + "bJti8xz+Szgq64gaBGOK9o+WOdLAd/w7p7DJLdztJ0bYoyT4V3B3ZqR9RyGq6mYC\n" + "jkXlc5YbYHjueBbp0oeNXqsXHNAWQZo=\n" + "-----END EC PRIVATE KEY-----\n"; + +static const char torture_ecdsa384_testkey_pub[] = + "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzOD" + "QAAABhBFdzgE3oGtWjVAyLf6L8Hzku7tIy7MGL7U9sm2LzHP5LOCrriBoEY4r2j5Y5" + "0sB3/DunsMkt3O0nRtijJPhXcHdmpH1HIarqZgKOReVzlhtgeO54FunSh41eqxcc0B" + "ZBmg== aris@kalix86"; + +static const char torture_ecdsa521_testkey[] = + "-----BEGIN EC PRIVATE KEY-----\n" + "MIHbAgEBBEG83nSJ2SLoiBvEku1JteQKWx/Xt6THksgC7rrIaTUmNzk+60f0sCCm\n" + "Gll0dgrZLmeIw+TtnG1E20VZflCKq+IdkaAHBgUrgQQAI6GBiQOBhgAEAc6D728d\n" + "baQkHnSPtztaRwJw63CBl15cykB4SXXuwWdNOtPzBijUULMTTvBXbra8gL4ATd9d\n" + "Qnuwn8KQUh2T/z+BARjWPKhcHcGx57XpXCEkawzMYaHUUnRdeFEmNRsbXypsf0mJ\n" + "KATU3h8gzTMkbrx8DJTFHEIjXBShs44HsSYVl3Xy\n" + "-----END EC PRIVATE KEY-----\n"; + +static const char torture_ecdsa521_testkey_pub[] = + "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1Mj" + "EAAACFBAHOg+9vHW2kJB50j7c7WkcCcOtwgZdeXMpAeEl17sFnTTrT8wYo1FCzE07w" + "V262vIC+AE3fXUJ7sJ/CkFIdk/8/gQEY1jyoXB3Bsee16VwhJGsMzGGh1FJ0XXhRJj" + "UbG18qbH9JiSgE1N4fIM0zJG68fAyUxRxCI1wUobOOB7EmFZd18g== aris@kalix86"; + static int verbosity = 0; #ifndef _WIN32 @@ -302,6 +460,84 @@ void torture_sftp_close(struct torture_sftp *t) { #endif /* _WIN32 */ +void torture_write_file(const char *filename, const char *data){ + int fd; + int rc; + + assert_non_null(filename); + assert_true(filename[0] != '\0'); + assert_non_null(data); + + fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0755); + assert_true(fd >= 0); + + rc = write(fd, data, strlen(data)); + assert_int_equal(rc, strlen(data)); + + close(fd); +} + +static const char *torture_get_testkey_internal(enum ssh_keytypes_e type, + int bits, + int with_passphrase, + int pubkey) +{ + switch (type) { + case SSH_KEYTYPE_DSS: + if (pubkey) { + return torture_dsa_testkey_pub; + } else if (with_passphrase) { + return torture_dsa_testkey_pp; + } + return torture_dsa_testkey; + case SSH_KEYTYPE_RSA: + if (pubkey) { + return torture_rsa_testkey_pub; + } else if (with_passphrase) { + return torture_rsa_testkey_pp; + } + return torture_rsa_testkey; + case SSH_KEYTYPE_ECDSA: + if (bits == 521) { + if (pubkey) { + return torture_ecdsa521_testkey_pub; + } + return torture_ecdsa521_testkey; + } else if (bits == 384) { + if (pubkey) { + return torture_ecdsa384_testkey_pub; + } + return torture_ecdsa384_testkey; + } + + if (pubkey) { + return torture_ecdsa256_testkey_pub; + } + return torture_ecdsa256_testkey; + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_UNKNOWN: + return NULL; + } + + return NULL; +} + +const char *torture_get_testkey(enum ssh_keytypes_e type, + int ecda_bits, + int with_passphrase) +{ + return torture_get_testkey_internal(type, ecda_bits, with_passphrase, 0); +} + +const char *torture_get_testkey_pub(enum ssh_keytypes_e type, int ecda_bits) +{ + return torture_get_testkey_internal(type, ecda_bits, 0, 1); +} + +const char *torture_get_testkey_passphrase(void) +{ + return TORTURE_TESTKEY_PASSWORD; +} int torture_libssh_verbosity(void){ return verbosity; diff --git a/libssh/tests/torture.h b/libssh/tests/torture.h index dbc1906a..ffcea8bb 100644 --- a/libssh/tests/torture.h +++ b/libssh/tests/torture.h @@ -3,7 +3,7 @@ * * This file is part of the SSH Library * - * Copyright (c) 2008-2009 by Andreas Schneider + * Copyright (c) 2008-2009 by Andreas Schneider * * 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 @@ -68,6 +68,14 @@ ssh_session torture_ssh_session(const char *host, struct torture_sftp *torture_sftp_session(ssh_session session); void torture_sftp_close(struct torture_sftp *t); +const char *torture_get_testkey(enum ssh_keytypes_e type, + int ecdsa_bits, + int with_passphrase); +const char *torture_get_testkey_pub(enum ssh_keytypes_e type, int ecdsa_bits); +const char *torture_get_testkey_passphrase(void); + +void torture_write_file(const char *filename, const char *data); + /* * This function must be defined in every unit test file. */ diff --git a/libssh/tests/unittests/torture_buffer.c b/libssh/tests/unittests/torture_buffer.c index dee6e7d4..ec87259d 100644 --- a/libssh/tests/unittests/torture_buffer.c +++ b/libssh/tests/unittests/torture_buffer.c @@ -9,6 +9,7 @@ static void setup(void **state) { ssh_buffer buffer; buffer = ssh_buffer_new(); + ssh_buffer_set_secure(buffer); *state = (void *) buffer; } @@ -25,7 +26,7 @@ static void torture_growing_buffer(void **state) { int i; for(i=0;iused >= 128){ if(buffer_get_rest_len(buffer) * 2 < buffer->allocated){ assert_true(buffer_get_rest_len(buffer) * 2 >= buffer->allocated); @@ -43,11 +44,11 @@ static void torture_growing_buffer_shifting(void **state) { int i; unsigned char c; for(i=0; i<1024;++i){ - buffer_add_data(buffer,"S",1); + ssh_buffer_add_data(buffer,"S",1); } for(i=0;iused >= 128){ if(buffer_get_rest_len(buffer) * 4 < buffer->allocated){ assert_true(buffer_get_rest_len(buffer) * 4 >= buffer->allocated); @@ -63,7 +64,7 @@ static void torture_growing_buffer_shifting(void **state) { static void torture_buffer_prepend(void **state) { ssh_buffer buffer = *state; uint32_t v; - buffer_add_data(buffer,"abcdef",6); + ssh_buffer_add_data(buffer,"abcdef",6); buffer_prepend_data(buffer,"xyz",3); assert_int_equal(buffer_get_rest_len(buffer),9); assert_memory_equal(buffer_get_rest(buffer), "xyzabcdef", 9); @@ -102,27 +103,150 @@ static void torture_buffer_get_ssh_string(void **state) { for(i=0; i < (int)(sizeof(values)/sizeof(values[0]));++i){ for(j=0; j< (int)sizeof(data);++j){ for(k=1;k<5;++k){ - buffer=buffer_new(); + buffer = ssh_buffer_new(); assert_non_null(buffer); for(l=0;lexecuted++; +} + +static void torture_log_callback(void **state) +{ + struct test_mock_state t = { + .executed = 0, + }; + + (void)state; /* unused */ + + ssh_set_log_callback(test_mock_ssh_logging_callback); + ssh_set_log_userdata(&t); + ssh_set_log_level(1); + + expect_value(test_mock_ssh_logging_callback, priority, 1); + expect_string(test_mock_ssh_logging_callback, function, "torture_log_callback"); + expect_string(test_mock_ssh_logging_callback, buffer, "torture_log_callback: test"); + + SSH_LOG(SSH_LOG_WARN, "test"); + + assert_int_equal(t.executed, 1); +} + int torture_run_tests(void) { int rc; const UnitTest tests[] = { unit_test_setup_teardown(torture_callbacks_size, setup, teardown), unit_test_setup_teardown(torture_callbacks_exists, setup, teardown), + unit_test(torture_log_callback), }; ssh_init(); diff --git a/libssh/tests/unittests/torture_channel.c b/libssh/tests/unittests/torture_channel.c index 5bf34fd9..1d928b84 100644 --- a/libssh/tests/unittests/torture_channel.c +++ b/libssh/tests/unittests/torture_channel.c @@ -20,6 +20,7 @@ static void torture_channel_select(void **state) fd = open("/dev/null", 0); assert_true(fd > 2); + FD_ZERO(&readfds); FD_SET(fd, &readfds); for (i = 0; i < 10; i++) { diff --git a/libssh/tests/unittests/torture_pki.c b/libssh/tests/unittests/torture_pki.c index 7324177e..efcbb01b 100644 --- a/libssh/tests/unittests/torture_pki.c +++ b/libssh/tests/unittests/torture_pki.c @@ -8,44 +8,57 @@ #define LIBSSH_RSA_TESTKEY "libssh_testkey.id_rsa" #define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa" #define LIBSSH_ECDSA_TESTKEY "libssh_testkey.id_ecdsa" -#define LIBSSH_PASSPHRASE "libssh-rocks" + const unsigned char HASH[] = "12345678901234567890"; static void setup_rsa_key(void **state) { - int rc; - (void) state; /* unused */ unlink(LIBSSH_RSA_TESTKEY); unlink(LIBSSH_RSA_TESTKEY ".pub"); - rc = system("ssh-keygen -t rsa -q -N \"\" -f " LIBSSH_RSA_TESTKEY); - assert_true(rc == 0); + torture_write_file(LIBSSH_RSA_TESTKEY, + torture_get_testkey(SSH_KEYTYPE_RSA, 0, 0)); + torture_write_file(LIBSSH_RSA_TESTKEY ".pub", + torture_get_testkey_pub(SSH_KEYTYPE_RSA, 0)); } static void setup_dsa_key(void **state) { - int rc; - (void) state; /* unused */ unlink(LIBSSH_DSA_TESTKEY); unlink(LIBSSH_DSA_TESTKEY ".pub"); - rc = system("ssh-keygen -t dsa -q -N \"\" -f " LIBSSH_DSA_TESTKEY); - assert_true(rc == 0); + torture_write_file(LIBSSH_DSA_TESTKEY, + torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0)); + torture_write_file(LIBSSH_DSA_TESTKEY ".pub", + torture_get_testkey_pub(SSH_KEYTYPE_DSS, 0)); } #ifdef HAVE_OPENSSL_ECC -static void setup_ecdsa_key(void **state) { - int rc; +static void setup_ecdsa_key(void **state, int ecdsa_bits) { (void) state; /* unused */ unlink(LIBSSH_ECDSA_TESTKEY); unlink(LIBSSH_ECDSA_TESTKEY ".pub"); - rc = system("ssh-keygen -t ecdsa -q -N \"\" -f " LIBSSH_ECDSA_TESTKEY); - assert_true(rc == 0); + torture_write_file(LIBSSH_ECDSA_TESTKEY, + torture_get_testkey(SSH_KEYTYPE_ECDSA, ecdsa_bits, 0)); + torture_write_file(LIBSSH_ECDSA_TESTKEY ".pub", + torture_get_testkey_pub(SSH_KEYTYPE_ECDSA, ecdsa_bits)); +} + +static void setup_ecdsa_key_521(void **state) { + setup_ecdsa_key(state, 521); +} + +static void setup_ecdsa_key_384(void **state) { + setup_ecdsa_key(state, 384); +} + +static void setup_ecdsa_key_256(void **state) { + setup_ecdsa_key(state, 256); } #endif @@ -56,18 +69,6 @@ static void setup_both_keys(void **state) { setup_dsa_key(state); } -static void setup_both_keys_passphrase(void **state) { - int rc; - - (void) state; /* unused */ - - rc = system("ssh-keygen -t rsa -q -N " LIBSSH_PASSPHRASE " -f " LIBSSH_RSA_TESTKEY); - assert_true(rc == 0); - - rc = system("ssh-keygen -t dsa -q -N " LIBSSH_PASSPHRASE " -f " LIBSSH_DSA_TESTKEY); - assert_true(rc == 0); -} - static void teardown(void **state) { (void) state; /* unused */ @@ -111,24 +112,40 @@ static char *read_file(const char *filename) { static int torture_read_one_line(const char *filename, char *buffer, size_t len) { FILE *fp; - size_t rc; + size_t nmemb; fp = fopen(filename, "r"); if (fp == NULL) { return -1; } - rc = fread(buffer, len, 1, fp); - if (rc != 0 || ferror(fp)) { + nmemb = fread(buffer, len - 2, 1, fp); + if (nmemb != 0 || ferror(fp)) { fclose(fp); return -1; } + buffer[len - 1] = '\0'; fclose(fp); return 0; } +/** @internal + * returns the character len of a public key string, omitting the comment part + */ +static int torture_pubkey_len(const char *pubkey){ + const char *ptr; + ptr=strchr(pubkey, ' '); + if (ptr != NULL){ + ptr = strchr(ptr + 1, ' '); + if (ptr != NULL){ + return ptr - pubkey; + } + } + return 0; +} + static void torture_pki_keytype(void **state) { enum ssh_keytypes_e type; const char *type_c; @@ -167,7 +184,7 @@ static void torture_pki_import_privkey_base64_RSA(void **state) { int rc; char *key_str; ssh_key key; - const char *passphrase = LIBSSH_PASSPHRASE; + const char *passphrase = torture_get_testkey_passphrase(); enum ssh_keytypes_e type; (void) state; /* unused */ @@ -190,60 +207,48 @@ static void torture_pki_import_privkey_base64_RSA(void **state) { static void torture_pki_import_privkey_base64_NULL_key(void **state) { int rc; - char *key_str; - ssh_key key; - const char *passphrase = LIBSSH_PASSPHRASE; + const char *passphrase = torture_get_testkey_passphrase(); (void) state; /* unused */ - key_str = read_file(LIBSSH_RSA_TESTKEY); - assert_true(key_str != NULL); - - key = ssh_key_new(); - assert_true(key != NULL); - /* test if it returns -1 if key is NULL */ - rc = ssh_pki_import_privkey_base64(key_str, passphrase, NULL, NULL, NULL); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_RSA, 0, 0), + passphrase, + NULL, + NULL, + NULL); assert_true(rc == -1); - free(key_str); - ssh_key_free(key); } static void torture_pki_import_privkey_base64_NULL_str(void **state) { int rc; - char *key_str; ssh_key key = NULL; - const char *passphrase = LIBSSH_PASSPHRASE; + const char *passphrase = torture_get_testkey_passphrase(); (void) state; /* unused */ - key_str = read_file(LIBSSH_RSA_TESTKEY); - assert_true(key_str != NULL); - /* test if it returns -1 if key_str is NULL */ rc = ssh_pki_import_privkey_base64(NULL, passphrase, NULL, NULL, &key); assert_true(rc == -1); - free(key_str); ssh_key_free(key); } static void torture_pki_import_privkey_base64_DSA(void **state) { int rc; - char *key_str; ssh_key key; - const char *passphrase = LIBSSH_PASSPHRASE; + const char *passphrase = torture_get_testkey_passphrase(); (void) state; /* unused */ - key_str = read_file(LIBSSH_DSA_TESTKEY); - assert_true(key_str != NULL); - - rc = ssh_pki_import_privkey_base64(key_str, passphrase, NULL, NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0), + passphrase, + NULL, + NULL, + &key); assert_true(rc == 0); - free(key_str); ssh_key_free(key); } @@ -252,7 +257,7 @@ static void torture_pki_import_privkey_base64_ECDSA(void **state) { int rc; char *key_str; ssh_key key; - const char *passphrase = LIBSSH_PASSPHRASE; + const char *passphrase = torture_get_testkey_passphrase(); (void) state; /* unused */ @@ -269,97 +274,110 @@ static void torture_pki_import_privkey_base64_ECDSA(void **state) { static void torture_pki_import_privkey_base64_passphrase(void **state) { int rc; - char *key_str; ssh_key key = NULL; - const char *passphrase = LIBSSH_PASSPHRASE; + const char *passphrase = torture_get_testkey_passphrase(); (void) state; /* unused */ - key_str = read_file(LIBSSH_RSA_TESTKEY); - assert_true(key_str != NULL); - rc = ssh_pki_import_privkey_base64(key_str, passphrase, NULL, NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_RSA, 0, 1), + passphrase, + NULL, + NULL, + &key); assert_true(rc == 0); ssh_key_free(key); /* test if it returns -1 if passphrase is wrong */ - rc = ssh_pki_import_privkey_base64(key_str, "wrong passphrase !!", NULL, - NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_RSA, 0, 1), + "wrong passphrase !!", + NULL, + NULL, + &key); assert_true(rc == -1); #ifndef HAVE_LIBCRYPTO /* test if it returns -1 if passphrase is NULL */ /* libcrypto asks for a passphrase, so skip this test */ - rc = ssh_pki_import_privkey_base64(key_str, NULL, NULL, NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_RSA, 0, 1), + NULL, + NULL, + NULL, + &key); assert_true(rc == -1); #endif - free(key_str); - /* same for DSA */ - key_str = read_file(LIBSSH_DSA_TESTKEY); - assert_true(key_str != NULL); - rc = ssh_pki_import_privkey_base64(key_str, passphrase, NULL, NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1), + passphrase, + NULL, + NULL, + &key); assert_true(rc == 0); ssh_key_free(key); /* test if it returns -1 if passphrase is wrong */ - rc = ssh_pki_import_privkey_base64(key_str, "wrong passphrase !!", NULL, NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1), + "wrong passphrase !!", + NULL, + NULL, + &key); assert_true(rc == -1); #ifndef HAVE_LIBCRYPTO /* test if it returns -1 if passphrase is NULL */ /* libcrypto asks for a passphrase, so skip this test */ - rc = ssh_pki_import_privkey_base64(key_str, NULL, NULL, NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1), + NULL, + NULL, + NULL, + &key); assert_true(rc == -1); #endif - free(key_str); } static void torture_pki_pki_publickey_from_privatekey_RSA(void **state) { int rc; - char *key_str; ssh_key key; ssh_key pubkey; const char *passphrase = NULL; (void) state; /* unused */ - key_str = read_file(LIBSSH_RSA_TESTKEY); - assert_true(key_str != NULL); - - rc = ssh_pki_import_privkey_base64(key_str, passphrase, NULL, NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_RSA, 0, 0), + passphrase, + NULL, + NULL, + &key); assert_true(rc == 0); rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey); assert_true(rc == SSH_OK); - free(key_str); ssh_key_free(key); ssh_key_free(pubkey); } static void torture_pki_pki_publickey_from_privatekey_DSA(void **state) { int rc; - char *key_str; ssh_key key; ssh_key pubkey; const char *passphrase = NULL; (void) state; /* unused */ - key_str = read_file(LIBSSH_DSA_TESTKEY); - assert_true(key_str != NULL); - - rc = ssh_pki_import_privkey_base64(key_str, passphrase, NULL, NULL, &key); + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0), + passphrase, + NULL, + NULL, + &key); assert_true(rc == 0); rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey); assert_true(rc == SSH_OK); - free(key_str); ssh_key_free(key); ssh_key_free(pubkey); } @@ -399,7 +417,7 @@ static void torture_pki_publickey_dsa_base64(void **state) (void) state; /* unused */ - key_buf = read_file(LIBSSH_DSA_TESTKEY ".pub"); + key_buf = strdup(torture_get_testkey_pub(SSH_KEYTYPE_DSS, 0)); assert_true(key_buf != NULL); q = p = key_buf; @@ -475,7 +493,7 @@ static void torture_pki_publickey_rsa_base64(void **state) (void) state; /* unused */ - key_buf = read_file(LIBSSH_RSA_TESTKEY ".pub"); + key_buf = strdup(torture_get_testkey_pub(SSH_KEYTYPE_RSA, 0)); assert_true(key_buf != NULL); q = p = key_buf; @@ -504,19 +522,14 @@ static void torture_pki_publickey_rsa_base64(void **state) } static void torture_generate_pubkey_from_privkey_rsa(void **state) { - char pubkey_original[4096] = {0}; char pubkey_generated[4096] = {0}; ssh_key privkey; ssh_key pubkey; int rc; + int len; (void) state; /* unused */ - rc = torture_read_one_line(LIBSSH_RSA_TESTKEY ".pub", - pubkey_original, - sizeof(pubkey_original)); - assert_true(rc == 0); - /* remove the public key, generate it from the private key and write it. */ unlink(LIBSSH_RSA_TESTKEY ".pub"); @@ -538,26 +551,24 @@ static void torture_generate_pubkey_from_privkey_rsa(void **state) { sizeof(pubkey_generated)); assert_true(rc == 0); - assert_string_equal(pubkey_original, pubkey_generated); + len = torture_pubkey_len(torture_get_testkey_pub(SSH_KEYTYPE_RSA, 0)); + assert_memory_equal(torture_get_testkey_pub(SSH_KEYTYPE_RSA, 0), + pubkey_generated, + len); ssh_key_free(privkey); ssh_key_free(pubkey); } static void torture_generate_pubkey_from_privkey_dsa(void **state) { - char pubkey_original[4096] = {0}; char pubkey_generated[4096] = {0}; ssh_key privkey; ssh_key pubkey; + int len; int rc; (void) state; /* unused */ - rc = torture_read_one_line(LIBSSH_DSA_TESTKEY ".pub", - pubkey_original, - sizeof(pubkey_original)); - assert_true(rc == 0); - /* remove the public key, generate it from the private key and write it. */ unlink(LIBSSH_DSA_TESTKEY ".pub"); @@ -579,7 +590,10 @@ static void torture_generate_pubkey_from_privkey_dsa(void **state) { sizeof(pubkey_generated)); assert_true(rc == 0); - assert_string_equal(pubkey_original, pubkey_generated); + len = torture_pubkey_len(torture_get_testkey_pub(SSH_KEYTYPE_DSS, 0)); + assert_memory_equal(torture_get_testkey_pub(SSH_KEYTYPE_DSS, 0), + pubkey_generated, + len); ssh_key_free(privkey); ssh_key_free(pubkey); @@ -592,6 +606,7 @@ static void torture_generate_pubkey_from_privkey_ecdsa(void **state) { ssh_key privkey; ssh_key pubkey; int rc; + int len; (void) state; /* unused */ @@ -620,8 +635,8 @@ static void torture_generate_pubkey_from_privkey_ecdsa(void **state) { pubkey_generated, sizeof(pubkey_generated)); assert_true(rc == 0); - - assert_string_equal(pubkey_original, pubkey_generated); + len = torture_pubkey_len(pubkey_original); + assert_int_equal(strncmp(pubkey_original, pubkey_generated, len), 0); ssh_key_free(privkey); ssh_key_free(pubkey); @@ -766,6 +781,39 @@ static void torture_pki_duplicate_key_ecdsa(void **state) ssh_string_free_char(b64_key); ssh_string_free_char(b64_key_gen); } + +/* Test case for bug #147: Private ECDSA key duplication did not carry + * over parts of the key that then caused subsequent key demotion to + * fail. + */ +static void torture_pki_ecdsa_duplicate_then_demote(void **state) +{ + ssh_key pubkey; + ssh_key privkey; + ssh_key privkey_dup; + int rc; + + (void) state; + + rc = ssh_pki_import_privkey_file(LIBSSH_ECDSA_TESTKEY, + NULL, + NULL, + NULL, + &privkey); + assert_true(rc == 0); + + privkey_dup = ssh_key_dup(privkey); + assert_true(privkey_dup != NULL); + assert_int_equal(privkey->ecdsa_nid, privkey_dup->ecdsa_nid); + + rc = ssh_pki_export_privkey_to_pubkey(privkey_dup, &pubkey); + assert_true(rc == 0); + assert_int_equal(pubkey->ecdsa_nid, privkey->ecdsa_nid); + + ssh_key_free(pubkey); + ssh_key_free(privkey); + ssh_key_free(privkey_dup); +} #endif static void torture_pki_generate_key_rsa(void **state) @@ -906,6 +954,9 @@ static void torture_pki_generate_key_ecdsa(void **state) int rc; ssh_key key; ssh_signature sign; + enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN; + const char *type_char = NULL; + const char *etype_char = NULL; ssh_session session=ssh_new(); (void) state; @@ -916,6 +967,13 @@ static void torture_pki_generate_key_ecdsa(void **state) assert_true(sign != NULL); rc = pki_signature_verify(session,sign,key,HASH,20); assert_true(rc == SSH_OK); + type = ssh_key_type(key); + assert_true(type == SSH_KEYTYPE_ECDSA); + type_char = ssh_key_type_to_char(type); + assert_true(strcmp(type_char, "ssh-ecdsa") == 0); + etype_char = ssh_pki_key_ecdsa_name(key); + assert_true(strcmp(etype_char, "ecdsa-sha2-nistp256") == 0); + ssh_signature_free(sign); ssh_key_free(key); key=NULL; @@ -927,6 +985,13 @@ static void torture_pki_generate_key_ecdsa(void **state) assert_true(sign != NULL); rc = pki_signature_verify(session,sign,key,HASH,20); assert_true(rc == SSH_OK); + type = ssh_key_type(key); + assert_true(type == SSH_KEYTYPE_ECDSA); + type_char = ssh_key_type_to_char(type); + assert_true(strcmp(type_char, "ssh-ecdsa") == 0); + etype_char =ssh_pki_key_ecdsa_name(key); + assert_true(strcmp(etype_char, "ecdsa-sha2-nistp384") == 0); + ssh_signature_free(sign); ssh_key_free(key); key=NULL; @@ -938,6 +1003,13 @@ static void torture_pki_generate_key_ecdsa(void **state) assert_true(sign != NULL); rc = pki_signature_verify(session,sign,key,HASH,20); assert_true(rc == SSH_OK); + type = ssh_key_type(key); + assert_true(type == SSH_KEYTYPE_ECDSA); + type_char = ssh_key_type_to_char(type); + assert_true(strcmp(type_char, "ssh-ecdsa") == 0); + etype_char =ssh_pki_key_ecdsa_name(key); + assert_true(strcmp(etype_char, "ecdsa-sha2-nistp521") == 0); + ssh_signature_free(sign); ssh_key_free(key); key=NULL; @@ -946,6 +1018,166 @@ static void torture_pki_generate_key_ecdsa(void **state) } #endif +#ifdef HAVE_LIBCRYPTO +static void torture_pki_write_privkey_rsa(void **state) +{ + ssh_key origkey; + ssh_key privkey; + int rc; + + (void) state; /* unused */ + + ssh_set_log_level(5); + + rc = ssh_pki_import_privkey_file(LIBSSH_RSA_TESTKEY, + NULL, + NULL, + NULL, + &origkey); + assert_true(rc == 0); + + unlink(LIBSSH_RSA_TESTKEY); + + rc = ssh_pki_export_privkey_file(origkey, + "", + NULL, + NULL, + LIBSSH_RSA_TESTKEY); + assert_true(rc == 0); + + rc = ssh_pki_import_privkey_file(LIBSSH_RSA_TESTKEY, + NULL, + NULL, + NULL, + &privkey); + assert_true(rc == 0); + + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + + ssh_key_free(origkey); + ssh_key_free(privkey); +} + +static void torture_pki_write_privkey_dsa(void **state) +{ + ssh_key origkey; + ssh_key privkey; + int rc; + + (void) state; /* unused */ + + ssh_set_log_level(5); + + rc = ssh_pki_import_privkey_file(LIBSSH_DSA_TESTKEY, + NULL, + NULL, + NULL, + &origkey); + assert_true(rc == 0); + + unlink(LIBSSH_DSA_TESTKEY); + + rc = ssh_pki_export_privkey_file(origkey, + "", + NULL, + NULL, + LIBSSH_DSA_TESTKEY); + assert_true(rc == 0); + + rc = ssh_pki_import_privkey_file(LIBSSH_DSA_TESTKEY, + NULL, + NULL, + NULL, + &privkey); + assert_true(rc == 0); + + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + + ssh_key_free(origkey); + ssh_key_free(privkey); +} + +#ifdef HAVE_ECC +static void torture_pki_write_privkey_ecdsa(void **state) +{ + ssh_key origkey; + ssh_key privkey; + int rc; + + (void) state; /* unused */ + + ssh_set_log_level(5); + + rc = ssh_pki_import_privkey_file(LIBSSH_ECDSA_TESTKEY, + NULL, + NULL, + NULL, + &origkey); + assert_true(rc == 0); + + unlink(LIBSSH_ECDSA_TESTKEY); + + rc = ssh_pki_export_privkey_file(origkey, + "", + NULL, + NULL, + LIBSSH_ECDSA_TESTKEY); + assert_true(rc == 0); + + rc = ssh_pki_import_privkey_file(LIBSSH_ECDSA_TESTKEY, + NULL, + NULL, + NULL, + &privkey); + assert_true(rc == 0); + + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + + ssh_key_free(origkey); + ssh_key_free(privkey); +} +#endif +#endif /* HAVE_LIBCRYPTO */ + +#ifdef HAVE_ECC +static void torture_pki_ecdsa_name(void **state, const char *expected_name) +{ + int rc; + ssh_key key; + const char *etype_char = NULL; + + (void) state; /* unused */ + + ssh_set_log_level(5); + + rc = ssh_pki_import_privkey_file(LIBSSH_ECDSA_TESTKEY, NULL, NULL, NULL, &key); + assert_true(rc == 0); + + etype_char =ssh_pki_key_ecdsa_name(key); + assert_true(strcmp(etype_char, expected_name) == 0); + + ssh_key_free(key); +} + +static void torture_pki_ecdsa_name256(void **state) +{ + torture_pki_ecdsa_name(state, "ecdsa-sha2-nistp256"); +} + +static void torture_pki_ecdsa_name384(void **state) +{ + torture_pki_ecdsa_name(state, "ecdsa-sha2-nistp384"); +} + +static void torture_pki_ecdsa_name521(void **state) +{ + torture_pki_ecdsa_name(state, "ecdsa-sha2-nistp521"); +} +#endif + int torture_run_tests(void) { int rc; const UnitTest tests[] = { @@ -968,12 +1200,16 @@ int torture_run_tests(void) { teardown), #ifdef HAVE_ECC unit_test_setup_teardown(torture_pki_import_privkey_base64_ECDSA, - setup_ecdsa_key, + setup_ecdsa_key_256, + teardown), + unit_test_setup_teardown(torture_pki_import_privkey_base64_ECDSA, + setup_ecdsa_key_384, + teardown), + unit_test_setup_teardown(torture_pki_import_privkey_base64_ECDSA, + setup_ecdsa_key_521, teardown), #endif - unit_test_setup_teardown(torture_pki_import_privkey_base64_passphrase, - setup_both_keys_passphrase, - teardown), + unit_test(torture_pki_import_privkey_base64_passphrase), /* ssh_pki_export_privkey_to_pubkey */ unit_test_setup_teardown(torture_pki_pki_publickey_from_privatekey_RSA, setup_rsa_key, @@ -983,7 +1219,22 @@ int torture_run_tests(void) { teardown), #ifdef HAVE_ECC unit_test_setup_teardown(torture_pki_publickey_from_privatekey_ECDSA, - setup_ecdsa_key, + setup_ecdsa_key_256, + teardown), + unit_test_setup_teardown(torture_pki_publickey_from_privatekey_ECDSA, + setup_ecdsa_key_384, + teardown), + unit_test_setup_teardown(torture_pki_publickey_from_privatekey_ECDSA, + setup_ecdsa_key_521, + teardown), + unit_test_setup_teardown(torture_pki_ecdsa_duplicate_then_demote, + setup_ecdsa_key_256, + teardown), + unit_test_setup_teardown(torture_pki_ecdsa_duplicate_then_demote, + setup_ecdsa_key_384, + teardown), + unit_test_setup_teardown(torture_pki_ecdsa_duplicate_then_demote, + setup_ecdsa_key_521, teardown), #endif /* public key */ @@ -995,7 +1246,13 @@ int torture_run_tests(void) { teardown), #ifdef HAVE_ECC unit_test_setup_teardown(torture_pki_publickey_ecdsa_base64, - setup_ecdsa_key, + setup_ecdsa_key_256, + teardown), + unit_test_setup_teardown(torture_pki_publickey_ecdsa_base64, + setup_ecdsa_key_384, + teardown), + unit_test_setup_teardown(torture_pki_publickey_ecdsa_base64, + setup_ecdsa_key_521, teardown), #endif @@ -1007,7 +1264,13 @@ int torture_run_tests(void) { teardown), #ifdef HAVE_ECC unit_test_setup_teardown(torture_generate_pubkey_from_privkey_ecdsa, - setup_ecdsa_key, + setup_ecdsa_key_256, + teardown), + unit_test_setup_teardown(torture_generate_pubkey_from_privkey_ecdsa, + setup_ecdsa_key_384, + teardown), + unit_test_setup_teardown(torture_generate_pubkey_from_privkey_ecdsa, + setup_ecdsa_key_521, teardown), #endif @@ -1019,7 +1282,13 @@ int torture_run_tests(void) { teardown), #ifdef HAVE_ECC unit_test_setup_teardown(torture_pki_duplicate_key_ecdsa, - setup_ecdsa_key, + setup_ecdsa_key_256, + teardown), + unit_test_setup_teardown(torture_pki_duplicate_key_ecdsa, + setup_ecdsa_key_384, + teardown), + unit_test_setup_teardown(torture_pki_duplicate_key_ecdsa, + setup_ecdsa_key_521, teardown), #endif unit_test(torture_pki_generate_key_rsa), @@ -1027,6 +1296,36 @@ int torture_run_tests(void) { unit_test(torture_pki_generate_key_dsa), #ifdef HAVE_ECC unit_test(torture_pki_generate_key_ecdsa), +#endif +#ifdef HAVE_LIBCRYPTO + unit_test_setup_teardown(torture_pki_write_privkey_rsa, + setup_rsa_key, + teardown), + unit_test_setup_teardown(torture_pki_write_privkey_dsa, + setup_dsa_key, + teardown), +#ifdef HAVE_ECC + unit_test_setup_teardown(torture_pki_write_privkey_ecdsa, + setup_ecdsa_key_256, + teardown), + unit_test_setup_teardown(torture_pki_write_privkey_ecdsa, + setup_ecdsa_key_384, + teardown), + unit_test_setup_teardown(torture_pki_write_privkey_ecdsa, + setup_ecdsa_key_521, + teardown), +#endif +#endif /* HAVE_LIBCRYPTO */ +#ifdef HAVE_ECC + unit_test_setup_teardown(torture_pki_ecdsa_name256, + setup_ecdsa_key_256, + teardown), + unit_test_setup_teardown(torture_pki_ecdsa_name384, + setup_ecdsa_key_384, + teardown), + unit_test_setup_teardown(torture_pki_ecdsa_name521, + setup_ecdsa_key_521, + teardown), #endif };