mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
Compare commits
122 Commits
0b4b71cc11
...
libssh-0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
301d0e16df | ||
|
|
c182a21e11 | ||
|
|
3a28fbe5c6 | ||
|
|
65f363c9e3 | ||
|
|
1c763e29d1 | ||
|
|
7d85085d2a | ||
|
|
8e4d67aa9e | ||
|
|
266174a6d3 | ||
|
|
87db2659ec | ||
|
|
0fad4e6307 | ||
|
|
02cbd41b92 | ||
|
|
750693d10b | ||
|
|
56953f8aab | ||
|
|
0f1723b5c7 | ||
|
|
f1998d6064 | ||
|
|
d0ef7afdfa | ||
|
|
6e459f5756 | ||
|
|
51746e51f0 | ||
|
|
e7ef3f2962 | ||
|
|
b8d92bbcc7 | ||
|
|
f2aaee53df | ||
|
|
b026b24b55 | ||
|
|
028859ce99 | ||
|
|
d64f06f98a | ||
|
|
b298a04f96 | ||
|
|
962012bbf6 | ||
|
|
abfc42fad3 | ||
|
|
1ad67bd66e | ||
|
|
f553a6740a | ||
|
|
bac5d3f10a | ||
|
|
c8c3d418ee | ||
|
|
33be8038fe | ||
|
|
dff6c0821e | ||
|
|
82175044dc | ||
|
|
8559f59404 | ||
|
|
160fc7df10 | ||
|
|
a9d8a3d448 | ||
|
|
f13b91c2d8 | ||
|
|
90b4845e0c | ||
|
|
6ddb730a27 | ||
|
|
b35ee876ad | ||
|
|
697650caa9 | ||
|
|
5504ff4051 | ||
|
|
f79ec51b7f | ||
|
|
78485f446a | ||
|
|
3443aec901 | ||
|
|
261612179f | ||
|
|
5f4ffda887 | ||
|
|
6fd9cc8ce3 | ||
|
|
b595cc7ada | ||
|
|
d044b79de0 | ||
|
|
827c24055f | ||
|
|
1eff5d68f4 | ||
|
|
e4ede51d87 | ||
|
|
991b4422bd | ||
|
|
1a2c46781c | ||
|
|
65699380cf | ||
|
|
52e648c7f1 | ||
|
|
66314eeb71 | ||
|
|
573e0e48dc | ||
|
|
a2bb9b5d0c | ||
|
|
0de97c48d0 | ||
|
|
eeb498c0e3 | ||
|
|
715855d888 | ||
|
|
38004ecf94 | ||
|
|
edb1b8ba2c | ||
|
|
1e9e37580f | ||
|
|
8b5b785e0c | ||
|
|
d245706678 | ||
|
|
5911d058f1 | ||
|
|
3daa06dba7 | ||
|
|
45888d65ba | ||
|
|
33a73594e6 | ||
|
|
9cdcd16e82 | ||
|
|
12077f7294 | ||
|
|
f067d9e0d3 | ||
|
|
ec753057a5 | ||
|
|
39aefd479f | ||
|
|
2e5b6beec7 | ||
|
|
11c16531f0 | ||
|
|
69ee0062d7 | ||
|
|
13c69821dd | ||
|
|
543c730691 | ||
|
|
97bda86d41 | ||
|
|
77c9498dbe | ||
|
|
404452728d | ||
|
|
e111a63acb | ||
|
|
054682e72d | ||
|
|
5bff8b5dc6 | ||
|
|
758fbdd31b | ||
|
|
5c0add44e7 | ||
|
|
9f4e7eb06b | ||
|
|
1d157c57a3 | ||
|
|
7d35d25297 | ||
|
|
4119ad0fd8 | ||
|
|
771dc30f79 | ||
|
|
747dd17e64 | ||
|
|
093431f929 | ||
|
|
854795c654 | ||
|
|
da064c9a18 | ||
|
|
c85dc05436 | ||
|
|
8d0d3d4d7b | ||
|
|
0b2e13bc9b | ||
|
|
51f4a5743d | ||
|
|
e816256333 | ||
|
|
960a6d1cdd | ||
|
|
1fa9ea7f43 | ||
|
|
afa77c11ca | ||
|
|
825de355d4 | ||
|
|
a910526e10 | ||
|
|
dfc3cb7112 | ||
|
|
3264d3e83c | ||
|
|
6030d2fcd5 | ||
|
|
406a014d58 | ||
|
|
af0153f30f | ||
|
|
84dde6d302 | ||
|
|
dd38f523e1 | ||
|
|
5318ddaabc | ||
|
|
2f50ef2fe6 | ||
|
|
eae3a60ef8 | ||
|
|
318f675ef8 | ||
|
|
7beb580aab |
@@ -26,4 +26,3 @@ BreakAfterReturnType: ExceptShortType
|
||||
AlwaysBreakAfterReturnType: AllDefinitions
|
||||
AlignEscapedNewlines: Left
|
||||
ForEachMacros: ['ssh_callbacks_iterate']
|
||||
AlignConsecutiveMacros: 'Consecutive'
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,4 +10,3 @@ tags
|
||||
/build
|
||||
/obj*
|
||||
doc/tags.xml
|
||||
.DS_Store
|
||||
|
||||
139
.gitlab-ci.yml
139
.gitlab-ci.yml
@@ -27,17 +27,13 @@ workflow:
|
||||
when: never
|
||||
- if: '$CI_COMMIT_BRANCH'
|
||||
|
||||
.build_options:
|
||||
.build:
|
||||
stage: build
|
||||
variables:
|
||||
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
|
||||
CMAKE_DEFAULT_DEBUG_OPTIONS: "-DCMAKE_C_FLAGS='-O0 -g -ggdb' -DPICKY_DEVELOPER=ON"
|
||||
CMAKE_BUILD_OPTIONS: "-DWITH_BLOWFISH_CIPHER=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON"
|
||||
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DGSSAPI_TESTING=ON -DWITH_BENCHMARKS=ON -DFUZZ_TESTING=ON"
|
||||
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
|
||||
|
||||
.build:
|
||||
extends: .build_options
|
||||
stage: build
|
||||
before_script: &build
|
||||
- uname -a
|
||||
- cat /etc/os-release
|
||||
@@ -125,7 +121,7 @@ review:
|
||||
###############################################################################
|
||||
# CentOS builds #
|
||||
###############################################################################
|
||||
centos10s/openssl_3.2.x/x86_64:
|
||||
centos10s/openssl_3.5.x/x86_64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
|
||||
extends: .tests
|
||||
variables:
|
||||
@@ -136,7 +132,7 @@ centos10s/openssl_3.2.x/x86_64:
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
|
||||
centos10s/openssl_3.2.x/x86_64/fips:
|
||||
centos10s/openssl_3.5.x/x86_64/fips:
|
||||
extends: .fips
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
|
||||
variables:
|
||||
@@ -147,7 +143,7 @@ centos10s/openssl_3.2.x/x86_64/fips:
|
||||
make -j$(nproc) &&
|
||||
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
|
||||
|
||||
centos9s/openssl_3.x/x86_64:
|
||||
centos9s/openssl_3.5.x/x86_64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||
extends: .tests
|
||||
variables:
|
||||
@@ -164,7 +160,7 @@ centos9s/mbedtls_2.x/x86_64:
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF"
|
||||
|
||||
centos9s/openssl_3.x/x86_64/fips:
|
||||
centos9s/openssl_3.5.x/x86_64/fips:
|
||||
extends: .fips
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||
script:
|
||||
@@ -229,15 +225,15 @@ fedora/coverage:
|
||||
coverage_format: cobertura
|
||||
path: obj/coverage_xml.xml
|
||||
|
||||
fedora/openssl_3.x/x86_64:
|
||||
fedora/openssl_3.0.x/x86_64:
|
||||
extends: .fedora
|
||||
|
||||
fedora/openssl_3.x/x86_64/pkcs11-provider:
|
||||
fedora/openssl_3.0.x/x86_64/pkcs11-provider:
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||
extends: .fedora
|
||||
|
||||
fedora/openssl_3.x/x86_64/minimal:
|
||||
fedora/openssl_3.0.x/x86_64/minimal:
|
||||
extends: .fedora
|
||||
variables:
|
||||
script:
|
||||
@@ -409,7 +405,7 @@ fedora/mingw32:
|
||||
paths:
|
||||
- obj-csbuild/
|
||||
|
||||
fedora/csbuild/openssl_3.x:
|
||||
fedora/csbuild/openssl_3.0.x:
|
||||
extends: .csbuild
|
||||
script:
|
||||
- csbuild
|
||||
@@ -439,62 +435,6 @@ fedora/csbuild/mbedtls:
|
||||
--color
|
||||
--print-current --print-fixed
|
||||
|
||||
###############################################################################
|
||||
# Fedora abidiff #
|
||||
###############################################################################
|
||||
|
||||
fedora/abidiff:
|
||||
stage: analysis
|
||||
variables:
|
||||
GIT_DEPTH: "100"
|
||||
CMAKE_OPTIONS: $CMAKE_DEFAULT_DEBUG_OPTIONS $CMAKE_BUILD_OPTIONS
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
before_script:
|
||||
- uname -a
|
||||
- cat /etc/os-release
|
||||
- mount
|
||||
- df -h
|
||||
- cat /proc/swaps
|
||||
- free -h
|
||||
- |
|
||||
# for merge requests
|
||||
if [[ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]]; then
|
||||
export CI_COMMIT_BEFORE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
|
||||
fi
|
||||
# for branches run
|
||||
if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then
|
||||
export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
||||
fi
|
||||
|
||||
# Check if the commit exists in this branch
|
||||
# This is not the case for a force push
|
||||
git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
|
||||
|
||||
- mkdir -p obj-${CI_COMMIT_BEFORE_SHA}
|
||||
- mkdir -p obj-${CI_COMMIT_SHA}
|
||||
|
||||
- export INSTALL_DIR1=$(pwd)/install/${CI_COMMIT_BEFORE_SHA}
|
||||
- export INSTALL_DIR2=$(pwd)/install/${CI_COMMIT_SHA}
|
||||
script:
|
||||
- git checkout ${CI_COMMIT_BEFORE_SHA}
|
||||
- pushd obj-${CI_COMMIT_BEFORE_SHA}
|
||||
- cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR1} .. &&
|
||||
make -j$(nproc) && make -j$(nproc) install
|
||||
- popd
|
||||
- ls -l ${INSTALL_DIR1}/lib*/
|
||||
- git checkout ${CI_COMMIT_SHA}
|
||||
- pushd obj-${CI_COMMIT_SHA}
|
||||
- cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR2} .. &&
|
||||
make -j$(nproc) && make -j$(nproc) install
|
||||
- popd
|
||||
- ls -l ${INSTALL_DIR2}/lib*/
|
||||
- ./.gitlab-ci/checkabi.sh ${INSTALL_DIR1} ${INSTALL_DIR2}
|
||||
tags:
|
||||
- saas-linux-small-amd64
|
||||
except:
|
||||
- tags
|
||||
only:
|
||||
- merge_requests
|
||||
|
||||
###############################################################################
|
||||
# Ubuntu builds #
|
||||
@@ -507,7 +447,7 @@ ubuntu/openssl_3.0.x/x86_64:
|
||||
###############################################################################
|
||||
# Alpine builds #
|
||||
###############################################################################
|
||||
alpine/openssl_3.x/musl:
|
||||
alpine/openssl_3.0.x/musl:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$ALPINE_BUILD
|
||||
extends: .tests
|
||||
script:
|
||||
@@ -524,10 +464,10 @@ alpine/openssl_3.x/musl:
|
||||
###############################################################################
|
||||
# Tumbleweed builds #
|
||||
###############################################################################
|
||||
tumbleweed/openssl_3.x/x86_64/gcc:
|
||||
tumbleweed/openssl_3.0.x/x86_64/gcc:
|
||||
extends: .tumbleweed
|
||||
|
||||
tumbleweed/openssl_3.x/x86/gcc:
|
||||
tumbleweed/openssl_3.0.x/x86/gcc:
|
||||
extends: .tumbleweed
|
||||
script:
|
||||
- cmake
|
||||
@@ -540,12 +480,12 @@ tumbleweed/openssl_3.x/x86/gcc:
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc)
|
||||
|
||||
tumbleweed/openssl_3.x/x86_64/gcc7:
|
||||
tumbleweed/openssl_3.0.x/x86_64/gcc7:
|
||||
extends: .tumbleweed
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7"
|
||||
|
||||
tumbleweed/openssl_3.x/x86/gcc7:
|
||||
tumbleweed/openssl_3.0.x/x86/gcc7:
|
||||
extends: .tumbleweed
|
||||
script:
|
||||
- cmake
|
||||
@@ -557,7 +497,7 @@ tumbleweed/openssl_3.x/x86/gcc7:
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
|
||||
tumbleweed/openssl_3.x/x86_64/clang:
|
||||
tumbleweed/openssl_3.0.x/x86_64/clang:
|
||||
extends: .tumbleweed
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
|
||||
@@ -567,11 +507,6 @@ tumbleweed/mbedtls-3.6.x/x86_64/gcc:
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: "-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
|
||||
|
||||
tumbleweed/mbedtls-3.6.x/x86_64/clang:
|
||||
extends: .tumbleweed
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
|
||||
|
||||
tumbleweed/static-analysis:
|
||||
extends: .tests
|
||||
stage: analysis
|
||||
@@ -633,7 +568,9 @@ freebsd/openssl_1.1.1/x86_64:
|
||||
# 2024-05-13: These jobs run out of the stages as they take extremely long and
|
||||
# usually timeout with the update to Gitlab 17.0
|
||||
.vs:
|
||||
stage: test
|
||||
stage: analysis
|
||||
needs: []
|
||||
allow_failure: true
|
||||
cache:
|
||||
key: vcpkg.${CI_JOB_NAME}
|
||||
paths:
|
||||
@@ -725,41 +662,3 @@ coverity:
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/cov-int/*.txt
|
||||
|
||||
###############################################################################
|
||||
# MacOS #
|
||||
###############################################################################
|
||||
.macos:
|
||||
tags:
|
||||
- saas-macos-medium-m1
|
||||
image: macos-14-xcode-15
|
||||
before_script:
|
||||
- echo "MacOS runner started"
|
||||
- brew update
|
||||
- brew install cmake openssl cmocka doxygen
|
||||
- mkdir obj && cd obj
|
||||
only:
|
||||
- branches@libssh/libssh-mirror
|
||||
- branches@cryptomilk/libssh-mirror
|
||||
- branches@jjelen/libssh-mirror
|
||||
- branches@marco.fortina/libssh-mirror
|
||||
|
||||
# TODO add -DFUZZ_TESTING=ON clang cant find _LLVMFuzzerInitialize on arm64
|
||||
macos-m1:
|
||||
extends: .macos
|
||||
variables:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
|
||||
CMAKE_BUILD_OPTIONS: "-DWITH_BLOWFISH_CIPHER=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON"
|
||||
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON"
|
||||
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
|
||||
stage: test
|
||||
script:
|
||||
- cmake $CMAKE_OPTIONS .. &&
|
||||
make -j$(sysctl -n hw.logicalcpu) &&
|
||||
ctest --output-on-failure
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
INSTALL_DIR1=${1}
|
||||
INSTALL_DIR2=${2}
|
||||
|
||||
abidiff \
|
||||
--headers-dir1 "${INSTALL_DIR1}/include/libssh/" \
|
||||
--headers-dir2 "${INSTALL_DIR2}/include/libssh/" \
|
||||
"${INSTALL_DIR1}/lib64/libssh.so" \
|
||||
"${INSTALL_DIR2}/lib64/libssh.so" \
|
||||
--fail-no-debug-info
|
||||
abiret=$?
|
||||
|
||||
ABIDIFF_ERROR=$(((abiret & 0x01) != 0))
|
||||
ABIDIFF_USAGE_ERROR=$(((abiret & 0x02) != 0))
|
||||
ABIDIFF_ABI_CHANGE=$(((abiret & 0x04) != 0))
|
||||
ABIDIFF_ABI_INCOMPATIBLE_CHANGE=$(((abiret & 0x08) != 0))
|
||||
ABIDIFF_UNKNOWN_BIT_SET=$(((abiret & 0xf0) != 0))
|
||||
|
||||
if [ $ABIDIFF_ERROR -ne 0 ]; then
|
||||
echo "abidiff reported ABIDIFF_ERROR."
|
||||
exit 1
|
||||
fi
|
||||
if [ $ABIDIFF_USAGE_ERROR -ne 0 ]; then
|
||||
echo "abidiff reported ABIDIFF_USAGE_ERROR."
|
||||
exit 1
|
||||
fi
|
||||
if [ $ABIDIFF_UNKNOWN_BIT_SET -ne 0 ]; then
|
||||
echo "abidiff reported ABIDIFF_UNKNOWN_BIT_SET."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $ABIDIFF_ABI_INCOMPATIBLE_CHANGE -ne 0 ]; then
|
||||
echo "abidiff result ABIDIFF_ABI_INCOMPATIBLE_CHANGE, this breaks the API!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $ABIDIFF_ABI_CHANGE -ne 0 ]; then
|
||||
echo "Ignoring abidiff result ABI_CHANGE"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -1,16 +0,0 @@
|
||||
Add a description of the new feature/bug fix. Reference any relevant bugs.
|
||||
|
||||
## Checklist
|
||||
* [ ] Commits have `Signed-off-by:` with name/author being identical to the commit author
|
||||
* [ ] Code modified for feature
|
||||
* [ ] Test suite updated with functionality tests
|
||||
* [ ] Test suite updated with negative tests
|
||||
* [ ] Documentation updated
|
||||
* [ ] The project pipelines timeout is [extended](https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run) at least to 2 hours.
|
||||
|
||||
## Reviewer's checklist:
|
||||
* [ ] Any issues marked for closing are addressed
|
||||
* [ ] There is a test suite reasonably covering new functionality or modifications
|
||||
* [ ] Function naming, parameters, return values, types, etc., are consistent and according to [CONTRIBUTING.md](https://gitlab.com/libssh/libssh-mirror/-/blob/master/CONTRIBUTING.md)
|
||||
* [ ] This feature/change has adequate documentation added
|
||||
* [ ] No obvious mistakes in the code
|
||||
38
CHANGELOG
38
CHANGELOG
@@ -1,6 +1,44 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
version 0.11.3 (released 2025-09-09)
|
||||
* Security:
|
||||
* CVE-2025-8114: Fix NULL pointer dereference after allocation failure
|
||||
* CVE-2025-8277: Fix memory leak of ephemeral key pair during repeated wrong KEX
|
||||
* Potential UAF when send() fails during key exchange
|
||||
* Fix possible timeout during KEX if client sends authentication too early (#311)
|
||||
* Cleanup OpenSSL PKCS#11 provider when loaded
|
||||
* Zeroize buffers containing private key blobs during export
|
||||
|
||||
version 0.11.2 (released 2025-06-24)
|
||||
* Security:
|
||||
* CVE-2025-4877 - Write beyond bounds in binary to base64 conversion
|
||||
* CVE-2025-4878 - Use of uninitialized variable in privatekey_from_file()
|
||||
* CVE-2025-5318 - Likely read beyond bounds in sftp server handle management
|
||||
* CVE-2025-5351 - Double free in functions exporting keys
|
||||
* CVE-2025-5372 - ssh_kdf() returns a success code on certain failures
|
||||
* CVE-2025-5449 - Likely read beyond bounds in sftp server message decoding
|
||||
* CVE-2025-5987 - Invalid return code for chacha20 poly1305 with OpenSSL
|
||||
* Compatibility
|
||||
* Fixed compatibility with CPM.cmake
|
||||
* Compatibility with OpenSSH 10.0
|
||||
* Tests compatibility with new Dropbear releases
|
||||
* Removed p11-kit remoting from the pkcs11 testsuite
|
||||
* Bugfixes
|
||||
* Implement missing packet filter for DH GEX
|
||||
* Properly process the SSH2_MSG_DEBUG message
|
||||
* Allow escaping quotes in quoted arguments to ssh configuration
|
||||
* Do not fail with unknown match keywords in ssh configuration
|
||||
* Process packets before selecting signature algorithm during authentication
|
||||
* Do not fail hard when the SFTP status message is not sent by noncompliant
|
||||
servers
|
||||
|
||||
version 0.11.1 (released 2024-08-30)
|
||||
* Fixed default TTY modes that are set when stdin is not connected to tty (#270)
|
||||
* Fixed zlib cleanup procedure, which could crash on i386
|
||||
* Various test fixes improving their stability
|
||||
* Fixed cygwin build
|
||||
|
||||
version 0.11.0 (released 2024-07-31)
|
||||
* Deprecations and Removals:
|
||||
* Dropped support for DSA
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.12.0)
|
||||
cmake_minimum_required(VERSION 3.14.0)
|
||||
|
||||
# Specify search path for CMake modules to be loaded by include()
|
||||
# and find_package()
|
||||
@@ -9,7 +9,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
||||
include(DefineCMakeDefaults)
|
||||
include(DefineCompilerFlags)
|
||||
|
||||
project(libssh VERSION 0.11.00 LANGUAGES C)
|
||||
project(libssh VERSION 0.11.3 LANGUAGES C)
|
||||
|
||||
# global needed variable
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
@@ -21,7 +21,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
# Increment AGE. Set REVISION to 0
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.10.0")
|
||||
set(LIBRARY_VERSION "4.10.3")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
@@ -41,8 +41,6 @@ macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source buil
|
||||
# Copy library files to a lib sub-directory
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
|
||||
|
||||
set(LIBSSSH_PC_REQUIRES_PRIVATE "")
|
||||
|
||||
# search for libraries
|
||||
if (WITH_ZLIB)
|
||||
find_package(ZLIB REQUIRED)
|
||||
@@ -68,7 +66,6 @@ find_package(Threads)
|
||||
|
||||
if (WITH_GSSAPI)
|
||||
find_package(GSSAPI)
|
||||
list(APPEND LIBSSH_PC_REQUIRES_PRIVATE ${GSSAPI_PC_REQUIRES})
|
||||
endif (WITH_GSSAPI)
|
||||
|
||||
if (WITH_NACL)
|
||||
@@ -252,15 +249,9 @@ message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
|
||||
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
|
||||
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
|
||||
message(STATUS "Release is final: ${WITH_FINAL}")
|
||||
if (WITH_HERMETIC_USR)
|
||||
message(STATUS "User global client config: ${USR_GLOBAL_CLIENT_CONFIG}")
|
||||
endif ()
|
||||
message(STATUS "Global client config: ${GLOBAL_CLIENT_CONFIG}")
|
||||
if (WITH_SERVER)
|
||||
if (WITH_HERMETIC_USR)
|
||||
message(STATUS "User global bind config: ${USR_GLOBAL_BIND_CONFIG}")
|
||||
endif ()
|
||||
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
|
||||
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
|
||||
endif()
|
||||
message(STATUS "********************************************")
|
||||
|
||||
|
||||
@@ -117,25 +117,6 @@ libssh Developer's Certificate of Origin for each patch, or inside each
|
||||
patch. Just the sign-off message is all that is required once we've
|
||||
received the initial email.
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
Contributing patches through Merge Request workflow on Gitlab allows us to run
|
||||
various checks on various configuration as part of Gitlab CI. Unfortunately,
|
||||
some pipelines are slower (as they involve building dependencies) so the default
|
||||
timeout of 1 hour needs to be extended at least to 2 hours. This can be done in
|
||||
project settings of your libssh fork:
|
||||
|
||||
https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run
|
||||
|
||||
Otherwise you will encounter errors like these, usually on visualstudio builds:
|
||||
|
||||
```
|
||||
ERROR: Job failed: execution took longer than 1h0m0s seconds
|
||||
The script exceeded the maximum execution time set for the job
|
||||
```
|
||||
|
||||
Note, that the built dependencies are cached so after successful build in your
|
||||
namespace, the rebuilds should be much faster.
|
||||
|
||||
# Coding conventions in the libssh tree
|
||||
|
||||
@@ -536,37 +517,6 @@ Bad example:
|
||||
break;
|
||||
}
|
||||
|
||||
## ABI Versioning and Symbol Management
|
||||
|
||||
To maintain [ABI](https://en.wikipedia.org/wiki/Application_binary_interface) stability
|
||||
and ensure backward compatibility, libssh uses **symbol versioning** to track and manage
|
||||
exported functions and variables. This allows libssh to introduce new symbols or modify
|
||||
existing functions in an ABI-compatible way.
|
||||
|
||||
When introducing a new symbol:
|
||||
|
||||
1. Use the `LIBSSH_API` macro to mark the symbol as part of the public API.
|
||||
2. If you have [abimap](https://github.com/ansasaki/abimap) installed, the new symbols are
|
||||
automatically generated in the `src/libssh_dev.map` file in the **build** directory and used automatically for building the updated library. But, depending on the version of `abimap` under use, you may face linker errors like: `unable to find version dependency LIBSSH_4_9_0`. In this case, you need to manually replace the existing `src/libssh.map` file with the generated `libssh_dev.map` file to update the symbol versioning.
|
||||
3. If you do not have abimap installed, the modified/added symbols must manually be added to the
|
||||
`src/libssh.map` file. The symbols must be added in the following format (assuming that 4_10_0 is the latest released version):
|
||||
|
||||
```
|
||||
LIBSSH_AFTER_4_10_0
|
||||
{
|
||||
global:
|
||||
new_function;
|
||||
new_variable;
|
||||
} LIBSSH_4_10_0;
|
||||
```
|
||||
4. After following either of the above steps, the library can be successfully built and
|
||||
tested without any linker errors.
|
||||
|
||||
5. When submitting the patch, make sure that any new symbols have been added to `libssh.map` as described in step 3, so that the new additions may not be excluded from the next release due to human error.
|
||||
|
||||
Also, to maintain ABI compatibility, existing symbols must not be removed. Instead, they can
|
||||
be marked as deprecated using the `LIBSSH_DEPRECATED` macro. This allows the symbol to be
|
||||
removed in a future release without breaking the ABI.
|
||||
|
||||
Have fun and happy libssh hacking!
|
||||
|
||||
|
||||
@@ -226,7 +226,6 @@ if (GCRYPT_FOUND)
|
||||
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
|
||||
if (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
|
||||
set(HAVE_GCRYPT_CHACHA_POLY 1)
|
||||
set(HAVE_GCRYPT_CURVE25519 1)
|
||||
endif (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
|
||||
endif (GCRYPT_FOUND)
|
||||
|
||||
@@ -237,13 +236,6 @@ if (MBEDTLS_FOUND)
|
||||
set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls")
|
||||
check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H)
|
||||
check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H)
|
||||
if (MBEDTLS_VERSION VERSION_LESS "3.0.0")
|
||||
check_symbol_exists(MBEDTLS_ECP_DP_CURVE25519_ENABLED "config.h" HAVE_MBEDTLS_CURVE25519)
|
||||
else()
|
||||
check_symbol_exists(MBEDTLS_ECP_DP_CURVE25519_ENABLED "mbedtls_config.h" HAVE_MBEDTLS_CURVE25519)
|
||||
endif()
|
||||
|
||||
|
||||
if (WITH_BLOWFISH_CIPHER)
|
||||
check_include_file(blowfish.h HAVE_BLOWFISH)
|
||||
endif()
|
||||
|
||||
@@ -27,7 +27,6 @@ option(WITH_INSECURE_NONE "Enable insecure none cipher and MAC algorithms (not s
|
||||
option(WITH_EXEC "Enable libssh to execute arbitrary commands from configuration files or options (match exec, proxy commands and OpenSSH-based proxy-jumps)." ON)
|
||||
option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF)
|
||||
option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
|
||||
option(WITH_HERMETIC_USR "Build with support for hermetic /usr/" OFF)
|
||||
|
||||
if (WITH_ZLIB)
|
||||
set(WITH_LIBZ ON)
|
||||
@@ -60,11 +59,6 @@ if (NOT GLOBAL_CLIENT_CONFIG)
|
||||
set(GLOBAL_CLIENT_CONFIG "/etc/ssh/ssh_config")
|
||||
endif (NOT GLOBAL_CLIENT_CONFIG)
|
||||
|
||||
if (WITH_HERMETIC_USR)
|
||||
set(USR_GLOBAL_BIND_CONFIG "/usr${GLOBAL_BIND_CONFIG}")
|
||||
set(USR_GLOBAL_CLIENT_CONFIG "/usr${GLOBAL_CLIENT_CONFIG}")
|
||||
endif (WITH_HERMETIC_USR)
|
||||
|
||||
if (FUZZ_TESTING)
|
||||
set(WITH_INSECURE_NONE ON)
|
||||
endif (FUZZ_TESTING)
|
||||
|
||||
6
INSTALL
6
INSTALL
@@ -38,16 +38,14 @@ First, you need to configure the compilation, using CMake. Go inside the
|
||||
`build` dir. Create it if it doesn't exist.
|
||||
|
||||
GNU/Linux, MacOS X, MSYS/MinGW:
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
|
||||
|
||||
cmake -DUNIT_TESTING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
|
||||
make
|
||||
|
||||
On Windows you should choose a makefile generator with -G or use
|
||||
|
||||
cmake-gui.exe ..
|
||||
|
||||
To enable building tests use -DUNIT_TESTING=ON. For this, the
|
||||
[cmocka](https://cmocka.org) dependency is required.
|
||||
|
||||
To enable additional client tests against a local OpenSSH server, add the
|
||||
compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH
|
||||
server package and some wrapper libraries (see optional requirements) to
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
# GSSAPI_INCLUDE_DIR - the GSSAPI include directory
|
||||
# GSSAPI_LIBRARIES - Link these to use GSSAPI
|
||||
# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI
|
||||
# GSSAPI_PC_REQUIRES - pkg-config module name if found, needed for
|
||||
# Requires.private for static linking
|
||||
#
|
||||
#=============================================================================
|
||||
# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
|
||||
@@ -26,23 +24,12 @@
|
||||
#=============================================================================
|
||||
#
|
||||
|
||||
set(_mit_modname "mit-krb5-gssapi")
|
||||
set(_heimdal_modname "heimdal-gssapi")
|
||||
|
||||
if(NOT _GSSAPI_ROOT_HINTS AND NOT _GSSAPI_ROOT_PATHS)
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(_GSSAPI ${_mit_modname} ${_heimdal_modname})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_path(GSSAPI_ROOT_DIR
|
||||
NAMES
|
||||
include/gssapi.h
|
||||
include/gssapi/gssapi.h
|
||||
HINTS
|
||||
${_GSSAPI_ROOT_HINTS}
|
||||
"${_GSSAPI_INCLUDEDIR}"
|
||||
PATHS
|
||||
${_GSSAPI_ROOT_PATHS}
|
||||
)
|
||||
@@ -330,15 +317,9 @@ endif (GSSAPI_FLAVOR_HEIMDAL)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR)
|
||||
|
||||
if(GSSAPI_FOUND)
|
||||
if(_GSSAPI_FOUND) # via pkg-config
|
||||
if (GSSAPI_FLAVOR_MIT)
|
||||
set(GSSAPI_PC_REQUIRES ${_mit_modname})
|
||||
elseif (GSSAPI_FLAVOR_HEIMDAL)
|
||||
set(GSSAPI_PC_REQUIRES ${_heimdal_modname})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
|
||||
set(GSSAPI_FOUND TRUE)
|
||||
endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
|
||||
|
||||
# show the GSSAPI_INCLUDE_DIR and GSSAPI_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(GSSAPI_INCLUDE_DIR GSSAPI_LIBRARIES)
|
||||
# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES)
|
||||
|
||||
@@ -72,23 +72,21 @@ find_library(MBEDTLS_X509_LIBRARY
|
||||
set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
|
||||
${MBEDTLS_X509_LIBRARY})
|
||||
|
||||
# mbedtls 2.8
|
||||
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
|
||||
# mbedtls 2.8
|
||||
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
|
||||
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
|
||||
|
||||
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+\\.[0-9]+\\.[0-9]+).*$"
|
||||
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
|
||||
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
|
||||
endif()
|
||||
|
||||
# mbedtls 3.6
|
||||
if (NOT MBEDTLS_VERSION AND MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
|
||||
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h" _mbedtls_version_str REGEX
|
||||
elseif (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
|
||||
# mbedtls 3.6
|
||||
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
|
||||
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
|
||||
|
||||
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+\\.[0-9]+\\.[0-9]+).*$"
|
||||
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
|
||||
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
if (MBEDTLS_VERSION)
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
#cmakedefine SOURCEDIR "${SOURCEDIR}"
|
||||
|
||||
/* Global bind configuration file path */
|
||||
#cmakedefine USR_GLOBAL_BIND_CONFIG "${USR_GLOBAL_BIND_CONFIG}"
|
||||
#cmakedefine GLOBAL_BIND_CONFIG "${GLOBAL_BIND_CONFIG}"
|
||||
|
||||
/* Global client configuration file path */
|
||||
#cmakedefine USR_GLOBAL_CLIENT_CONFIG "${USR_GLOBAL_CLIENT_CONFIG}"
|
||||
#cmakedefine GLOBAL_CLIENT_CONFIG "${GLOBAL_CLIENT_CONFIG}"
|
||||
|
||||
/************************** HEADER FILES *************************/
|
||||
@@ -87,9 +85,6 @@
|
||||
/* Define to 1 if you have elliptic curve cryptography in openssl */
|
||||
#cmakedefine HAVE_OPENSSL_ECC 1
|
||||
|
||||
/* Define to 1 if mbedTLS supports curve25519 */
|
||||
#cmakedefine HAVE_MBEDTLS_CURVE25519 1
|
||||
|
||||
/* Define to 1 if you have elliptic curve cryptography in gcrypt */
|
||||
#cmakedefine HAVE_GCRYPT_ECC 1
|
||||
|
||||
@@ -102,9 +97,6 @@
|
||||
/* Define to 1 if you have gcrypt with ChaCha20/Poly1305 support */
|
||||
#cmakedefine HAVE_GCRYPT_CHACHA_POLY 1
|
||||
|
||||
/* Define to 1 if you have gcrypt with curve25519 support */
|
||||
#cmakedefine HAVE_GCRYPT_CURVE25519
|
||||
|
||||
/*************************** FUNCTIONS ***************************/
|
||||
|
||||
/* Define to 1 if you have the `EVP_chacha20' function. */
|
||||
|
||||
@@ -91,10 +91,4 @@ that it used:
|
||||
}
|
||||
@endcode
|
||||
|
||||
Warning: In a single channel, only ONE command can be executed!
|
||||
If you want to executed multiple commands, allocate separate channels for
|
||||
them or consider opening interactive shell.
|
||||
Attempting to run multiple consecutive commands in one channel will fail.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@ the interesting functions as you go.
|
||||
|
||||
The libssh library provides:
|
||||
|
||||
- <strong>Key Exchange Methods</strong>: <i>sntrup761x25519-sha512@openssh.com, curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
|
||||
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
|
||||
- <strong>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256
|
||||
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc
|
||||
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none
|
||||
|
||||
@@ -303,6 +303,7 @@ span.lineno {
|
||||
padding-right: 4px;
|
||||
text-align: right;
|
||||
color: black;
|
||||
height: 100px;
|
||||
white-space: pre;
|
||||
border-right: 3px solid #1d7567;
|
||||
background-color: #323232; }
|
||||
|
||||
@@ -66,6 +66,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
if ((p = strchr(buffer, '\n'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
@@ -74,7 +75,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memset(buffer, 0, strlen(buffer));
|
||||
} else {
|
||||
if (password && strstr(prompt, "Password:")) {
|
||||
answer = password;
|
||||
@@ -146,7 +147,7 @@ int authenticate_console(ssh_session session)
|
||||
|
||||
// Try to authenticate
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
error(session);
|
||||
return rc;
|
||||
}
|
||||
@@ -155,7 +156,7 @@ int authenticate_console(ssh_session session)
|
||||
while (rc != SSH_AUTH_SUCCESS) {
|
||||
if (method & SSH_AUTH_METHOD_GSSAPI_MIC){
|
||||
rc = ssh_userauth_gssapi(session);
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
if(rc == SSH_AUTH_ERROR) {
|
||||
error(session);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
@@ -165,7 +166,7 @@ int authenticate_console(ssh_session session)
|
||||
// Try to authenticate with public key first
|
||||
if (method & SSH_AUTH_METHOD_PUBLICKEY) {
|
||||
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
error(session);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
@@ -205,7 +206,7 @@ int authenticate_console(ssh_session session)
|
||||
// Try to authenticate with keyboard interactive";
|
||||
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||
rc = authenticate_kbdint(session, NULL);
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
error(session);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
@@ -220,7 +221,7 @@ int authenticate_console(ssh_session session)
|
||||
// Try to authenticate with password
|
||||
if (method & SSH_AUTH_METHOD_PASSWORD) {
|
||||
rc = ssh_userauth_password(session, NULL, password);
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
error(session);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
|
||||
@@ -21,50 +21,47 @@ clients must be made or how a client should react.
|
||||
#include "examples_common.h"
|
||||
#include <stdio.h>
|
||||
|
||||
ssh_session connect_ssh(const char *host, const char *user, int verbosity)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
int auth = 0;
|
||||
ssh_session connect_ssh(const char *host, const char *user,int verbosity){
|
||||
ssh_session session = NULL;
|
||||
int auth=0;
|
||||
|
||||
session = ssh_new();
|
||||
if (session == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
session=ssh_new();
|
||||
if (session == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (user != NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
if(user != NULL){
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
if (ssh_connect(session)) {
|
||||
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
if (verify_knownhost(session) < 0) {
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
auth = authenticate_console(session);
|
||||
if (auth == SSH_AUTH_SUCCESS) {
|
||||
return session;
|
||||
} else if (auth == SSH_AUTH_DENIED) {
|
||||
fprintf(stderr, "Authentication failed\n");
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error while authenticating : %s\n",
|
||||
ssh_get_error(session));
|
||||
}
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
if(verify_knownhost(session)<0){
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
auth=authenticate_console(session);
|
||||
if(auth==SSH_AUTH_SUCCESS){
|
||||
return session;
|
||||
} else if(auth==SSH_AUTH_DENIED){
|
||||
fprintf(stderr,"Authentication failed\n");
|
||||
} else {
|
||||
fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session));
|
||||
}
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ clients must be made or how a client should react.
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
/** Zero a structure */
|
||||
#define ZERO_STRUCT(x) memset(&(x), 0, sizeof(x))
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
|
||||
int authenticate_console(ssh_session session);
|
||||
int authenticate_kbdint(ssh_session session, const char *password);
|
||||
|
||||
@@ -350,12 +350,7 @@ int main(int argc, char *argv[])
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (arguments.file == NULL) {
|
||||
fprintf(stderr, "Error: Missing argument file\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (arguments.action_list) {
|
||||
if (arguments.action_list && arguments.file) {
|
||||
list_fingerprint(arguments.file);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -119,10 +119,6 @@ static struct location *parse_location(char *loc)
|
||||
struct location *location = NULL;
|
||||
char *ptr = NULL;
|
||||
|
||||
if (loc == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
location = malloc(sizeof(struct location));
|
||||
if (location == NULL) {
|
||||
return NULL;
|
||||
|
||||
@@ -32,163 +32,151 @@ static const char *createcommand =
|
||||
"cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
|
||||
static char *host = NULL;
|
||||
|
||||
static void usage(const char *argv0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage : %s [options] host\n"
|
||||
"sample tiny scp downloader client - libssh-%s\n"
|
||||
"This program will create files in /tmp and try to fetch them\n",
|
||||
argv0,
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
static void usage(const char *argv0){
|
||||
fprintf(stderr,"Usage : %s [options] host\n"
|
||||
"sample tiny scp downloader client - libssh-%s\n"
|
||||
"This program will create files in /tmp and try to fetch them\n",
|
||||
// "Options :\n",
|
||||
// " -r : use RSA to verify host public key\n",
|
||||
argv0,
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
while ((i = getopt(argc, argv, "v")) != -1) {
|
||||
switch (i) {
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown option %c\n", optopt);
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
host = argv[optind];
|
||||
if (host == NULL)
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
while((i=getopt(argc,argv,"v"))!=-1){
|
||||
switch(i){
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void create_files(ssh_session session)
|
||||
{
|
||||
ssh_channel channel = ssh_channel_new(session);
|
||||
char buffer[1];
|
||||
int rc;
|
||||
|
||||
if (channel == NULL) {
|
||||
fprintf(stderr, "Error creating channel: %s\n", ssh_get_error(session));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (ssh_channel_open_session(channel) != SSH_OK) {
|
||||
fprintf(stderr, "Error creating channel: %s\n", ssh_get_error(session));
|
||||
ssh_channel_free(channel);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (ssh_channel_request_exec(channel, createcommand) != SSH_OK) {
|
||||
fprintf(stderr,
|
||||
"Error executing command: %s\n",
|
||||
ssh_get_error(session));
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while (!ssh_channel_is_eof(channel)) {
|
||||
rc = ssh_channel_read(channel, buffer, 1, 1);
|
||||
if (rc != 1) {
|
||||
fprintf(stderr, "Error reading from channel\n");
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = write(1, buffer, 1);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Error writing to buffer\n");
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
static int fetch_files(ssh_session session)
|
||||
{
|
||||
int size;
|
||||
char buffer[BUF_SIZE];
|
||||
int mode;
|
||||
char *filename = NULL;
|
||||
int r;
|
||||
ssh_scp scp = ssh_scp_new(session,
|
||||
SSH_SCP_READ | SSH_SCP_RECURSIVE,
|
||||
"/tmp/libssh_tests/*");
|
||||
if (ssh_scp_init(scp) != SSH_OK) {
|
||||
fprintf(stderr, "error initializing scp: %s\n", ssh_get_error(session));
|
||||
ssh_scp_free(scp);
|
||||
return -1;
|
||||
}
|
||||
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
|
||||
do {
|
||||
r = ssh_scp_pull_request(scp);
|
||||
switch (r) {
|
||||
case SSH_SCP_REQUEST_NEWFILE:
|
||||
size = ssh_scp_request_get_size(scp);
|
||||
filename = strdup(ssh_scp_request_get_filename(scp));
|
||||
mode = ssh_scp_request_get_permissions(scp);
|
||||
printf("downloading file %s, size %d, perms 0%o\n",
|
||||
filename,
|
||||
size,
|
||||
mode);
|
||||
free(filename);
|
||||
ssh_scp_accept_request(scp);
|
||||
r = ssh_scp_read(scp, buffer, sizeof(buffer));
|
||||
if (r == SSH_ERROR) {
|
||||
fprintf(stderr,
|
||||
"Error reading scp: %s\n",
|
||||
ssh_get_error(session));
|
||||
ssh_scp_close(scp);
|
||||
ssh_scp_free(scp);
|
||||
return -1;
|
||||
}
|
||||
printf("done\n");
|
||||
break;
|
||||
case SSH_ERROR:
|
||||
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
|
||||
ssh_scp_close(scp);
|
||||
ssh_scp_free(scp);
|
||||
return -1;
|
||||
case SSH_SCP_REQUEST_WARNING:
|
||||
fprintf(stderr, "Warning: %s\n", ssh_scp_request_get_warning(scp));
|
||||
break;
|
||||
case SSH_SCP_REQUEST_NEWDIR:
|
||||
filename = strdup(ssh_scp_request_get_filename(scp));
|
||||
mode = ssh_scp_request_get_permissions(scp);
|
||||
printf("downloading directory %s, perms 0%o\n", filename, mode);
|
||||
free(filename);
|
||||
ssh_scp_accept_request(scp);
|
||||
break;
|
||||
case SSH_SCP_REQUEST_ENDDIR:
|
||||
printf("End of directory\n");
|
||||
break;
|
||||
case SSH_SCP_REQUEST_EOF:
|
||||
printf("End of requests\n");
|
||||
goto end;
|
||||
}
|
||||
} while (1);
|
||||
end:
|
||||
ssh_scp_close(scp);
|
||||
ssh_scp_free(scp);
|
||||
return 0;
|
||||
}
|
||||
host = argv[optind];
|
||||
if(host == NULL)
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
if (opts(argc, argv) < 0)
|
||||
return EXIT_FAILURE;
|
||||
session = connect_ssh(host, NULL, verbosity);
|
||||
if (session == NULL)
|
||||
return EXIT_FAILURE;
|
||||
create_files(session);
|
||||
fetch_files(session);
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
static void create_files(ssh_session session){
|
||||
ssh_channel channel=ssh_channel_new(session);
|
||||
char buffer[1];
|
||||
int rc;
|
||||
|
||||
if(channel == NULL){
|
||||
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(ssh_channel_open_session(channel) != SSH_OK){
|
||||
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
|
||||
ssh_channel_free(channel);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(ssh_channel_request_exec(channel,createcommand) != SSH_OK){
|
||||
fprintf(stderr,"Error executing command: %s\n",ssh_get_error(session));
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while(!ssh_channel_is_eof(channel)){
|
||||
rc = ssh_channel_read(channel,buffer,1,1);
|
||||
if (rc != 1) {
|
||||
fprintf(stderr, "Error reading from channel\n");
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = write(1, buffer, 1);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Error writing to buffer\n");
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ssh_channel_close(channel);
|
||||
ssh_channel_free(channel);
|
||||
}
|
||||
|
||||
|
||||
static int fetch_files(ssh_session session){
|
||||
int size;
|
||||
char buffer[BUF_SIZE];
|
||||
int mode;
|
||||
char *filename = NULL;
|
||||
int r;
|
||||
ssh_scp scp=ssh_scp_new(session, SSH_SCP_READ | SSH_SCP_RECURSIVE, "/tmp/libssh_tests/*");
|
||||
if(ssh_scp_init(scp) != SSH_OK){
|
||||
fprintf(stderr,"error initializing scp: %s\n",ssh_get_error(session));
|
||||
ssh_scp_free(scp);
|
||||
return -1;
|
||||
}
|
||||
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
|
||||
do {
|
||||
|
||||
r=ssh_scp_pull_request(scp);
|
||||
switch(r){
|
||||
case SSH_SCP_REQUEST_NEWFILE:
|
||||
size=ssh_scp_request_get_size(scp);
|
||||
filename=strdup(ssh_scp_request_get_filename(scp));
|
||||
mode=ssh_scp_request_get_permissions(scp);
|
||||
printf("downloading file %s, size %d, perms 0%o\n",filename,size,mode);
|
||||
free(filename);
|
||||
ssh_scp_accept_request(scp);
|
||||
r=ssh_scp_read(scp,buffer,sizeof(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(session));
|
||||
ssh_scp_close(scp);
|
||||
ssh_scp_free(scp);
|
||||
return -1;
|
||||
}
|
||||
printf("done\n");
|
||||
break;
|
||||
case SSH_ERROR:
|
||||
fprintf(stderr,"Error: %s\n",ssh_get_error(session));
|
||||
ssh_scp_close(scp);
|
||||
ssh_scp_free(scp);
|
||||
return -1;
|
||||
case SSH_SCP_REQUEST_WARNING:
|
||||
fprintf(stderr,"Warning: %s\n",ssh_scp_request_get_warning(scp));
|
||||
break;
|
||||
case SSH_SCP_REQUEST_NEWDIR:
|
||||
filename=strdup(ssh_scp_request_get_filename(scp));
|
||||
mode=ssh_scp_request_get_permissions(scp);
|
||||
printf("downloading directory %s, perms 0%o\n",filename,mode);
|
||||
free(filename);
|
||||
ssh_scp_accept_request(scp);
|
||||
break;
|
||||
case SSH_SCP_REQUEST_ENDDIR:
|
||||
printf("End of directory\n");
|
||||
break;
|
||||
case SSH_SCP_REQUEST_EOF:
|
||||
printf("End of requests\n");
|
||||
goto end;
|
||||
}
|
||||
} while (1);
|
||||
end:
|
||||
ssh_scp_close(scp);
|
||||
ssh_scp_free(scp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session = NULL;
|
||||
if(opts(argc,argv)<0)
|
||||
return EXIT_FAILURE;
|
||||
session=connect_ssh(host,NULL,verbosity);
|
||||
if(session == NULL)
|
||||
return EXIT_FAILURE;
|
||||
create_files(session);
|
||||
fetch_files(session);
|
||||
ssh_disconnect(session);
|
||||
ssh_free(session);
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,60 +5,60 @@
|
||||
|
||||
#define LIMIT 0x100000000UL
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
ssh_channel channel = NULL;
|
||||
char buffer[1024 * 1024] = {0};
|
||||
int rc;
|
||||
uint64_t total = 0;
|
||||
uint64_t lastshown = 4096;
|
||||
session = connect_ssh("localhost", NULL, 0);
|
||||
if (session == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL) {
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = ssh_channel_open_session(channel);
|
||||
if (rc < 0) {
|
||||
ssh_channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = ssh_channel_request_exec(channel, "cat > /dev/null");
|
||||
if (rc < 0) {
|
||||
ssh_channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while ((rc = ssh_channel_write(channel, buffer, sizeof(buffer))) > 0) {
|
||||
total += rc;
|
||||
if (total / 2 >= lastshown) {
|
||||
printf("written %llx\n", (long long unsigned int)total);
|
||||
lastshown = total;
|
||||
}
|
||||
if (total > LIMIT)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
printf("error : %s\n", ssh_get_error(session));
|
||||
ssh_channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssh_channel_send_eof(channel);
|
||||
ssh_channel_close(channel);
|
||||
int main(void) {
|
||||
ssh_session session = NULL;
|
||||
ssh_channel channel;
|
||||
char buffer[1024*1024];
|
||||
int rc;
|
||||
uint64_t total=0;
|
||||
uint64_t lastshown=4096;
|
||||
session = connect_ssh("localhost", NULL, 0);
|
||||
if (session == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL) {
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
rc = ssh_channel_open_session(channel);
|
||||
if (rc < 0) {
|
||||
ssh_channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = ssh_channel_request_exec(channel, "cat > /dev/null");
|
||||
if (rc < 0) {
|
||||
ssh_channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
while ((rc = ssh_channel_write(channel, buffer, sizeof(buffer))) > 0) {
|
||||
total += rc;
|
||||
if(total/2 >= lastshown){
|
||||
printf("written %llx\n", (long long unsigned int) total);
|
||||
lastshown=total;
|
||||
}
|
||||
if(total > LIMIT)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
printf("error : %s\n",ssh_get_error(session));
|
||||
ssh_channel_close(channel);
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssh_channel_send_eof(channel);
|
||||
ssh_channel_close(channel);
|
||||
|
||||
ssh_disconnect(session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -192,6 +192,9 @@ static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
static int
|
||||
parse_opt(int argc, char **argv, ssh_bind sshbind)
|
||||
{
|
||||
int no_default_keys = 0;
|
||||
int rsa_already_set = 0;
|
||||
int ecdsa_already_set = 0;
|
||||
int key;
|
||||
|
||||
while((key = getopt(argc, argv, "a:e:k:p:P:r:u:v")) != -1) {
|
||||
@@ -199,10 +202,16 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, optarg);
|
||||
} else if (key == 'k') {
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
||||
/* 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;
|
||||
} else if (key == 'r') {
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
||||
rsa_already_set = 1;
|
||||
} else if (key == 'e') {
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
|
||||
ecdsa_already_set = 1;
|
||||
} else if (key == 'a') {
|
||||
strncpy(authorizedkeys, optarg, DEF_STR_SIZE-1);
|
||||
} else if (key == 'u') {
|
||||
@@ -247,6 +256,12 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
|
||||
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, argv[optind]);
|
||||
|
||||
if (!no_default_keys) {
|
||||
set_default_keys(sshbind,
|
||||
rsa_already_set,
|
||||
ecdsa_already_set);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_ARGP_H */
|
||||
|
||||
@@ -40,236 +40,222 @@ clients must be made or how a client should react.
|
||||
#endif
|
||||
|
||||
char *host = NULL;
|
||||
const char *desthost = "localhost";
|
||||
const char *port = "22";
|
||||
const char *desthost="localhost";
|
||||
const char *port="22";
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
#include <libssh/pcap.h>
|
||||
char *pcap_file = NULL;
|
||||
char *pcap_file=NULL;
|
||||
#endif
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
|
||||
exit(1);
|
||||
fprintf(stderr,"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int opts(int argc, char **argv)
|
||||
{
|
||||
static int opts(int argc, char **argv){
|
||||
int i;
|
||||
while ((i = getopt(argc, argv, "P:")) != -1) {
|
||||
switch (i) {
|
||||
while((i=getopt(argc,argv,"P:"))!=-1){
|
||||
switch(i){
|
||||
#ifdef WITH_PCAP
|
||||
case 'P':
|
||||
pcap_file = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
pcap_file=optarg;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fprintf(stderr, "unknown option %c\n", optopt);
|
||||
usage();
|
||||
default:
|
||||
fprintf(stderr,"unknown option %c\n",optopt);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if (optind < argc)
|
||||
host = argv[optind++];
|
||||
if (optind < argc)
|
||||
desthost = argv[optind++];
|
||||
if (optind < argc)
|
||||
port = argv[optind++];
|
||||
if (host == NULL)
|
||||
if(optind < argc)
|
||||
host=argv[optind++];
|
||||
if(optind < argc)
|
||||
desthost=argv[optind++];
|
||||
if(optind < argc)
|
||||
port=argv[optind++];
|
||||
if(host==NULL)
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void select_loop(ssh_session session, ssh_channel channel)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
char buffer[BUF_SIZE];
|
||||
/* channels will be set to the channels to poll.
|
||||
* outchannels will contain the result of the poll
|
||||
*/
|
||||
ssh_channel channels[2], outchannels[2];
|
||||
int lus;
|
||||
int eof = 0;
|
||||
int maxfd;
|
||||
int ret;
|
||||
while (channel) {
|
||||
do {
|
||||
static void select_loop(ssh_session session,ssh_channel channel){
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
char buffer[BUF_SIZE];
|
||||
/* channels will be set to the channels to poll.
|
||||
* outchannels will contain the result of the poll
|
||||
*/
|
||||
ssh_channel channels[2], outchannels[2];
|
||||
int lus;
|
||||
int eof=0;
|
||||
int maxfd;
|
||||
int ret;
|
||||
while(channel){
|
||||
do{
|
||||
int fd;
|
||||
|
||||
ZERO_STRUCT(fds);
|
||||
FD_ZERO(&fds);
|
||||
if (!eof)
|
||||
FD_SET(0, &fds);
|
||||
timeout.tv_sec = 30;
|
||||
timeout.tv_usec = 0;
|
||||
FD_ZERO(&fds);
|
||||
if(!eof)
|
||||
FD_SET(0,&fds);
|
||||
timeout.tv_sec=30;
|
||||
timeout.tv_usec=0;
|
||||
|
||||
fd = ssh_get_fd(session);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr,
|
||||
"Error getting the session file descriptor: %s\n",
|
||||
ssh_get_error(session));
|
||||
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);
|
||||
if (ret == EINTR)
|
||||
continue;
|
||||
if (FD_ISSET(0, &fds)) {
|
||||
lus = read(0, buffer, sizeof(buffer));
|
||||
if (lus)
|
||||
ssh_channel_write(channel, buffer, lus);
|
||||
else {
|
||||
eof = 1;
|
||||
ssh_channel_send_eof(channel);
|
||||
}
|
||||
}
|
||||
if (channel && ssh_channel_is_closed(channel)) {
|
||||
ssh_channel_free(channel);
|
||||
channel = NULL;
|
||||
channels[0] = NULL;
|
||||
}
|
||||
if (outchannels[0]) {
|
||||
while (channel && ssh_channel_is_open(channel) &&
|
||||
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;
|
||||
channels[0]=channel; // set the first channel we want to read from
|
||||
channels[1]=NULL;
|
||||
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
|
||||
if(ret==EINTR)
|
||||
continue;
|
||||
if(FD_ISSET(0,&fds)){
|
||||
lus=read(0,buffer,sizeof(buffer));
|
||||
if(lus)
|
||||
ssh_channel_write(channel,buffer,lus);
|
||||
else {
|
||||
eof=1;
|
||||
ssh_channel_send_eof(channel);
|
||||
}
|
||||
}
|
||||
if(channel && ssh_channel_is_closed(channel)){
|
||||
ssh_channel_free(channel);
|
||||
channel=NULL;
|
||||
channels[0]=NULL;
|
||||
}
|
||||
if(outchannels[0]){
|
||||
while(channel && ssh_channel_is_open(channel) && 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){
|
||||
ssh_channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else {
|
||||
ret = write(1, buffer, lus);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error writing to stdin: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
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){
|
||||
ssh_channel_free(channel);
|
||||
channel=channels[0]=NULL;
|
||||
} else {
|
||||
ret = write(2, buffer, lus);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Error writing to stderr: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (lus == 0) {
|
||||
ssh_channel_free(channel);
|
||||
channel = channels[0] = NULL;
|
||||
} else {
|
||||
ret = write(1, buffer, lus);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,
|
||||
"Error writing to stdin: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
ssh_channel_free(channel);
|
||||
channel = channels[0] = NULL;
|
||||
} else {
|
||||
ret = write(2, buffer, lus);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,
|
||||
"Error writing to stderr: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (channel && ssh_channel_is_closed(channel)) {
|
||||
ssh_channel_free(channel);
|
||||
channel = NULL;
|
||||
}
|
||||
} while (ret == EINTR || ret == SSH_EINTR);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(channel && ssh_channel_is_closed(channel)){
|
||||
ssh_channel_free(channel);
|
||||
channel=NULL;
|
||||
}
|
||||
} while (ret==EINTR || ret==SSH_EINTR);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void forwarding(ssh_session session)
|
||||
{
|
||||
static void forwarding(ssh_session session){
|
||||
ssh_channel channel;
|
||||
int r;
|
||||
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));
|
||||
if(r<0) {
|
||||
printf("error forwarding port : %s\n",ssh_get_error(session));
|
||||
return;
|
||||
}
|
||||
select_loop(session, channel);
|
||||
select_loop(session,channel);
|
||||
}
|
||||
|
||||
static int client(ssh_session session)
|
||||
{
|
||||
int auth = 0;
|
||||
char *banner = NULL;
|
||||
int state;
|
||||
static int client(ssh_session session){
|
||||
int auth=0;
|
||||
char *banner = NULL;
|
||||
int state;
|
||||
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0)
|
||||
return -1;
|
||||
ssh_options_parse_config(session, NULL);
|
||||
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
|
||||
return -1;
|
||||
ssh_options_parse_config(session, NULL);
|
||||
|
||||
if (ssh_connect(session)) {
|
||||
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
state = verify_knownhost(session);
|
||||
if (state != 0)
|
||||
return -1;
|
||||
ssh_userauth_none(session, NULL);
|
||||
banner = ssh_get_issue_banner(session);
|
||||
if (banner) {
|
||||
printf("%s\n", banner);
|
||||
free(banner);
|
||||
}
|
||||
auth = authenticate_console(session);
|
||||
if (auth != SSH_AUTH_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
forwarding(session);
|
||||
return 0;
|
||||
if(ssh_connect(session)){
|
||||
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
state=verify_knownhost(session);
|
||||
if (state != 0)
|
||||
return -1;
|
||||
ssh_userauth_none(session, NULL);
|
||||
banner=ssh_get_issue_banner(session);
|
||||
if(banner){
|
||||
printf("%s\n",banner);
|
||||
free(banner);
|
||||
}
|
||||
auth=authenticate_console(session);
|
||||
if(auth != SSH_AUTH_SUCCESS){
|
||||
return -1;
|
||||
}
|
||||
forwarding(session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_PCAP
|
||||
ssh_pcap_file pcap;
|
||||
void set_pcap(ssh_session session);
|
||||
void set_pcap(ssh_session session)
|
||||
{
|
||||
if (!pcap_file)
|
||||
return;
|
||||
pcap = ssh_pcap_file_new();
|
||||
if (ssh_pcap_file_open(pcap, pcap_file) == SSH_ERROR) {
|
||||
printf("Error opening pcap file\n");
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap = NULL;
|
||||
return;
|
||||
}
|
||||
ssh_set_pcap_file(session, pcap);
|
||||
void 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);
|
||||
}
|
||||
|
||||
void cleanup_pcap(void);
|
||||
void cleanup_pcap(void)
|
||||
{
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap = NULL;
|
||||
ssh_pcap_file_free(pcap);
|
||||
pcap = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session = NULL;
|
||||
|
||||
session = ssh_new();
|
||||
|
||||
if (ssh_options_getopt(session, &argc, argv)) {
|
||||
fprintf(stderr,
|
||||
"error parsing command line :%s\n",
|
||||
ssh_get_error(session));
|
||||
usage();
|
||||
if(ssh_options_getopt(session, &argc, argv)) {
|
||||
fprintf(stderr, "error parsing command line :%s\n",
|
||||
ssh_get_error(session));
|
||||
usage();
|
||||
}
|
||||
opts(argc, argv);
|
||||
opts(argc,argv);
|
||||
#ifdef WITH_PCAP
|
||||
set_pcap(session);
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,6 @@ extern "C" {
|
||||
|
||||
bignum ssh_make_string_bn(ssh_string string);
|
||||
ssh_string ssh_make_bignum_string(bignum num);
|
||||
ssh_string ssh_make_padded_bignum_string(bignum num, size_t pad_len);
|
||||
void ssh_print_bignum(const char *which, const_bignum num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -325,28 +325,6 @@ typedef int (*ssh_gssapi_accept_sec_ctx_callback) (ssh_session session,
|
||||
typedef int (*ssh_gssapi_verify_mic_callback) (ssh_session session,
|
||||
ssh_string mic, void *mic_buffer, size_t mic_buffer_size, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Handles an SSH new channel open "direct-tcpip" request. This
|
||||
* happens when the client forwards an incoming TCP connection on a port it
|
||||
* wants to forward to the destination. This is a server-side API
|
||||
* @param session current session handler
|
||||
* @param destination_address the address that the TCP connection connected to
|
||||
* @param destination_port the port that the TCP connection connected to
|
||||
* @param originator_address the originator IP address
|
||||
* @param originator_port the originator port
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @returns a valid ssh_channel handle if the request is to be allowed
|
||||
* @returns NULL if the request should not be allowed
|
||||
* @warning The channel pointer returned by this callback must be closed by the
|
||||
* application.
|
||||
*/
|
||||
typedef ssh_channel (*ssh_channel_open_request_direct_tcpip_callback)(
|
||||
ssh_session session,
|
||||
const char *destination_address,
|
||||
int destination_port,
|
||||
const char *originator_address,
|
||||
int originator_port,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* This structure can be used to implement a libssh server, with appropriate callbacks.
|
||||
@@ -397,12 +375,6 @@ struct ssh_server_callbacks_struct {
|
||||
/* This function will be called when a MIC needs to be verified.
|
||||
*/
|
||||
ssh_gssapi_verify_mic_callback gssapi_verify_mic_function;
|
||||
/**
|
||||
* This function will be called when an incoming "direct-tcpip"
|
||||
* request is received.
|
||||
*/
|
||||
ssh_channel_open_request_direct_tcpip_callback
|
||||
channel_open_request_direct_tcpip_function;
|
||||
};
|
||||
typedef struct ssh_server_callbacks_struct *ssh_server_callbacks;
|
||||
|
||||
|
||||
@@ -45,11 +45,10 @@
|
||||
#ifdef HAVE_OPENSSL_ECDH_H
|
||||
#include <openssl/ecdh.h>
|
||||
#endif
|
||||
#include "libssh/curve25519.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/kex.h"
|
||||
#include "libssh/sntrup761.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
#define DIGEST_MAX_LEN 64
|
||||
|
||||
@@ -57,34 +56,32 @@
|
||||
#define AES_GCM_IVLEN 12
|
||||
|
||||
enum ssh_key_exchange_e {
|
||||
/* diffie-hellman-group1-sha1 */
|
||||
SSH_KEX_DH_GROUP1_SHA1 = 1,
|
||||
/* diffie-hellman-group14-sha1 */
|
||||
SSH_KEX_DH_GROUP14_SHA1,
|
||||
/* diffie-hellman-group1-sha1 */
|
||||
SSH_KEX_DH_GROUP1_SHA1=1,
|
||||
/* diffie-hellman-group14-sha1 */
|
||||
SSH_KEX_DH_GROUP14_SHA1,
|
||||
#ifdef WITH_GEX
|
||||
/* diffie-hellman-group-exchange-sha1 */
|
||||
SSH_KEX_DH_GEX_SHA1,
|
||||
/* diffie-hellman-group-exchange-sha256 */
|
||||
SSH_KEX_DH_GEX_SHA256,
|
||||
/* diffie-hellman-group-exchange-sha1 */
|
||||
SSH_KEX_DH_GEX_SHA1,
|
||||
/* diffie-hellman-group-exchange-sha256 */
|
||||
SSH_KEX_DH_GEX_SHA256,
|
||||
#endif /* WITH_GEX */
|
||||
/* ecdh-sha2-nistp256 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP256,
|
||||
/* ecdh-sha2-nistp384 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP384,
|
||||
/* ecdh-sha2-nistp521 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP521,
|
||||
/* curve25519-sha256@libssh.org */
|
||||
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG,
|
||||
/* curve25519-sha256 */
|
||||
SSH_KEX_CURVE25519_SHA256,
|
||||
/* diffie-hellman-group16-sha512 */
|
||||
SSH_KEX_DH_GROUP16_SHA512,
|
||||
/* diffie-hellman-group18-sha512 */
|
||||
SSH_KEX_DH_GROUP18_SHA512,
|
||||
/* diffie-hellman-group14-sha256 */
|
||||
SSH_KEX_DH_GROUP14_SHA256,
|
||||
/* sntrup761x25519-sha512@openssh.com */
|
||||
SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM,
|
||||
/* ecdh-sha2-nistp256 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP256,
|
||||
/* ecdh-sha2-nistp384 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP384,
|
||||
/* ecdh-sha2-nistp521 */
|
||||
SSH_KEX_ECDH_SHA2_NISTP521,
|
||||
/* curve25519-sha256@libssh.org */
|
||||
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG,
|
||||
/* curve25519-sha256 */
|
||||
SSH_KEX_CURVE25519_SHA256,
|
||||
/* diffie-hellman-group16-sha512 */
|
||||
SSH_KEX_DH_GROUP16_SHA512,
|
||||
/* diffie-hellman-group18-sha512 */
|
||||
SSH_KEX_DH_GROUP18_SHA512,
|
||||
/* diffie-hellman-group14-sha256 */
|
||||
SSH_KEX_DH_GROUP14_SHA256,
|
||||
};
|
||||
|
||||
enum ssh_cipher_e {
|
||||
@@ -128,20 +125,9 @@ struct ssh_crypto_struct {
|
||||
ssh_string ecdh_server_pubkey;
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
EVP_PKEY *curve25519_privkey;
|
||||
#elif defined(HAVE_GCRYPT_CURVE25519)
|
||||
gcry_sexp_t curve25519_privkey;
|
||||
#else
|
||||
ssh_curve25519_privkey curve25519_privkey;
|
||||
#endif
|
||||
ssh_curve25519_pubkey curve25519_client_pubkey;
|
||||
ssh_curve25519_pubkey curve25519_server_pubkey;
|
||||
#endif
|
||||
#ifdef HAVE_SNTRUP761
|
||||
ssh_sntrup761_privkey sntrup761_privkey;
|
||||
ssh_sntrup761_pubkey sntrup761_client_pubkey;
|
||||
ssh_sntrup761_ciphertext sntrup761_ciphertext;
|
||||
#endif
|
||||
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
||||
size_t session_id_len;
|
||||
@@ -237,9 +223,6 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
|
||||
size_t requested_len);
|
||||
|
||||
int secure_memcmp(const void *s1, const void *s2, size_t n);
|
||||
#if defined(HAVE_LIBCRYPTO) && !defined(WITH_PKCS11_PROVIDER)
|
||||
ENGINE *pki_get_engine(void);
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
void compress_cleanup(struct ssh_crypto_struct *crypto);
|
||||
|
||||
|
||||
@@ -50,9 +50,6 @@ int crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned c
|
||||
typedef unsigned char ssh_curve25519_pubkey[CURVE25519_PUBKEY_SIZE];
|
||||
typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
|
||||
|
||||
int ssh_curve25519_init(ssh_session session);
|
||||
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k);
|
||||
int ssh_curve25519_create_k(ssh_session session, ssh_curve25519_pubkey k);
|
||||
|
||||
int ssh_client_curve25519_init(ssh_session session);
|
||||
void ssh_client_curve25519_remove_callbacks(ssh_session session);
|
||||
|
||||
@@ -52,10 +52,10 @@ char *ssh_prefix_default_algos(enum ssh_kex_types_e algo, const char *list);
|
||||
char **ssh_space_tokenize(const char *chain);
|
||||
int ssh_get_kex1(ssh_session session);
|
||||
char *ssh_find_matching(const char *in_d, const char *what_d);
|
||||
const char *ssh_kex_get_supported_method(enum ssh_kex_types_e type);
|
||||
const char *ssh_kex_get_default_methods(enum ssh_kex_types_e type);
|
||||
const char *ssh_kex_get_fips_methods(enum ssh_kex_types_e type);
|
||||
const char *ssh_kex_get_description(enum ssh_kex_types_e type);
|
||||
const char *ssh_kex_get_supported_method(uint32_t algo);
|
||||
const char *ssh_kex_get_default_methods(uint32_t algo);
|
||||
const char *ssh_kex_get_fips_methods(uint32_t algo);
|
||||
const char *ssh_kex_get_description(uint32_t algo);
|
||||
char *ssh_client_select_hostkeys(ssh_session session);
|
||||
int ssh_send_rekex(ssh_session session);
|
||||
int server_set_kex(ssh_session session);
|
||||
|
||||
@@ -121,6 +121,15 @@ typedef BN_CTX* bignum_CTX;
|
||||
|
||||
ssh_string pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p);
|
||||
int pki_key_ecgroup_name_to_nid(const char *group);
|
||||
|
||||
#if defined(WITH_PKCS11_URI)
|
||||
#if defined(WITH_PKCS11_PROVIDER)
|
||||
int pki_load_pkcs11_provider(void);
|
||||
#else
|
||||
ENGINE *pki_get_engine(void);
|
||||
#endif
|
||||
#endif /* WITH_PKCS11_PROVIDER */
|
||||
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
#endif /* LIBCRYPTO_H_ */
|
||||
|
||||
@@ -49,10 +49,9 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef int mode_t;
|
||||
@@ -875,7 +874,6 @@ 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);
|
||||
LIBSSH_API const char *ssh_get_supported_methods(enum ssh_kex_types_e type);
|
||||
|
||||
LIBSSH_API ssh_buffer ssh_buffer_new(void);
|
||||
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
|
||||
@@ -888,27 +886,6 @@ LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
|
||||
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
|
||||
LIBSSH_API int ssh_session_set_disconnect_message(ssh_session session, const char *message);
|
||||
|
||||
/* SSHSIG hashes data independently from the key used, so we use a new enum
|
||||
to avoid confusion. See
|
||||
https://gitlab.com/jas/ietf-sshsig-format/-/blob/cc70a225cbd695d5a6f20aaebdb4b92b0818e43a/ietf-sshsig-format.md#L137
|
||||
*/
|
||||
enum sshsig_digest_e {
|
||||
SSHSIG_DIGEST_SHA2_256 = 0,
|
||||
SSHSIG_DIGEST_SHA2_512 = 1,
|
||||
};
|
||||
|
||||
LIBSSH_API int sshsig_sign(const void *data,
|
||||
size_t data_length,
|
||||
ssh_key privkey,
|
||||
const char *sig_namespace,
|
||||
enum sshsig_digest_e hash_alg,
|
||||
char **signature);
|
||||
LIBSSH_API int sshsig_verify(const void *data,
|
||||
size_t data_length,
|
||||
const char *signature,
|
||||
const char *sig_namespace,
|
||||
ssh_key *sign_key);
|
||||
|
||||
#ifndef LIBSSH_LEGACY_0_4
|
||||
#include "libssh/legacy.h"
|
||||
#endif
|
||||
|
||||
@@ -28,7 +28,6 @@ struct ssh_auth_request {
|
||||
int method;
|
||||
char *password;
|
||||
struct ssh_key_struct *pubkey;
|
||||
struct ssh_key_struct *server_pubkey;
|
||||
char *sigtype;
|
||||
enum ssh_publickey_state_e signature_state;
|
||||
char kbdint_response;
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ssh_config_parse(ssh_session session, FILE *fp, bool global);
|
||||
int ssh_config_parse_file(ssh_session session, const char *filename);
|
||||
int ssh_config_parse_string(ssh_session session, const char *input);
|
||||
int ssh_options_set_algo(ssh_session session,
|
||||
|
||||
@@ -51,15 +51,6 @@
|
||||
#define SSH_KEY_FLAG_PRIVATE 0x0002
|
||||
#define SSH_KEY_FLAG_PKCS11_URI 0x0004
|
||||
|
||||
/* Constants matching the Lightweight Secure Shell Signature Format */
|
||||
/* https://datatracker.ietf.org/doc/draft-josefsson-sshsig-format */
|
||||
#define SSHSIG_VERSION 0x01
|
||||
#define SSHSIG_MAGIC_PREAMBLE "SSHSIG"
|
||||
#define SSHSIG_MAGIC_PREAMBLE_LEN (sizeof(SSHSIG_MAGIC_PREAMBLE) - 1)
|
||||
#define SSHSIG_BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----"
|
||||
#define SSHSIG_END_SIGNATURE "-----END SSH SIGNATURE-----"
|
||||
#define SSHSIG_LINE_LENGTH 76
|
||||
|
||||
struct ssh_key_struct {
|
||||
enum ssh_keytypes_e type;
|
||||
int flags;
|
||||
@@ -72,12 +63,11 @@ struct ssh_key_struct {
|
||||
mbedtls_pk_context *pk;
|
||||
mbedtls_ecdsa_context *ecdsa;
|
||||
#elif defined(HAVE_LIBCRYPTO)
|
||||
/* This holds either ENGINE/PROVIDER key for PKCS#11 support
|
||||
* or just key in high-level format */
|
||||
/* This holds either ENGINE key for PKCS#11 support or just key in
|
||||
* high-level format */
|
||||
EVP_PKEY *key;
|
||||
/* keep this around for FIPS mode so we can parse the public keys. We won't
|
||||
* be able to use them nor use the private keys though */
|
||||
uint8_t *ed25519_pubkey;
|
||||
uint8_t *ed25519_privkey;
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
#ifndef HAVE_LIBCRYPTO
|
||||
ed25519_pubkey *ed25519_pubkey;
|
||||
|
||||
@@ -148,7 +148,6 @@ int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
|
||||
int pki_privkey_build_ed25519(ssh_key key,
|
||||
ssh_string pubkey,
|
||||
ssh_string privkey);
|
||||
int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey);
|
||||
|
||||
/* PKI Container OpenSSH */
|
||||
ssh_key ssh_pki_openssh_pubkey_import(const char *text_key);
|
||||
|
||||
@@ -157,6 +157,7 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx);
|
||||
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p);
|
||||
int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, struct ssh_socket_struct *s);
|
||||
void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p);
|
||||
bool ssh_poll_is_locked(ssh_poll_handle p);
|
||||
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout);
|
||||
ssh_poll_ctx ssh_poll_get_default_ctx(ssh_session session);
|
||||
int ssh_event_add_poll(ssh_event event, ssh_poll_handle p);
|
||||
|
||||
@@ -30,11 +30,10 @@
|
||||
#define _LIBSSH_PRIV_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if !defined(HAVE_STRTOULL)
|
||||
# if defined(HAVE___STRTOULL)
|
||||
@@ -165,9 +164,6 @@ int ssh_gettimeofday(struct timeval *__p, void *__t);
|
||||
|
||||
#define gettimeofday ssh_gettimeofday
|
||||
|
||||
struct tm *ssh_localtime(const time_t *timer, struct tm *result);
|
||||
# define localtime_r ssh_localtime
|
||||
|
||||
#define _XCLOSESOCKET closesocket
|
||||
|
||||
# ifdef HAVE_IO_H
|
||||
@@ -333,7 +329,7 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen);
|
||||
/* match.c */
|
||||
int match_pattern_list(const char *string, const char *pattern,
|
||||
size_t len, int dolower);
|
||||
int match_hostname(const char *host, const char *pattern, size_t len);
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len);
|
||||
#ifndef _WIN32
|
||||
int match_cidr_address_list(const char *address,
|
||||
const char *addrlist,
|
||||
@@ -357,10 +353,10 @@ int ssh_connector_remove_event(ssh_connector connector);
|
||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
|
||||
|
||||
/** Zero a structure */
|
||||
#define ZERO_STRUCT(x) memset(&(x), 0, sizeof(x))
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
|
||||
/** Zero a structure given a pointer to the structure */
|
||||
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((x), 0, sizeof(*(x))); } while(0)
|
||||
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
|
||||
|
||||
/** Get the size of an array */
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
@@ -120,8 +120,6 @@ enum ssh_pending_call_e {
|
||||
/* server-sig-algs extension */
|
||||
#define SSH_EXT_SIG_RSA_SHA256 0x02
|
||||
#define SSH_EXT_SIG_RSA_SHA512 0x04
|
||||
/* Host-bound public key authentication extension */
|
||||
#define SSH_EXT_PUBLICKEY_HOSTBOUND 0x08
|
||||
|
||||
/* members that are common to ssh_session and ssh_bind */
|
||||
struct ssh_common_struct {
|
||||
|
||||
@@ -79,7 +79,6 @@ typedef struct sftp_status_message_struct* sftp_status_message;
|
||||
typedef struct sftp_statvfs_struct* sftp_statvfs_t;
|
||||
typedef struct sftp_limits_struct* sftp_limits_t;
|
||||
typedef struct sftp_aio_struct* sftp_aio;
|
||||
typedef struct sftp_name_id_map_struct *sftp_name_id_map;
|
||||
|
||||
struct sftp_session_struct {
|
||||
ssh_session session;
|
||||
@@ -214,22 +213,6 @@ struct sftp_limits_struct {
|
||||
uint64_t max_open_handles; /** maximum number of active handles allowed by server */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SFTP names map structure to store the mapping between ids and names.
|
||||
*
|
||||
* This is mainly for the use of sftp_get_users_groups_by_id() function.
|
||||
*/
|
||||
struct sftp_name_id_map_struct {
|
||||
/** @brief Count of name-id pairs in the map */
|
||||
uint32_t count;
|
||||
|
||||
/** @brief Array of ids, ids[i] mapped to names[i] */
|
||||
uint32_t *ids;
|
||||
|
||||
/** @brief Array of names, names[i] mapped to ids[i] */
|
||||
char **names;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a new sftp session.
|
||||
*
|
||||
@@ -237,30 +220,24 @@ struct sftp_name_id_map_struct {
|
||||
* with the server inside of the provided ssh session. This function call is
|
||||
* usually followed by the sftp_init(), which initializes SFTP protocol itself.
|
||||
*
|
||||
* @param session The ssh session to use. The session *must* be in
|
||||
* blocking mode since most `sftp_*` functions do not
|
||||
* support the non-blocking API.
|
||||
* @param session The ssh session to use.
|
||||
*
|
||||
* @return A new sftp session or NULL on error.
|
||||
*
|
||||
* @see sftp_free()
|
||||
* @see sftp_init()
|
||||
* @see ssh_set_blocking()
|
||||
*/
|
||||
LIBSSH_API sftp_session sftp_new(ssh_session session);
|
||||
|
||||
/**
|
||||
* @brief Start a new sftp session with an existing channel.
|
||||
*
|
||||
* @param session The ssh session to use. The session *must* be in
|
||||
* blocking mode since most `sftp_*` functions do not
|
||||
* support the non-blocking API.
|
||||
* @param session The ssh session to use.
|
||||
* @param channel An open session channel with subsystem already allocated
|
||||
*
|
||||
* @return A new sftp session or NULL on error.
|
||||
*
|
||||
* @see sftp_free()
|
||||
* @see ssh_set_blocking()
|
||||
*/
|
||||
LIBSSH_API sftp_session sftp_new_channel(ssh_session session, ssh_channel channel);
|
||||
|
||||
@@ -1211,58 +1188,6 @@ LIBSSH_API char *sftp_expand_path(sftp_session sftp, const char *path);
|
||||
*/
|
||||
LIBSSH_API char *sftp_home_directory(sftp_session sftp, const char *username);
|
||||
|
||||
/**
|
||||
* @brief Create a new sftp_name_id_map struct.
|
||||
*
|
||||
* @param count The number of ids/names to store in the map.
|
||||
*
|
||||
* @return A pointer to the newly allocated sftp_name_id_map
|
||||
* struct.
|
||||
*/
|
||||
LIBSSH_API sftp_name_id_map sftp_name_id_map_new(uint32_t count);
|
||||
|
||||
/**
|
||||
* @brief Free the memory of an allocated `sftp_name_id_map` struct.
|
||||
*
|
||||
* @param map A pointer to the `sftp_name_id_map` struct to free.
|
||||
*/
|
||||
LIBSSH_API void sftp_name_id_map_free(sftp_name_id_map map);
|
||||
|
||||
/**
|
||||
* @brief Retrieves usernames and group names based on provided user and group
|
||||
* IDs.
|
||||
*
|
||||
* The retrieved names are stored in the `names` field of the
|
||||
* `sftp_name_id_map` structure. In case a uid or gid is not found, an empty
|
||||
* string is stored.
|
||||
*
|
||||
* This calls the "users-groups-by-id@openssh.com" extension.
|
||||
* You should check if the extension is supported using:
|
||||
*
|
||||
* @code
|
||||
* int supported = sftp_extension_supported(sftp,
|
||||
* "users-groups-by-id@openssh.com", "1");
|
||||
* @endcode
|
||||
*
|
||||
* @param sftp The SFTP session handle.
|
||||
*
|
||||
* @param users_map A pointer to a `sftp_name_id_map` struct with the user
|
||||
* IDs. Can be NULL if only group names are needed.
|
||||
*
|
||||
* @param groups_map A pointer to a `sftp_name_id_map` struct with the group
|
||||
* IDs. Can be NULL if only user names are needed.
|
||||
*
|
||||
* @return 0 on success, < 0 on error with ssh and sftp error set.
|
||||
*
|
||||
* @note The caller needs to free the memory used for
|
||||
* the maps later using `sftp_name_id_map_free()`.
|
||||
*
|
||||
* @see sftp_get_error()
|
||||
*/
|
||||
LIBSSH_API int sftp_get_users_groups_by_id(sftp_session sftp,
|
||||
sftp_name_id_map users_map,
|
||||
sftp_name_id_map groups_map);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
/**
|
||||
* @brief Create a new sftp server session.
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#ifndef SFTP_PRIV_H
|
||||
#define SFTP_PRIV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -64,39 +62,6 @@ int sftp_read_and_dispatch(sftp_session sftp);
|
||||
|
||||
sftp_message sftp_dequeue(sftp_session sftp, uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief Receive the response of an sftp request
|
||||
*
|
||||
* In blocking mode, if the response hasn't arrived at the time of call, this
|
||||
* function waits for the response to arrive.
|
||||
*
|
||||
* @param sftp The sftp session via which the request was sent.
|
||||
*
|
||||
* @param id The request identifier of the request whose
|
||||
* corresponding response is required.
|
||||
*
|
||||
* @param blocking Flag to indicate the operating mode. true indicates
|
||||
* blocking mode and false indicates non-blocking mode
|
||||
*
|
||||
* @param msg_ptr Pointer to the location to store the response message.
|
||||
* In case of success, the message is allocated
|
||||
* dynamically and must be freed (using
|
||||
* sftp_message_free()) by the caller after usage. In case
|
||||
* of failure, this is left untouched.
|
||||
*
|
||||
* @returns SSH_OK on success
|
||||
* @returns SSH_ERROR on failure with the sftp and ssh errors set
|
||||
* @returns SSH_AGAIN in case of non-blocking mode if the response hasn't
|
||||
* arrived yet.
|
||||
*
|
||||
* @warning In blocking mode, this may block indefinitely for an invalid request
|
||||
* identifier.
|
||||
*/
|
||||
int sftp_recv_response_msg(sftp_session sftp,
|
||||
uint32_t id,
|
||||
bool blocking,
|
||||
sftp_message *msg_ptr);
|
||||
|
||||
/*
|
||||
* Assigns a new SFTP ID for new requests and assures there is no collision
|
||||
* between them.
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
|
||||
* Copyright (c) 2023 Simon Josefsson <simon@josefsson.org>
|
||||
* Copyright (c) 2025 Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation,
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SNTRUP761_H_
|
||||
#define SNTRUP761_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "curve25519.h"
|
||||
#include "libssh.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CURVE25519
|
||||
#define HAVE_SNTRUP761 1
|
||||
#endif
|
||||
|
||||
extern void crypto_hash_sha512(unsigned char *out,
|
||||
const unsigned char *in,
|
||||
unsigned long long inlen);
|
||||
|
||||
/*
|
||||
* Derived from public domain source, written by (in alphabetical order):
|
||||
* - Daniel J. Bernstein
|
||||
* - Chitchanok Chuengsatiansup
|
||||
* - Tanja Lange
|
||||
* - Christine van Vredendaal
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SNTRUP761_SECRETKEY_SIZE 1763
|
||||
#define SNTRUP761_PUBLICKEY_SIZE 1158
|
||||
#define SNTRUP761_CIPHERTEXT_SIZE 1039
|
||||
#define SNTRUP761_SIZE 32
|
||||
|
||||
typedef void sntrup761_random_func(void *ctx, size_t length, uint8_t *dst);
|
||||
|
||||
void sntrup761_keypair(uint8_t *pk,
|
||||
uint8_t *sk,
|
||||
void *random_ctx,
|
||||
sntrup761_random_func *random);
|
||||
void sntrup761_enc(uint8_t *c,
|
||||
uint8_t *k,
|
||||
const uint8_t *pk,
|
||||
void *random_ctx,
|
||||
sntrup761_random_func *random);
|
||||
void sntrup761_dec(uint8_t *k, const uint8_t *c, const uint8_t *sk);
|
||||
|
||||
typedef unsigned char ssh_sntrup761_pubkey[SNTRUP761_PUBLICKEY_SIZE];
|
||||
typedef unsigned char ssh_sntrup761_privkey[SNTRUP761_SECRETKEY_SIZE];
|
||||
typedef unsigned char ssh_sntrup761_ciphertext[SNTRUP761_CIPHERTEXT_SIZE];
|
||||
|
||||
int ssh_client_sntrup761x25519_init(ssh_session session);
|
||||
void ssh_client_sntrup761x25519_remove_callbacks(ssh_session session);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
void ssh_server_sntrup761x25519_init(ssh_session session);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SNTRUP761_H_ */
|
||||
@@ -129,7 +129,6 @@ int evp_build_pkey(const char* name, OSSL_PARAM_BLD *param_bld, EVP_PKEY **pkey,
|
||||
int evp_dup_dsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
||||
int evp_dup_rsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
||||
int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote);
|
||||
int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote);
|
||||
#endif /* HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -8,4 +8,3 @@ Description: The SSH Library
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs: -L${libdir} -lssh
|
||||
Cflags: -I${includedir}
|
||||
Requires.private: @LIBSSH_PC_REQUIRES_PRIVATE@
|
||||
|
||||
@@ -1 +1 @@
|
||||
4.10.0
|
||||
4.10.3
|
||||
445
src/ABI/libssh-4.10.1.symbols
Normal file
445
src/ABI/libssh-4.10.1.symbols
Normal file
@@ -0,0 +1,445 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_aio_begin_read
|
||||
sftp_aio_begin_write
|
||||
sftp_aio_free
|
||||
sftp_aio_wait_read
|
||||
sftp_aio_wait_write
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_channel_default_data_callback
|
||||
sftp_channel_default_subsystem_request
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_expand_path
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_hardlink
|
||||
sftp_home_directory
|
||||
sftp_init
|
||||
sftp_limits
|
||||
sftp_limits_free
|
||||
sftp_lsetstat
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_state
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_port
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_pty_size_modes
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_dup
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_base64_format
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_file_format
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_request_no_more_sessions
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_issue_banner
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_get_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_set_disconnect_message
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_default
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_publickey_auto_get_current_identity
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_vlog
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
445
src/ABI/libssh-4.10.2.symbols
Normal file
445
src/ABI/libssh-4.10.2.symbols
Normal file
@@ -0,0 +1,445 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_aio_begin_read
|
||||
sftp_aio_begin_write
|
||||
sftp_aio_free
|
||||
sftp_aio_wait_read
|
||||
sftp_aio_wait_write
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_channel_default_data_callback
|
||||
sftp_channel_default_subsystem_request
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_expand_path
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_hardlink
|
||||
sftp_home_directory
|
||||
sftp_init
|
||||
sftp_limits
|
||||
sftp_limits_free
|
||||
sftp_lsetstat
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_state
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_port
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_pty_size_modes
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_dup
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_base64_format
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_file_format
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_request_no_more_sessions
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_issue_banner
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_get_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_set_disconnect_message
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_default
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_publickey_auto_get_current_identity
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_vlog
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
445
src/ABI/libssh-4.10.3.symbols
Normal file
445
src/ABI/libssh-4.10.3.symbols
Normal file
@@ -0,0 +1,445 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_aio_begin_read
|
||||
sftp_aio_begin_write
|
||||
sftp_aio_free
|
||||
sftp_aio_wait_read
|
||||
sftp_aio_wait_write
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_channel_default_data_callback
|
||||
sftp_channel_default_subsystem_request
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_expand_path
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_hardlink
|
||||
sftp_home_directory
|
||||
sftp_init
|
||||
sftp_limits
|
||||
sftp_limits_free
|
||||
sftp_lsetstat
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_state
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_port
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_pty_size_modes
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_dup
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_base64_format
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_file_format
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_request_no_more_sessions
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_issue_banner
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_get_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_set_disconnect_message
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_default
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_publickey_auto_get_current_identity
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_vlog
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -87,7 +87,6 @@ set(libssh_SRCS
|
||||
connector.c
|
||||
crypto_common.c
|
||||
curve25519.c
|
||||
sntrup761.c
|
||||
dh.c
|
||||
ecdh.c
|
||||
error.c
|
||||
@@ -175,13 +174,6 @@ if (WITH_GCRYPT)
|
||||
chachapoly.c
|
||||
)
|
||||
endif (NOT HAVE_GCRYPT_CHACHA_POLY)
|
||||
|
||||
if (HAVE_GCRYPT_CURVE25519)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
curve25519_gcrypt.c
|
||||
)
|
||||
endif(HAVE_GCRYPT_CURVE25519)
|
||||
elseif (WITH_MBEDTLS)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
@@ -198,7 +190,6 @@ elseif (WITH_MBEDTLS)
|
||||
external/fe25519.c
|
||||
external/ge25519.c
|
||||
external/sc25519.c
|
||||
external/sntrup761.c
|
||||
)
|
||||
if (NOT (HAVE_MBEDTLS_CHACHA20_H AND HAVE_MBEDTLS_POLY1305_H))
|
||||
set(libssh_SRCS
|
||||
@@ -208,24 +199,17 @@ elseif (WITH_MBEDTLS)
|
||||
chachapoly.c
|
||||
)
|
||||
endif()
|
||||
if (HAVE_MBEDTLS_CURVE25519)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
curve25519_mbedcrypto.c
|
||||
)
|
||||
endif(HAVE_MBEDTLS_CURVE25519)
|
||||
|
||||
else (WITH_GCRYPT)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
threads/libcrypto.c
|
||||
pki_crypto.c
|
||||
ecdh_crypto.c
|
||||
curve25519_crypto.c
|
||||
getrandom_crypto.c
|
||||
md_crypto.c
|
||||
libcrypto.c
|
||||
dh_crypto.c
|
||||
external/sntrup761.c
|
||||
)
|
||||
if (NOT HAVE_OPENSSL_EVP_CHACHA20)
|
||||
set(libssh_SRCS
|
||||
@@ -277,10 +261,9 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
if (NOT WITH_NACL)
|
||||
if (NOT (HAVE_LIBCRYPTO OR HAVE_MBEDTLS_CURVE25519 OR HAVE_GCRYPT_CURVE25519))
|
||||
if (NOT HAVE_LIBCRYPTO)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
curve25519_fallback.c
|
||||
external/curve25519_ref.c
|
||||
)
|
||||
endif()
|
||||
|
||||
12
src/agent.c
12
src/agent.c
@@ -500,7 +500,6 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
unsigned int type = 0;
|
||||
unsigned int flags = 0;
|
||||
uint32_t dlen;
|
||||
size_t request_len;
|
||||
int rc;
|
||||
|
||||
request = ssh_buffer_new();
|
||||
@@ -526,14 +525,11 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
* - 2 x uint32_t
|
||||
* - 1 x ssh_string (uint8_t + data)
|
||||
*/
|
||||
request_len = sizeof(uint8_t) * 2 +
|
||||
sizeof(uint32_t) * 2 +
|
||||
ssh_string_len(key_blob);
|
||||
/* this can't overflow the uint32_t as the
|
||||
* STRING_SIZE_MAX is (UINT32_MAX >> 8) + 1 */
|
||||
rc = ssh_buffer_allocate_size(request, (uint32_t)request_len);
|
||||
rc = ssh_buffer_allocate_size(request,
|
||||
sizeof(uint8_t) * 2 +
|
||||
sizeof(uint32_t) * 2 +
|
||||
ssh_string_len(key_blob));
|
||||
if (rc < 0) {
|
||||
SSH_STRING_FREE(key_blob);
|
||||
SSH_BUFFER_FREE(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
225
src/auth.c
225
src/auth.c
@@ -463,108 +463,6 @@ fail:
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Adds the server's public key to the authentication request.
|
||||
*
|
||||
* This function is used internally when the hostbound public key authentication
|
||||
* extension is enabled. It export the server's public key and adds it to the
|
||||
* authentication buffer.
|
||||
*
|
||||
* @param[in] session The SSH session.
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
*/
|
||||
static int add_hostbound_pubkey(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
ssh_string server_pubkey_s = NULL;
|
||||
|
||||
if (session == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->current_crypto == NULL ||
|
||||
session->current_crypto->server_pubkey == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid session or server public key");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_pki_export_pubkey_blob(session->current_crypto->server_pubkey,
|
||||
&server_pubkey_s);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_add_ssh_string(session->out_buffer, server_pubkey_s);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
SSH_STRING_FREE(server_pubkey_s);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Build a public key authentication request.
|
||||
*
|
||||
* This helper function creates a SSH2_MSG_USERAUTH_REQUEST message for public
|
||||
* key authentication and adds the server's public key if the hostbound
|
||||
* extension is enabled.
|
||||
*
|
||||
* @param[in] session The SSH session.
|
||||
* @param[in] username The username, may be NULL.
|
||||
* @param[in] auth_type Authentication type (0 for key offer, 1 for actual
|
||||
* auth).
|
||||
* @param[in] sig_type_c The signature algorithm name.
|
||||
* @param[in] pubkey_s The public key string.
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
*/
|
||||
static int build_pubkey_auth_request(ssh_session session,
|
||||
const char *username,
|
||||
int has_signature,
|
||||
const char *sig_type_c,
|
||||
ssh_string pubkey_s)
|
||||
{
|
||||
int rc;
|
||||
const char *auth_method = "publickey";
|
||||
|
||||
if (session->extensions & SSH_EXT_PUBLICKEY_HOSTBOUND) {
|
||||
auth_method = "publickey-hostbound-v00@openssh.com";
|
||||
}
|
||||
|
||||
/* request */
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bsssbsS",
|
||||
SSH2_MSG_USERAUTH_REQUEST,
|
||||
username ? username : session->opts.username,
|
||||
"ssh-connection",
|
||||
auth_method,
|
||||
has_signature, /* private key? */
|
||||
sig_type_c, /* algo */
|
||||
pubkey_s /* public key */
|
||||
);
|
||||
if (rc < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->extensions & SSH_EXT_PUBLICKEY_HOSTBOUND) {
|
||||
rc = add_hostbound_pubkey(session);
|
||||
if (rc < 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to authenticate with the given public key.
|
||||
*
|
||||
@@ -611,17 +509,17 @@ int ssh_userauth_try_publickey(ssh_session session,
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
switch (session->pending_call_state) {
|
||||
case SSH_PENDING_CALL_NONE:
|
||||
break;
|
||||
case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY:
|
||||
goto pending;
|
||||
default:
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Wrong state (%d) during pending SSH call",
|
||||
session->pending_call_state);
|
||||
return SSH_AUTH_ERROR;
|
||||
switch(session->pending_call_state) {
|
||||
case SSH_PENDING_CALL_NONE:
|
||||
break;
|
||||
case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY:
|
||||
goto pending;
|
||||
default:
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Wrong state (%d) during pending SSH call",
|
||||
session->pending_call_state);
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
/* Note, that this is intentionally before checking the signature type
|
||||
@@ -638,15 +536,13 @@ int ssh_userauth_try_publickey(ssh_session session,
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
|
||||
if (sig_type_c == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Invalid key type (unknown)");
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
rc = ssh_key_algorithm_allowed(session, sig_type_c);
|
||||
if (!rc) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
" PUBLICKEY_ACCEPTED_TYPES configuration option",
|
||||
sig_type_c);
|
||||
@@ -654,12 +550,9 @@ int ssh_userauth_try_publickey(ssh_session session,
|
||||
}
|
||||
allowed = ssh_key_size_allowed(session, pubkey);
|
||||
if (!allowed) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The '%s' key type of size %d is not allowed by "
|
||||
"RSA_MIN_SIZE",
|
||||
sig_type_c,
|
||||
ssh_key_size(pubkey));
|
||||
"RSA_MIN_SIZE", sig_type_c, ssh_key_size(pubkey));
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
@@ -670,10 +563,20 @@ int ssh_userauth_try_publickey(ssh_session session,
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Trying signature type %s", sig_type_c);
|
||||
rc = build_pubkey_auth_request(session, username, 0, sig_type_c, pubkey_s);
|
||||
/* request */
|
||||
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
|
||||
SSH2_MSG_USERAUTH_REQUEST,
|
||||
username ? username : session->opts.username,
|
||||
"ssh-connection",
|
||||
"publickey",
|
||||
0, /* private key ? */
|
||||
sig_type_c, /* algo */
|
||||
pubkey_s /* public key */
|
||||
);
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SSH_STRING_FREE(pubkey_s);
|
||||
|
||||
session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
|
||||
@@ -742,17 +645,16 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
switch (session->pending_call_state) {
|
||||
case SSH_PENDING_CALL_NONE:
|
||||
break;
|
||||
case SSH_PENDING_CALL_AUTH_PUBKEY:
|
||||
goto pending;
|
||||
default:
|
||||
ssh_set_error(
|
||||
session,
|
||||
SSH_FATAL,
|
||||
"Bad call during pending SSH call in ssh_userauth_try_publickey");
|
||||
return SSH_AUTH_ERROR;
|
||||
switch(session->pending_call_state) {
|
||||
case SSH_PENDING_CALL_NONE:
|
||||
break;
|
||||
case SSH_PENDING_CALL_AUTH_PUBKEY:
|
||||
goto pending;
|
||||
default:
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Bad call during pending SSH call in ssh_userauth_try_publickey");
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
/* Note, that this is intentionally before checking the signature type
|
||||
@@ -772,15 +674,13 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, key_type);
|
||||
if (sig_type_c == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Invalid key type (unknown)");
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
rc = ssh_key_algorithm_allowed(session, sig_type_c);
|
||||
if (!rc) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
" PUBLICKEY_ACCEPTED_TYPES configuration option",
|
||||
sig_type_c);
|
||||
@@ -788,12 +688,9 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
}
|
||||
allowed = ssh_key_size_allowed(session, privkey);
|
||||
if (!allowed) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The '%s' key type of size %d is not allowed by "
|
||||
"RSA_MIN_SIZE",
|
||||
sig_type_c,
|
||||
ssh_key_size(privkey));
|
||||
"RSA_MIN_SIZE", sig_type_c, ssh_key_size(privkey));
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
@@ -804,7 +701,16 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Sending signature type %s", sig_type_c);
|
||||
rc = build_pubkey_auth_request(session, username, 1, sig_type_c, 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 */
|
||||
sig_type_c, /* algo */
|
||||
str /* public key or cert */
|
||||
);
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -892,16 +798,14 @@ static int ssh_userauth_agent_publickey(ssh_session session,
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
|
||||
if (sig_type_c == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Invalid key type (unknown)");
|
||||
SSH_STRING_FREE(pubkey_s);
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
rc = ssh_key_algorithm_allowed(session, sig_type_c);
|
||||
if (!rc) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
" PUBLICKEY_ACCEPTED_TYPES configuration option",
|
||||
sig_type_c);
|
||||
@@ -910,21 +814,27 @@ static int ssh_userauth_agent_publickey(ssh_session session,
|
||||
}
|
||||
allowed = ssh_key_size_allowed(session, pubkey);
|
||||
if (!allowed) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The '%s' key type of size %d is not allowed by "
|
||||
"RSA_MIN_SIZE",
|
||||
sig_type_c,
|
||||
ssh_key_size(pubkey));
|
||||
"RSA_MIN_SIZE", sig_type_c, ssh_key_size(pubkey));
|
||||
SSH_STRING_FREE(pubkey_s);
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
rc = build_pubkey_auth_request(session, username, 1, sig_type_c, pubkey_s);
|
||||
/* request */
|
||||
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
|
||||
SSH2_MSG_USERAUTH_REQUEST,
|
||||
username ? username : session->opts.username,
|
||||
"ssh-connection",
|
||||
"publickey",
|
||||
1, /* private key */
|
||||
sig_type_c, /* algo */
|
||||
pubkey_s /* public key */
|
||||
);
|
||||
SSH_STRING_FREE(pubkey_s);
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
SSH_STRING_FREE(pubkey_s);
|
||||
|
||||
/* sign the buffer with the private key */
|
||||
sig_blob = ssh_pki_do_sign_agent(session, session->out_buffer, pubkey);
|
||||
@@ -982,7 +892,7 @@ void ssh_agent_state_free(void *data)
|
||||
if (state) {
|
||||
SSH_STRING_FREE_CHAR(state->comment);
|
||||
ssh_key_free(state->pubkey);
|
||||
free(state);
|
||||
free (state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1008,7 +918,8 @@ void ssh_agent_state_free(void *data)
|
||||
* authentication. The username should only be set with ssh_options_set() only
|
||||
* before you connect to the server.
|
||||
*/
|
||||
int ssh_userauth_agent(ssh_session session, const char *username)
|
||||
int ssh_userauth_agent(ssh_session session,
|
||||
const char *username)
|
||||
{
|
||||
int rc = SSH_AUTH_ERROR;
|
||||
struct ssh_agent_state_struct *state = NULL;
|
||||
|
||||
@@ -186,7 +186,7 @@ error:
|
||||
static int to_block4(unsigned long *block, const char *source, int num)
|
||||
{
|
||||
const char *ptr = NULL;
|
||||
size_t i;
|
||||
unsigned int i;
|
||||
|
||||
*block = 0;
|
||||
if (num < 1) {
|
||||
|
||||
73
src/bignum.c
73
src/bignum.c
@@ -27,52 +27,40 @@
|
||||
#include "libssh/bignum.h"
|
||||
#include "libssh/string.h"
|
||||
|
||||
static ssh_string make_bignum_string(bignum num, size_t pad_to_len)
|
||||
{
|
||||
ssh_string ptr = NULL;
|
||||
size_t pad = 0;
|
||||
size_t len = bignum_num_bytes(num);
|
||||
size_t bits = bignum_num_bits(num);
|
||||
ssh_string ssh_make_bignum_string(bignum num) {
|
||||
ssh_string ptr = NULL;
|
||||
size_t pad = 0;
|
||||
size_t len = bignum_num_bytes(num);
|
||||
size_t bits = bignum_num_bits(num);
|
||||
|
||||
if (pad_to_len == 0) {
|
||||
/* If the first bit is set we have a negative number */
|
||||
if (!(bits % 8) && bignum_is_bit_set(num, bits - 1)) {
|
||||
pad++;
|
||||
}
|
||||
} else {
|
||||
if (len > pad_to_len) {
|
||||
return NULL;
|
||||
}
|
||||
pad = pad_to_len - len;
|
||||
}
|
||||
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
|
||||
SSH_LOG(SSH_LOG_TRACE, "%zu bits, %zu bytes, %zu padding", bits, len, pad);
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"%zu bits, %zu bytes, %zu padding",
|
||||
bits, len, pad);
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
|
||||
ptr = ssh_string_new(len + pad);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ptr = ssh_string_new(len + pad);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We have a negative number so we need a leading zero */
|
||||
if (pad) {
|
||||
memset(ptr->data, 0, pad);
|
||||
}
|
||||
/* We have a negative number so we need a leading zero */
|
||||
if (pad) {
|
||||
ptr->data[0] = 0;
|
||||
}
|
||||
|
||||
bignum_bn2bin(num, len, ptr->data + pad);
|
||||
bignum_bn2bin(num, len, ptr->data + pad);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ssh_string ssh_make_bignum_string(bignum num)
|
||||
{
|
||||
return make_bignum_string(num, 0);
|
||||
}
|
||||
|
||||
ssh_string ssh_make_padded_bignum_string(bignum num, size_t pad_len)
|
||||
{
|
||||
return make_bignum_string(num, pad_len);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bignum ssh_make_string_bn(ssh_string string)
|
||||
@@ -83,11 +71,10 @@ bignum ssh_make_string_bn(ssh_string string)
|
||||
#ifdef DEBUG_CRYPTO
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Importing a %zu bits, %zu bytes object ...",
|
||||
len * 8,
|
||||
len);
|
||||
len * 8, len);
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
|
||||
bignum_bin2bn(string->data, (int)len, &bn);
|
||||
bignum_bin2bn(string->data, len, &bn);
|
||||
|
||||
return bn;
|
||||
}
|
||||
@@ -99,9 +86,7 @@ void ssh_print_bignum(const char *name, const_bignum num)
|
||||
if (num != NULL) {
|
||||
bignum_bn2hex(num, &hex);
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"%s value: %s",
|
||||
name,
|
||||
SSH_LOG(SSH_LOG_DEBUG, "%s value: %s", name,
|
||||
(hex == NULL) ? "(null)" : (char *)hex);
|
||||
ssh_crypto_free(hex);
|
||||
}
|
||||
|
||||
@@ -669,8 +669,7 @@ int ssh_bind_config_parse_string(ssh_bind bind, const char *input)
|
||||
{
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
const char *c = input, *line_start = input;
|
||||
unsigned int line_num = 0;
|
||||
size_t line_len;
|
||||
unsigned int line_num = 0, line_len;
|
||||
uint32_t parser_flags;
|
||||
int rv;
|
||||
|
||||
@@ -699,10 +698,8 @@ int ssh_bind_config_parse_string(ssh_bind bind, const char *input)
|
||||
}
|
||||
line_len = c - line_start;
|
||||
if (line_len > MAX_LINE_SIZE - 1) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Line %u too long: %zu characters",
|
||||
line_num,
|
||||
line_len);
|
||||
SSH_LOG(SSH_LOG_WARN, "Line %u too long: %u characters",
|
||||
line_num, line_len);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(line, line_start, line_len);
|
||||
|
||||
94
src/buffer.c
94
src/buffer.c
@@ -407,26 +407,20 @@ void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
int
|
||||
ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
|
||||
struct ssh_string_struct *string)
|
||||
{
|
||||
size_t len;
|
||||
int rc;
|
||||
int ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
|
||||
struct ssh_string_struct *string) {
|
||||
uint32_t len = 0;
|
||||
|
||||
if (string == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (string == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = ssh_string_len(string) + sizeof(uint32_t);
|
||||
/* this can't overflow the uint32_t as the
|
||||
* STRING_SIZE_MAX is (UINT32_MAX >> 8) + 1 */
|
||||
rc = ssh_buffer_add_data(buffer, string, (uint32_t)len);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
len = ssh_string_len(string);
|
||||
if (ssh_buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -829,7 +823,6 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
||||
const char *p = NULL;
|
||||
ssh_string string = NULL;
|
||||
char *cstring = NULL;
|
||||
bignum b = NULL;
|
||||
size_t needed_size = 0;
|
||||
size_t len;
|
||||
size_t count;
|
||||
@@ -874,18 +867,13 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
||||
va_arg(ap, void *);
|
||||
count++; /* increase argument count */
|
||||
break;
|
||||
case 'F':
|
||||
case 'B':
|
||||
b = va_arg(ap, bignum);
|
||||
if (*p == 'F') {
|
||||
/* For padded bignum, we know the exact length */
|
||||
len = va_arg(ap, size_t);
|
||||
count++; /* increase argument count */
|
||||
needed_size += sizeof(uint32_t) + len;
|
||||
} else {
|
||||
/* The bignum bytes + 1 for possible padding */
|
||||
needed_size += sizeof(uint32_t) + bignum_num_bytes(b) + 1;
|
||||
}
|
||||
va_arg(ap, bignum);
|
||||
/*
|
||||
* Use a fixed size for a bignum
|
||||
* (they should normally be around 32)
|
||||
*/
|
||||
needed_size += 64;
|
||||
break;
|
||||
case 't':
|
||||
cstring = va_arg(ap, char *);
|
||||
@@ -991,40 +979,24 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
case 's':
|
||||
cstring = va_arg(ap, char *);
|
||||
len = strlen(cstring);
|
||||
if (len > UINT32_MAX) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
o.dword = (uint32_t)len;
|
||||
rc = ssh_buffer_add_u32(buffer, htonl(o.dword));
|
||||
rc = ssh_buffer_add_u32(buffer, htonl(len));
|
||||
if (rc == SSH_OK){
|
||||
rc = ssh_buffer_add_data(buffer, cstring, o.dword);
|
||||
rc = ssh_buffer_add_data(buffer, cstring, len);
|
||||
}
|
||||
cstring = NULL;
|
||||
break;
|
||||
case 'P':
|
||||
len = va_arg(ap, size_t);
|
||||
if (len > UINT32_MAX) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
o.data = va_arg(ap, void *);
|
||||
count++; /* increase argument count */
|
||||
|
||||
rc = ssh_buffer_add_data(buffer, o.data, (uint32_t)len);
|
||||
rc = ssh_buffer_add_data(buffer, o.data, len);
|
||||
o.data = NULL;
|
||||
break;
|
||||
case 'F':
|
||||
case 'B':
|
||||
b = va_arg(ap, bignum);
|
||||
if (*p == 'F') {
|
||||
len = va_arg(ap, size_t);
|
||||
count++; /* increase argument count */
|
||||
o.string = ssh_make_padded_bignum_string(b, len);
|
||||
} else {
|
||||
o.string = ssh_make_bignum_string(b);
|
||||
}
|
||||
o.string = ssh_make_bignum_string(b);
|
||||
if(o.string == NULL){
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
@@ -1035,11 +1007,7 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
case 't':
|
||||
cstring = va_arg(ap, char *);
|
||||
len = strlen(cstring);
|
||||
if (len > UINT32_MAX) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rc = ssh_buffer_add_data(buffer, cstring, (uint32_t)len);
|
||||
rc = ssh_buffer_add_data(buffer, cstring, len);
|
||||
cstring = NULL;
|
||||
break;
|
||||
default:
|
||||
@@ -1080,8 +1048,6 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
* 'P': size_t, void * (len of data, pointer to data)
|
||||
* only pushes data.
|
||||
* 'B': bignum (pushed as SSH string)
|
||||
* 'F': bignum, size_t (bignum, padded to fixed length,
|
||||
* 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
|
||||
@@ -1221,28 +1187,28 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
if (rlen != 4){
|
||||
break;
|
||||
}
|
||||
u32len = ntohl(u32len);
|
||||
if (u32len > max_len - 1) {
|
||||
len = ntohl(u32len);
|
||||
if (len > max_len - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_validate_length(buffer, u32len);
|
||||
rc = ssh_buffer_validate_length(buffer, len);
|
||||
if (rc != SSH_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
*o.cstring = malloc(u32len + 1);
|
||||
*o.cstring = malloc(len + 1);
|
||||
if (*o.cstring == NULL){
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rlen = ssh_buffer_get_data(buffer, *o.cstring, u32len);
|
||||
if (rlen != u32len) {
|
||||
rlen = ssh_buffer_get_data(buffer, *o.cstring, len);
|
||||
if (rlen != len){
|
||||
SAFE_FREE(*o.cstring);
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
(*o.cstring)[u32len] = '\0';
|
||||
(*o.cstring)[len] = '\0';
|
||||
o.cstring = NULL;
|
||||
rc = SSH_OK;
|
||||
break;
|
||||
@@ -1267,7 +1233,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rlen = ssh_buffer_get_data(buffer, *o.data, (uint32_t)len);
|
||||
rlen = ssh_buffer_get_data(buffer, *o.data, len);
|
||||
if (rlen != len){
|
||||
SAFE_FREE(*o.data);
|
||||
rc = SSH_ERROR;
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#define is_callback_valid(session, cb) \
|
||||
(cb->size > 0 || cb->size <= 1024 * sizeof(void *))
|
||||
(cb->size <= 0 || cb->size > 1024 * sizeof(void *))
|
||||
|
||||
/* LEGACY */
|
||||
static void ssh_legacy_log_callback(int priority,
|
||||
@@ -45,7 +45,8 @@ static void ssh_legacy_log_callback(int priority,
|
||||
log_fn(session, priority, buffer, log_data);
|
||||
}
|
||||
|
||||
void _ssh_remove_legacy_log_cb(void)
|
||||
void
|
||||
_ssh_remove_legacy_log_cb(void)
|
||||
{
|
||||
if (ssh_get_log_callback() == ssh_legacy_log_callback) {
|
||||
_ssh_reset_log_cb();
|
||||
@@ -53,27 +54,26 @@ void _ssh_remove_legacy_log_cb(void)
|
||||
}
|
||||
}
|
||||
|
||||
int ssh_set_callbacks(ssh_session session, ssh_callbacks cb)
|
||||
{
|
||||
if (session == NULL || cb == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
|
||||
if (session == NULL || cb == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (!is_callback_valid(session, cb)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
return SSH_ERROR;
|
||||
};
|
||||
session->common.callbacks = cb;
|
||||
if (is_callback_valid(session, cb)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
return SSH_ERROR;
|
||||
};
|
||||
session->common.callbacks = cb;
|
||||
|
||||
/* LEGACY */
|
||||
if (ssh_get_log_callback() == NULL && cb->log_function) {
|
||||
ssh_set_log_callback(ssh_legacy_log_callback);
|
||||
ssh_set_log_userdata(session);
|
||||
}
|
||||
/* LEGACY */
|
||||
if (ssh_get_log_callback() == NULL && cb->log_function) {
|
||||
ssh_set_log_callback(ssh_legacy_log_callback);
|
||||
ssh_set_log_userdata(session);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssh_add_set_channel_callbacks(ssh_channel channel,
|
||||
@@ -84,11 +84,11 @@ static int ssh_add_set_channel_callbacks(ssh_channel channel,
|
||||
int rc;
|
||||
|
||||
if (channel == NULL || cb == NULL) {
|
||||
return SSH_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session = channel->session;
|
||||
|
||||
if (!is_callback_valid(session, cb)) {
|
||||
if (is_callback_valid(session, cb)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
@@ -96,7 +96,7 @@ static int ssh_add_set_channel_callbacks(ssh_channel channel,
|
||||
};
|
||||
if (channel->callbacks == NULL) {
|
||||
channel->callbacks = ssh_list_new();
|
||||
if (channel->callbacks == NULL) {
|
||||
if (channel->callbacks == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -124,12 +124,12 @@ int ssh_remove_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
|
||||
{
|
||||
struct ssh_iterator *it = NULL;
|
||||
|
||||
if (channel == NULL || channel->callbacks == NULL) {
|
||||
if (channel == NULL || channel->callbacks == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
it = ssh_list_find(channel->callbacks, cb);
|
||||
if (it == NULL) {
|
||||
if (it == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -138,19 +138,19 @@ int ssh_remove_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb)
|
||||
{
|
||||
if (session == NULL || cb == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (!is_callback_valid(session, cb)) {
|
||||
int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb){
|
||||
if (session == NULL || cb == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (is_callback_valid(session, cb)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid callback passed in (badly initialized)");
|
||||
return SSH_ERROR;
|
||||
};
|
||||
session->server_callbacks = cb;
|
||||
session->server_callbacks = cb;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
1703
src/channels.c
1703
src/channels.c
File diff suppressed because it is too large
Load Diff
59
src/client.c
59
src/client.c
@@ -226,7 +226,7 @@ int ssh_send_banner(ssh_session session, int server)
|
||||
terminator);
|
||||
}
|
||||
|
||||
rc = ssh_socket_write(session->socket, buffer, (uint32_t)strlen(buffer));
|
||||
rc = ssh_socket_write(session->socket, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
goto end;
|
||||
}
|
||||
@@ -235,8 +235,8 @@ int ssh_send_banner(ssh_session session, int server)
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_OUT,
|
||||
buffer,
|
||||
(uint32_t)strlen(buffer),
|
||||
(uint32_t)strlen(buffer));
|
||||
strlen(buffer),
|
||||
strlen(buffer));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -254,52 +254,45 @@ end:
|
||||
*/
|
||||
int dh_handshake(ssh_session session)
|
||||
{
|
||||
int rc = SSH_AGAIN;
|
||||
int rc = SSH_AGAIN;
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"dh_handshake_state = %d, kex_type = %d",
|
||||
session->dh_handshake_state,
|
||||
session->next_crypto->kex_type);
|
||||
SSH_LOG(SSH_LOG_TRACE, "dh_handshake_state = %d, kex_type = %d",
|
||||
session->dh_handshake_state, session->next_crypto->kex_type);
|
||||
|
||||
switch (session->dh_handshake_state) {
|
||||
switch (session->dh_handshake_state) {
|
||||
case DH_STATE_INIT:
|
||||
switch (session->next_crypto->kex_type) {
|
||||
switch(session->next_crypto->kex_type){
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
case SSH_KEX_DH_GROUP14_SHA256:
|
||||
case SSH_KEX_DH_GROUP16_SHA512:
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
rc = ssh_client_dh_init(session);
|
||||
break;
|
||||
rc = ssh_client_dh_init(session);
|
||||
break;
|
||||
#ifdef WITH_GEX
|
||||
case SSH_KEX_DH_GEX_SHA1:
|
||||
case SSH_KEX_DH_GEX_SHA256:
|
||||
rc = ssh_client_dhgex_init(session);
|
||||
break;
|
||||
rc = ssh_client_dhgex_init(session);
|
||||
break;
|
||||
#endif /* WITH_GEX */
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
rc = ssh_client_ecdh_init(session);
|
||||
break;
|
||||
rc = ssh_client_ecdh_init(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_CURVE25519
|
||||
case SSH_KEX_CURVE25519_SHA256:
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
rc = ssh_client_curve25519_init(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_SNTRUP761
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
|
||||
rc = ssh_client_sntrup761x25519_init(session);
|
||||
break;
|
||||
rc = ssh_client_curve25519_init(session);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
case DH_STATE_INIT_SENT:
|
||||
/* wait until ssh_packet_dh_reply is called */
|
||||
break;
|
||||
@@ -307,17 +300,15 @@ int dh_handshake(ssh_session session)
|
||||
/* wait until ssh_packet_newkeys is called */
|
||||
break;
|
||||
case DH_STATE_FINISHED:
|
||||
return SSH_OK;
|
||||
return SSH_OK;
|
||||
default:
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid state in dh_handshake(): %d",
|
||||
session->dh_handshake_state);
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid state in dh_handshake(): %d",
|
||||
session->dh_handshake_state);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ssh_service_request_termination(void *s)
|
||||
|
||||
65
src/config.c
65
src/config.c
@@ -1451,32 +1451,6 @@ ssh_config_parse_line(ssh_session session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @brief Parse configuration from a file pointer
|
||||
*
|
||||
* @params[in] session The ssh session
|
||||
* @params[in] fp A valid file pointer
|
||||
* @params[in] global Whether the config is global or not
|
||||
*
|
||||
* @returns 0 on successful parsing the configuration file, -1 on error
|
||||
*/
|
||||
int ssh_config_parse(ssh_session session, FILE *fp, bool global)
|
||||
{
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
int parsing, rv;
|
||||
|
||||
parsing = 1;
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
count++;
|
||||
rv = ssh_config_parse_line(session, line, count, &parsing, 0, global);
|
||||
if (rv < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @brief Parse configuration file and set the options to the given session
|
||||
*
|
||||
* @params[in] session The ssh session
|
||||
@@ -1486,32 +1460,36 @@ int ssh_config_parse(ssh_session session, FILE *fp, bool global)
|
||||
*/
|
||||
int ssh_config_parse_file(ssh_session session, const char *filename)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
int rv;
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
FILE *f = NULL;
|
||||
int parsing, rv;
|
||||
bool global = 0;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = strcmp(filename, GLOBAL_CLIENT_CONFIG);
|
||||
#ifdef USR_GLOBAL_CLIENT_CONFIG
|
||||
if (rv != 0) {
|
||||
rv = strcmp(filename, USR_GLOBAL_CLIENT_CONFIG);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rv == 0) {
|
||||
global = true;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename);
|
||||
|
||||
rv = ssh_config_parse(session, fp, global);
|
||||
parsing = 1;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
rv = ssh_config_parse_line(session, line, count, &parsing, 0, global);
|
||||
if (rv < 0) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return rv;
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @brief Parse configuration string and set the options to the given session
|
||||
@@ -1526,8 +1504,7 @@ int ssh_config_parse_string(ssh_session session, const char *input)
|
||||
{
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
const char *c = input, *line_start = input;
|
||||
unsigned int line_num = 0;
|
||||
size_t line_len;
|
||||
unsigned int line_num = 0, line_len;
|
||||
int parsing, rv;
|
||||
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Reading configuration data from string:");
|
||||
@@ -1549,10 +1526,8 @@ int ssh_config_parse_string(ssh_session session, const char *input)
|
||||
}
|
||||
line_len = c - line_start;
|
||||
if (line_len > MAX_LINE_SIZE - 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Line %u too long: %zu characters",
|
||||
line_num,
|
||||
line_len);
|
||||
SSH_LOG(SSH_LOG_TRACE, "Line %u too long: %u characters",
|
||||
line_num, line_len);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(line, line_start, line_len);
|
||||
|
||||
@@ -209,8 +209,7 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
bind_itr != NULL;
|
||||
bind_itr = bind_itr->ai_next)
|
||||
{
|
||||
rc = bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen);
|
||||
if (rc < 0) {
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s",
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
|
||||
@@ -264,17 +264,17 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
|
||||
}
|
||||
connector->in_available = 1; /* Don't poll on it */
|
||||
return;
|
||||
} else if (r > 0) {
|
||||
} else if (r> 0) {
|
||||
/* loop around ssh_channel_write in case our window reduced due to a race */
|
||||
while (total != r){
|
||||
if (connector->out_flags & SSH_CONNECTOR_STDOUT) {
|
||||
w = ssh_channel_write(connector->out_channel,
|
||||
buffer + total,
|
||||
(uint32_t)(r - total));
|
||||
r - total);
|
||||
} else {
|
||||
w = ssh_channel_write_stderr(connector->out_channel,
|
||||
buffer + total,
|
||||
(uint32_t)(r - total));
|
||||
r - total);
|
||||
}
|
||||
if (w == SSH_ERROR) {
|
||||
return;
|
||||
@@ -294,7 +294,7 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
|
||||
while (total < r) {
|
||||
w = ssh_connector_fd_write(connector,
|
||||
buffer + total,
|
||||
(uint32_t)(r - total));
|
||||
r - total);
|
||||
if (w < 0) {
|
||||
ssh_connector_except(connector, connector->out_fd);
|
||||
return;
|
||||
@@ -340,9 +340,8 @@ ssh_connector_fd_out_cb(ssh_connector connector)
|
||||
} else if (r > 0) {
|
||||
/* loop around write in case the write blocks even for CHUNKSIZE bytes */
|
||||
while (total != r) {
|
||||
w = ssh_connector_fd_write(connector,
|
||||
buffer + total,
|
||||
(uint32_t)(r - total));
|
||||
w = ssh_connector_fd_write(connector, buffer + total,
|
||||
r - total);
|
||||
if (w < 0) {
|
||||
ssh_connector_except(connector, connector->out_fd);
|
||||
return;
|
||||
@@ -477,11 +476,9 @@ static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
ssh_connector_except_channel(connector, connector->out_channel);
|
||||
}
|
||||
} else if (connector->out_fd != SSH_INVALID_SOCKET) {
|
||||
ssize_t ws = ssh_connector_fd_write(connector, data, len);
|
||||
if (ws < 0) {
|
||||
w = ssh_connector_fd_write(connector, data, len);
|
||||
if (w < 0)
|
||||
ssh_connector_except(connector, connector->out_fd);
|
||||
}
|
||||
w = (int)ws;
|
||||
} else {
|
||||
ssh_set_error(session, SSH_FATAL, "output socket or channel closed");
|
||||
return SSH_ERROR;
|
||||
|
||||
340
src/curve25519.c
340
src/curve25519.c
@@ -26,43 +26,119 @@
|
||||
#include "libssh/curve25519.h"
|
||||
#ifdef HAVE_CURVE25519
|
||||
|
||||
#include "libssh/bignum.h"
|
||||
#ifdef WITH_NACL
|
||||
#include "nacl/crypto_scalarmult_curve25519.h"
|
||||
#endif
|
||||
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply);
|
||||
|
||||
static ssh_packet_callback dh_client_callbacks[] = {
|
||||
ssh_packet_client_curve25519_reply,
|
||||
ssh_packet_client_curve25519_reply
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_curve25519_client_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_REPLY,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = dh_client_callbacks,
|
||||
.user = NULL,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
int ssh_curve25519_create_k(ssh_session session, ssh_curve25519_pubkey k)
|
||||
static int ssh_curve25519_init(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
|
||||
size_t pkey_len = CURVE25519_PRIVKEY_SIZE;
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie,
|
||||
16);
|
||||
ssh_log_hexdump("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie,
|
||||
16);
|
||||
#endif
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = curve25519_do_create_k(session, k);
|
||||
return rc;
|
||||
rc = EVP_PKEY_keygen_init(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 keygen: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen(pctx, &pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to generate X25519 keys: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey,
|
||||
session->next_crypto->curve25519_server_pubkey,
|
||||
&pubkey_len);
|
||||
} else {
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey,
|
||||
session->next_crypto->curve25519_client_pubkey,
|
||||
&pubkey_len);
|
||||
}
|
||||
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get X25519 raw public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_get_raw_private_key(pkey,
|
||||
session->next_crypto->curve25519_privkey,
|
||||
&pkey_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get X25519 raw private key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
#else
|
||||
rc = ssh_get_random(session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (rc != 1) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
} else {
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
}
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -104,120 +180,193 @@ void ssh_client_curve25519_remove_callbacks(ssh_session session)
|
||||
static int ssh_curve25519_build_k(ssh_session session)
|
||||
{
|
||||
ssh_curve25519_pubkey k;
|
||||
int rc;
|
||||
|
||||
rc = ssh_curve25519_create_k(session, k);
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL, *pubkey = NULL;
|
||||
size_t shared_key_len = sizeof(k);
|
||||
int rc, ret = SSH_ERROR;
|
||||
|
||||
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE);
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create X25519 EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
bignum_bin2bn(k,
|
||||
CURVE25519_PUBKEY_SIZE,
|
||||
&session->next_crypto->shared_secret);
|
||||
pctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_init(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 key derivation: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (session->server) {
|
||||
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_client_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
} else {
|
||||
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
|
||||
session->next_crypto->curve25519_server_pubkey,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
}
|
||||
if (pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create X25519 public key EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_set_peer(pctx, pubkey);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to set peer X25519 public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive(pctx, k, &shared_key_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to derive X25519 shared secret: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
ret = SSH_OK;
|
||||
out:
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_free(pubkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if (ret == SSH_ERROR) {
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
if (session->server) {
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
} else {
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
}
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_log_hexdump("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_log_hexdump("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
#endif
|
||||
|
||||
return SSH_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
|
||||
* a SSH_MSG_NEWKEYS
|
||||
*/
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply)
|
||||
{
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_client_curve25519_remove_callbacks(session);
|
||||
ssh_client_curve25519_remove_callbacks(session);
|
||||
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No public key in packet");
|
||||
goto error;
|
||||
}
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
|
||||
SSH_STRING_FREE(pubkey_blob);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to import next public key");
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
|
||||
SSH_STRING_FREE(pubkey_blob);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to import next public key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
q_s_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_s_string == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No Q_S ECC point in packet");
|
||||
goto error;
|
||||
}
|
||||
if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Incorrect size for server Curve25519 public key: %zu",
|
||||
ssh_string_len(q_s_string));
|
||||
SSH_STRING_FREE(q_s_string);
|
||||
goto error;
|
||||
}
|
||||
memcpy(session->next_crypto->curve25519_server_pubkey,
|
||||
ssh_string_data(q_s_string),
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
SSH_STRING_FREE(q_s_string);
|
||||
q_s_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_s_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
|
||||
goto error;
|
||||
}
|
||||
if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE){
|
||||
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
|
||||
(int)ssh_string_len(q_s_string));
|
||||
SSH_STRING_FREE(q_s_string);
|
||||
goto error;
|
||||
}
|
||||
memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE);
|
||||
SSH_STRING_FREE(q_s_string);
|
||||
|
||||
signature = ssh_buffer_get_ssh_string(packet);
|
||||
if (signature == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->dh_server_signature = signature;
|
||||
signature = NULL; /* ownership changed */
|
||||
/* TODO: verify signature now instead of waiting for NEWKEYS */
|
||||
if (ssh_curve25519_build_k(session) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
}
|
||||
signature = ssh_buffer_get_ssh_string(packet);
|
||||
if (signature == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No signature in packet");
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->dh_server_signature = signature;
|
||||
signature=NULL; /* ownership changed */
|
||||
/* TODO: verify signature now instead of waiting for NEWKEYS */
|
||||
if (ssh_curve25519_build_k(session) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
rc = ssh_packet_send_newkeys(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
/* Send the MSG_NEWKEYS */
|
||||
rc = ssh_packet_send_newkeys(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
error:
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init);
|
||||
|
||||
static ssh_packet_callback dh_server_callbacks[] = {
|
||||
ssh_packet_server_curve25519_init,
|
||||
static ssh_packet_callback dh_server_callbacks[]= {
|
||||
ssh_packet_server_curve25519_init
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_curve25519_server_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_INIT,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = dh_server_callbacks,
|
||||
.user = NULL,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief sets up the curve25519-sha256@libssh.org kex callbacks
|
||||
*/
|
||||
void ssh_server_curve25519_init(ssh_session session)
|
||||
{
|
||||
void ssh_server_curve25519_init(ssh_session session){
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_curve25519_server_callbacks);
|
||||
}
|
||||
@@ -225,8 +374,7 @@ void ssh_server_curve25519_init(ssh_session session)
|
||||
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
* SSH_MSG_KEXDH_REPLY
|
||||
*/
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init)
|
||||
{
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string = NULL;
|
||||
ssh_string q_s_string = NULL;
|
||||
@@ -245,10 +393,10 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init)
|
||||
/* Extract the client pubkey from the init packet */
|
||||
q_c_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_c_string == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet");
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||
goto error;
|
||||
}
|
||||
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE) {
|
||||
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Incorrect size for server Curve25519 public key: %zu",
|
||||
@@ -257,8 +405,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init)
|
||||
}
|
||||
|
||||
memcpy(session->next_crypto->curve25519_client_pubkey,
|
||||
ssh_string_data(q_c_string),
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
|
||||
SSH_STRING_FREE(q_c_string);
|
||||
|
||||
/* Build server's key pair */
|
||||
@@ -300,7 +447,8 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init)
|
||||
}
|
||||
|
||||
/* add host's public key */
|
||||
rc = ssh_buffer_add_ssh_string(session->out_buffer, server_pubkey_blob);
|
||||
rc = ssh_buffer_add_ssh_string(session->out_buffer,
|
||||
server_pubkey_blob);
|
||||
SSH_STRING_FREE(server_pubkey_blob);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
@@ -361,7 +509,7 @@ error:
|
||||
SSH_STRING_FREE(q_c_string);
|
||||
SSH_STRING_FREE(q_s_string);
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* curve25519_crypto.c - Curve25519 ECDH functions for key exchange (OpenSSL)
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 2.1 of the License.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
int ssh_curve25519_init(ssh_session session)
|
||||
{
|
||||
ssh_curve25519_pubkey *pubkey_loc = NULL;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
|
||||
int rc;
|
||||
|
||||
if (session->server) {
|
||||
pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
|
||||
} else {
|
||||
pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
|
||||
}
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen_init(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 keygen: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_keygen(pctx, &pkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to generate X25519 keys: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey, *pubkey_loc, &pubkey_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to get X25519 raw public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_PKEY_free(pkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
session->next_crypto->curve25519_privkey = pkey;
|
||||
pkey = NULL;
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k)
|
||||
{
|
||||
ssh_curve25519_pubkey *peer_pubkey_loc = NULL;
|
||||
int rc, ret = SSH_ERROR;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
EVP_PKEY *pkey = NULL, *pubkey = NULL;
|
||||
size_t shared_key_len = CURVE25519_PUBKEY_SIZE;
|
||||
|
||||
if (session->server) {
|
||||
peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
|
||||
} else {
|
||||
peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
|
||||
}
|
||||
|
||||
pkey = session->next_crypto->curve25519_privkey;
|
||||
if (pkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create X25519 EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
pctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||
if (pctx == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_init(pctx);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to initialize X25519 key derivation: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519,
|
||||
NULL,
|
||||
*peer_pubkey_loc,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
if (pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create X25519 public key EVP_PKEY: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive_set_peer(pctx, pubkey);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to set peer X25519 public key: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EVP_PKEY_derive(pctx, k, &shared_key_len);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to derive X25519 shared secret: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
ret = SSH_OK;
|
||||
|
||||
out:
|
||||
EVP_PKEY_free(pubkey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* curve25519_fallback.c - Curve25519 ECDH functions for key exchange
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 2.1 of the License.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#ifdef WITH_NACL
|
||||
#include "nacl/crypto_scalarmult_curve25519.h"
|
||||
#endif
|
||||
|
||||
int ssh_curve25519_init(ssh_session session)
|
||||
{
|
||||
ssh_curve25519_pubkey *pubkey_loc = NULL;
|
||||
int rc;
|
||||
|
||||
if (session->server) {
|
||||
pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
|
||||
} else {
|
||||
pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
|
||||
}
|
||||
|
||||
rc = ssh_get_random(session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE,
|
||||
1);
|
||||
if (rc != 1) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
crypto_scalarmult_base(*pubkey_loc,
|
||||
session->next_crypto->curve25519_privkey);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k)
|
||||
{
|
||||
ssh_curve25519_pubkey *peer_pubkey_loc = NULL;
|
||||
|
||||
if (session->server) {
|
||||
peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
|
||||
} else {
|
||||
peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
|
||||
}
|
||||
|
||||
crypto_scalarmult(k,
|
||||
session->next_crypto->curve25519_privkey,
|
||||
*peer_pubkey_loc);
|
||||
return SSH_OK;
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* curve25519_gcrypt.c - Curve25519 ECDH functions for key exchange (Gcrypt)
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be>
|
||||
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 2.1 of the License.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
int ssh_curve25519_init(ssh_session session)
|
||||
{
|
||||
ssh_curve25519_pubkey *pubkey_loc = NULL;
|
||||
gcry_error_t gcry_err;
|
||||
gcry_sexp_t param = NULL, keypair_sexp = NULL;
|
||||
ssh_string pubkey = NULL;
|
||||
const char *pubkey_data = NULL;
|
||||
int ret = SSH_ERROR;
|
||||
|
||||
if (session->server) {
|
||||
pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
|
||||
} else {
|
||||
pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
|
||||
}
|
||||
|
||||
gcry_err =
|
||||
gcry_sexp_build(¶m, NULL, "(genkey (ecdh (curve Curve25519)))");
|
||||
if (gcry_err != GPG_ERR_NO_ERROR) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create keypair sexp: %s",
|
||||
gcry_strerror(gcry_err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
gcry_err = gcry_pk_genkey(&keypair_sexp, param);
|
||||
if (gcry_err != GPG_ERR_NO_ERROR) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to generate keypair: %s",
|
||||
gcry_strerror(gcry_err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Extract the public key */
|
||||
pubkey = ssh_sexp_extract_mpi(keypair_sexp,
|
||||
"q",
|
||||
GCRYMPI_FMT_USG,
|
||||
GCRYMPI_FMT_STD);
|
||||
if (pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to extract public key: %s",
|
||||
gcry_strerror(gcry_err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Store the public key in the session */
|
||||
/* The first byte should be 0x40 indicating that the point is compressed, so
|
||||
* we skip storing it */
|
||||
pubkey_data = (char *)ssh_string_data(pubkey);
|
||||
if (ssh_string_len(pubkey) != CURVE25519_PUBKEY_SIZE + 1 ||
|
||||
pubkey_data[0] != 0x40) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid public key with length: %zu",
|
||||
ssh_string_len(pubkey));
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(*pubkey_loc, pubkey_data + 1, CURVE25519_PUBKEY_SIZE);
|
||||
|
||||
/* Store the private key */
|
||||
session->next_crypto->curve25519_privkey = keypair_sexp;
|
||||
keypair_sexp = NULL;
|
||||
ret = SSH_OK;
|
||||
|
||||
out:
|
||||
ssh_string_burn(pubkey);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
gcry_sexp_release(param);
|
||||
gcry_sexp_release(keypair_sexp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k)
|
||||
{
|
||||
ssh_curve25519_pubkey *peer_pubkey_loc = NULL;
|
||||
gcry_error_t gcry_err;
|
||||
gcry_sexp_t pubkey_sexp = NULL, privkey_data_sexp = NULL,
|
||||
result_sexp = NULL;
|
||||
ssh_string shared_secret = NULL, privkey = NULL;
|
||||
char *shared_secret_data = NULL;
|
||||
int ret = SSH_ERROR;
|
||||
|
||||
if (session->server) {
|
||||
peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
|
||||
} else {
|
||||
peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
|
||||
}
|
||||
|
||||
gcry_err = gcry_sexp_build(
|
||||
&pubkey_sexp,
|
||||
NULL,
|
||||
"(key-data(public-key (ecdh (curve Curve25519) (q %b))))",
|
||||
CURVE25519_PUBKEY_SIZE,
|
||||
*peer_pubkey_loc);
|
||||
if (gcry_err != GPG_ERR_NO_ERROR) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create peer public key sexp: %s",
|
||||
gcry_strerror(gcry_err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
privkey = ssh_sexp_extract_mpi(session->next_crypto->curve25519_privkey,
|
||||
"d",
|
||||
GCRYMPI_FMT_USG,
|
||||
GCRYMPI_FMT_STD);
|
||||
if (privkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to extract private key");
|
||||
goto out;
|
||||
}
|
||||
|
||||
gcry_err = gcry_sexp_build(&privkey_data_sexp,
|
||||
NULL,
|
||||
"(data(flags raw)(value %b))",
|
||||
ssh_string_len(privkey),
|
||||
ssh_string_data(privkey));
|
||||
if (gcry_err != GPG_ERR_NO_ERROR) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to create private key sexp: %s",
|
||||
gcry_strerror(gcry_err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
gcry_err = gcry_pk_encrypt(&result_sexp, privkey_data_sexp, pubkey_sexp);
|
||||
if (gcry_err != GPG_ERR_NO_ERROR) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to compute shared secret: %s",
|
||||
gcry_strerror(gcry_err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
shared_secret = ssh_sexp_extract_mpi(result_sexp,
|
||||
"s",
|
||||
GCRYMPI_FMT_USG,
|
||||
GCRYMPI_FMT_USG);
|
||||
if (shared_secret == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to extract shared secret");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Copy the shared secret to the output buffer */
|
||||
/* The first byte should be 0x40 indicating that it is a compressed point,
|
||||
* so we skip it */
|
||||
shared_secret_data = (char *)ssh_string_data(shared_secret);
|
||||
if (ssh_string_len(shared_secret) != CURVE25519_PUBKEY_SIZE + 1 ||
|
||||
shared_secret_data[0] != 0x40) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid shared secret with length: %zu",
|
||||
ssh_string_len(shared_secret));
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(k, shared_secret_data + 1, CURVE25519_PUBKEY_SIZE);
|
||||
|
||||
ret = SSH_OK;
|
||||
gcry_sexp_release(session->next_crypto->curve25519_privkey);
|
||||
session->next_crypto->curve25519_privkey = NULL;
|
||||
|
||||
out:
|
||||
ssh_string_burn(shared_secret);
|
||||
SSH_STRING_FREE(shared_secret);
|
||||
ssh_string_burn(privkey);
|
||||
SSH_STRING_FREE(privkey);
|
||||
gcry_sexp_release(privkey_data_sexp);
|
||||
gcry_sexp_release(pubkey_sexp);
|
||||
gcry_sexp_release(result_sexp);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* curve25519_mbedcrypto.c - Curve25519 ECDH functions for key exchange
|
||||
* (MbedTLS)
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be>
|
||||
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.com>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 2.1 of the License.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "mbedcrypto-compat.h"
|
||||
|
||||
#include <mbedtls/ecdh.h>
|
||||
#include <mbedtls/error.h>
|
||||
|
||||
int ssh_curve25519_init(ssh_session session)
|
||||
{
|
||||
ssh_curve25519_pubkey *pubkey_loc = NULL;
|
||||
mbedtls_ecdh_context ecdh_ctx;
|
||||
mbedtls_ecdh_params *ecdh_params = NULL;
|
||||
mbedtls_ctr_drbg_context *ctr_drbg = NULL;
|
||||
int rc, ret = SSH_ERROR;
|
||||
char error_buf[128];
|
||||
|
||||
if (session->server) {
|
||||
pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
|
||||
} else {
|
||||
pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
|
||||
}
|
||||
|
||||
ctr_drbg = ssh_get_mbedtls_ctr_drbg_context();
|
||||
|
||||
mbedtls_ecdh_init(&ecdh_ctx);
|
||||
rc = mbedtls_ecdh_setup(&ecdh_ctx, MBEDTLS_ECP_DP_CURVE25519);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to setup X25519 context: %s", error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ecdh_params = &MBEDTLS_ECDH_PARAMS(ecdh_ctx);
|
||||
|
||||
rc = mbedtls_ecdh_gen_public(&ecdh_params->MBEDTLS_ECDH_PRIVATE(grp),
|
||||
&ecdh_params->MBEDTLS_ECDH_PRIVATE(d),
|
||||
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Q),
|
||||
mbedtls_ctr_drbg_random,
|
||||
ctr_drbg);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to generate X25519 keypair: %s",
|
||||
error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mbedtls_mpi_write_binary_le(&ecdh_params->MBEDTLS_ECDH_PRIVATE(d),
|
||||
session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to write X25519 private key: %s",
|
||||
error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mbedtls_mpi_write_binary_le(
|
||||
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Q).MBEDTLS_ECDH_PRIVATE(X),
|
||||
*pubkey_loc,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to write X25519 public key: %s",
|
||||
error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = SSH_OK;
|
||||
|
||||
out:
|
||||
mbedtls_ecdh_free(&ecdh_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k)
|
||||
{
|
||||
ssh_curve25519_pubkey *peer_pubkey_loc = NULL;
|
||||
int rc, ret = SSH_ERROR;
|
||||
mbedtls_ecdh_context ecdh_ctx;
|
||||
mbedtls_ecdh_params *ecdh_params = NULL;
|
||||
mbedtls_ctr_drbg_context *ctr_drbg = NULL;
|
||||
char error_buf[128];
|
||||
|
||||
if (session->server) {
|
||||
peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
|
||||
} else {
|
||||
peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
|
||||
}
|
||||
|
||||
ctr_drbg = ssh_get_mbedtls_ctr_drbg_context();
|
||||
|
||||
mbedtls_ecdh_init(&ecdh_ctx);
|
||||
rc = mbedtls_ecdh_setup(&ecdh_ctx, MBEDTLS_ECP_DP_CURVE25519);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to setup X25519 context: %s", error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ecdh_params = &MBEDTLS_ECDH_PARAMS(ecdh_ctx);
|
||||
|
||||
rc = mbedtls_mpi_read_binary_le(&ecdh_params->MBEDTLS_ECDH_PRIVATE(d),
|
||||
session->next_crypto->curve25519_privkey,
|
||||
CURVE25519_PRIVKEY_SIZE);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to read private key: %s", error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mbedtls_mpi_read_binary_le(
|
||||
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Qp).MBEDTLS_ECDH_PRIVATE(X),
|
||||
*peer_pubkey_loc,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to read peer public key: %s", error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mbedtls_mpi_lset(
|
||||
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Qp).MBEDTLS_ECDH_PRIVATE(Z),
|
||||
1);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to set Z coordinate: %s", error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mbedtls_ecdh_compute_shared(&ecdh_params->MBEDTLS_ECDH_PRIVATE(grp),
|
||||
&ecdh_params->MBEDTLS_ECDH_PRIVATE(z),
|
||||
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Qp),
|
||||
&ecdh_params->MBEDTLS_ECDH_PRIVATE(d),
|
||||
mbedtls_ctr_drbg_random,
|
||||
ctr_drbg);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to compute shared secret: %s",
|
||||
error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = mbedtls_mpi_write_binary_le(&ecdh_params->MBEDTLS_ECDH_PRIVATE(z),
|
||||
k,
|
||||
CURVE25519_PUBKEY_SIZE);
|
||||
if (rc != 0) {
|
||||
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to write shared secret: %s", error_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = SSH_OK;
|
||||
|
||||
out:
|
||||
mbedtls_ecdh_free(&ecdh_ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -416,9 +416,6 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli,
|
||||
do {
|
||||
firstbyte = getc(moduli);
|
||||
} while(firstbyte != '\n' && firstbyte != EOF);
|
||||
if (firstbyte == EOF) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (firstbyte == EOF) {
|
||||
@@ -442,9 +439,6 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli,
|
||||
do {
|
||||
firstbyte = getc(moduli);
|
||||
} while(firstbyte != '\n' && firstbyte != EOF);
|
||||
if (firstbyte == EOF) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -407,6 +407,11 @@ int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
|
||||
struct dh_ctx *ctx = NULL;
|
||||
int rc;
|
||||
|
||||
/* Cleanup any previously allocated dh_ctx */
|
||||
if (crypto->dh_ctx != NULL) {
|
||||
ssh_dh_cleanup(crypto);
|
||||
}
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return SSH_ERROR;
|
||||
@@ -592,7 +597,7 @@ int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
*dest = BN_bin2bn(kstring, (int)klen, NULL);
|
||||
*dest = BN_bin2bn(kstring, klen, NULL);
|
||||
if (*dest == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
|
||||
@@ -237,6 +237,11 @@ int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
|
||||
struct dh_ctx *ctx = NULL;
|
||||
int rc;
|
||||
|
||||
/* Cleanup any previously allocated dh_ctx */
|
||||
if (crypto->dh_ctx != NULL) {
|
||||
ssh_dh_cleanup(crypto);
|
||||
}
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return SSH_ERROR;
|
||||
|
||||
@@ -191,6 +191,17 @@ static ssh_string ssh_ecdh_generate(ssh_session session)
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Free any previously allocated privkey */
|
||||
if (session->next_crypto->ecdh_privkey != NULL) {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
EC_KEY_free(session->next_crypto->ecdh_privkey);
|
||||
#else
|
||||
EVP_PKEY_free(session->next_crypto->ecdh_privkey);
|
||||
#endif
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
}
|
||||
|
||||
session->next_crypto->ecdh_privkey = key;
|
||||
return pubkey_string;
|
||||
}
|
||||
@@ -219,6 +230,7 @@ int ssh_client_ecdh_init(ssh_session session)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ssh_string_free(session->next_crypto->ecdh_client_pubkey);
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
|
||||
/* register the packet callbacks */
|
||||
|
||||
@@ -101,8 +101,15 @@ int ssh_client_ecdh_init(ssh_session session)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Free any previously allocated privkey */
|
||||
if (session->next_crypto->ecdh_privkey != NULL) {
|
||||
gcry_sexp_release(session->next_crypto->ecdh_privkey);
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
}
|
||||
session->next_crypto->ecdh_privkey = key;
|
||||
key = NULL;
|
||||
|
||||
SSH_STRING_FREE(session->next_crypto->ecdh_client_pubkey);
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
client_pubkey = NULL;
|
||||
|
||||
|
||||
@@ -70,6 +70,12 @@ int ssh_client_ecdh_init(ssh_session session)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Free any previously allocated privkey */
|
||||
if (session->next_crypto->ecdh_privkey != NULL) {
|
||||
mbedtls_ecp_keypair_free(session->next_crypto->ecdh_privkey);
|
||||
SAFE_FREE(session->next_crypto->ecdh_privkey);
|
||||
}
|
||||
|
||||
session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
|
||||
if (session->next_crypto->ecdh_privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
@@ -110,6 +116,7 @@ int ssh_client_ecdh_init(ssh_session session)
|
||||
goto out;
|
||||
}
|
||||
|
||||
SSH_STRING_FREE(session->next_crypto->ecdh_client_pubkey);
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
client_pubkey = NULL;
|
||||
|
||||
|
||||
1060
src/external/sntrup761.c
vendored
1060
src/external/sntrup761.c
vendored
File diff suppressed because it is too large
Load Diff
@@ -63,7 +63,7 @@ static int ssh_gets(const char *prompt, char *buf, size_t len, int verify)
|
||||
fprintf(stdout, "%s", prompt);
|
||||
}
|
||||
fflush(stdout);
|
||||
if (fgets(tmp, (int)len, stdin) == NULL) {
|
||||
if (fgets(tmp, len, stdin) == NULL) {
|
||||
free(tmp);
|
||||
return 0;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ static int ssh_gets(const char *prompt, char *buf, size_t len, int verify)
|
||||
|
||||
fprintf(stdout, "\nVerifying, please re-enter. %s", prompt);
|
||||
fflush(stdout);
|
||||
if (!fgets(key_string, (int)len, stdin)) {
|
||||
if (! fgets(key_string, len, stdin)) {
|
||||
explicit_bzero(key_string, len);
|
||||
SAFE_FREE(key_string);
|
||||
clearerr(stdin);
|
||||
|
||||
130
src/kex.c
130
src/kex.c
@@ -40,7 +40,6 @@
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/string.h"
|
||||
#include "libssh/curve25519.h"
|
||||
#include "libssh/sntrup761.h"
|
||||
#include "libssh/knownhosts.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/pki.h"
|
||||
@@ -96,12 +95,6 @@
|
||||
#define CURVE25519 ""
|
||||
#endif /* HAVE_CURVE25519 */
|
||||
|
||||
#ifdef HAVE_SNTRUP761
|
||||
#define SNTRUP761X25519 "sntrup761x25519-sha512@openssh.com,"
|
||||
#else
|
||||
#define SNTRUP761X25519 ""
|
||||
#endif /* HAVE_SNTRUP761 */
|
||||
|
||||
#ifdef HAVE_ECC
|
||||
#define ECDH "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
|
||||
#define EC_HOSTKEYS "ecdsa-sha2-nistp521," \
|
||||
@@ -166,7 +159,6 @@
|
||||
|
||||
#define DEFAULT_KEY_EXCHANGE \
|
||||
CURVE25519 \
|
||||
SNTRUP761X25519 \
|
||||
ECDH \
|
||||
"diffie-hellman-group18-sha512,diffie-hellman-group16-sha512," \
|
||||
GEX_SHA256 \
|
||||
@@ -275,58 +267,38 @@ static const char *ssh_kex_descriptions[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *ssh_kex_get_default_methods(enum ssh_kex_types_e type)
|
||||
const char *ssh_kex_get_default_methods(uint32_t algo)
|
||||
{
|
||||
if (type >= SSH_KEX_METHODS) {
|
||||
if (algo >= SSH_KEX_METHODS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return default_methods[type];
|
||||
return default_methods[algo];
|
||||
}
|
||||
const char *ssh_kex_get_supported_method(enum ssh_kex_types_e type)
|
||||
|
||||
const char *ssh_kex_get_supported_method(uint32_t algo)
|
||||
{
|
||||
if (type >= SSH_KEX_METHODS) {
|
||||
if (algo >= SSH_KEX_METHODS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return supported_methods[type];
|
||||
return supported_methods[algo];
|
||||
}
|
||||
|
||||
const char *ssh_kex_get_description(enum ssh_kex_types_e type)
|
||||
{
|
||||
if (type >= SSH_KEX_METHODS) {
|
||||
return NULL;
|
||||
}
|
||||
const char *ssh_kex_get_description(uint32_t algo) {
|
||||
if (algo >= SSH_KEX_METHODS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ssh_kex_descriptions[type];
|
||||
return ssh_kex_descriptions[algo];
|
||||
}
|
||||
|
||||
const char *ssh_kex_get_fips_methods(enum ssh_kex_types_e type)
|
||||
{
|
||||
if (type >= SSH_KEX_METHODS) {
|
||||
return NULL;
|
||||
}
|
||||
const char *ssh_kex_get_fips_methods(uint32_t algo) {
|
||||
if (algo >= SSH_KEX_METHODS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fips_methods[type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a list of supported algorithms of a given type. This respects the
|
||||
* FIPS mode status.
|
||||
*
|
||||
* @param[in] type The type of the algorithm to query (SSH_KEX, SSH_MAC_C_S,
|
||||
* ...).
|
||||
*
|
||||
* @return The list of supported methods as comma-separated string, or NULL for
|
||||
* unknown type.
|
||||
*/
|
||||
const char *ssh_get_supported_methods(enum ssh_kex_types_e type)
|
||||
{
|
||||
if (ssh_fips_mode()) {
|
||||
return ssh_kex_get_fips_methods(type);
|
||||
} else {
|
||||
return ssh_kex_get_supported_method(type);
|
||||
}
|
||||
return fips_methods[algo];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -922,8 +894,6 @@ kex_select_kex_type(const char *kex)
|
||||
return SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
|
||||
} else if (strcmp(kex, "curve25519-sha256") == 0) {
|
||||
return SSH_KEX_CURVE25519_SHA256;
|
||||
} else if (strcmp(kex, "sntrup761x25519-sha512@openssh.com") == 0) {
|
||||
return SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM;
|
||||
}
|
||||
/* should not happen. We should be getting only valid names at this stage */
|
||||
return 0;
|
||||
@@ -963,11 +933,6 @@ static void revert_kex_callbacks(ssh_session session)
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
ssh_client_curve25519_remove_callbacks(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_SNTRUP761
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
|
||||
ssh_client_sntrup761x25519_remove_callbacks(session);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1375,7 +1340,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
|
||||
buf = ssh_buffer_new();
|
||||
if (buf == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1384,9 +1348,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
session->clientbanner,
|
||||
session->serverbanner);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to pack client and server banner");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -1400,9 +1361,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
|
||||
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to get next server pubkey blob");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -1417,9 +1375,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
server_pubkey_blob);
|
||||
SSH_STRING_FREE(server_pubkey_blob);
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to pack hashes and pubkey blob");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -1444,7 +1399,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
client_pubkey,
|
||||
server_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to pack DH pubkeys");
|
||||
goto error;
|
||||
}
|
||||
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
@@ -1480,7 +1434,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
client_pubkey,
|
||||
server_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to pack DH GEX params");
|
||||
goto error;
|
||||
}
|
||||
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
@@ -1503,7 +1456,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
session->next_crypto->ecdh_client_pubkey,
|
||||
session->next_crypto->ecdh_server_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to pack ECDH pubkeys");
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
@@ -1521,47 +1473,13 @@ int ssh_make_sessionid(ssh_session session)
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to pack Curve25519 pubkeys");
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
#endif /* HAVE_CURVE25519 */
|
||||
#ifdef HAVE_SNTRUP761
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
|
||||
rc = ssh_buffer_pack(buf,
|
||||
"dPPdPP",
|
||||
SNTRUP761_PUBLICKEY_SIZE + CURVE25519_PUBKEY_SIZE,
|
||||
(size_t)SNTRUP761_PUBLICKEY_SIZE,
|
||||
session->next_crypto->sntrup761_client_pubkey,
|
||||
(size_t)CURVE25519_PUBKEY_SIZE,
|
||||
session->next_crypto->curve25519_client_pubkey,
|
||||
SNTRUP761_CIPHERTEXT_SIZE + CURVE25519_PUBKEY_SIZE,
|
||||
(size_t)SNTRUP761_CIPHERTEXT_SIZE,
|
||||
session->next_crypto->sntrup761_ciphertext,
|
||||
(size_t)CURVE25519_PUBKEY_SIZE,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to pack SNTRU Prime params");
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
#endif /* HAVE_SNTRUP761 */
|
||||
}
|
||||
if (session->next_crypto->kex_type == SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM) {
|
||||
rc = ssh_buffer_pack(buf,
|
||||
"F",
|
||||
session->next_crypto->shared_secret,
|
||||
SHA512_DIGEST_LEN);
|
||||
} else {
|
||||
rc = ssh_buffer_pack(buf, "B", session->next_crypto->shared_secret);
|
||||
}
|
||||
rc = ssh_buffer_pack(buf, "B", session->next_crypto->shared_secret);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Failed to pack shared secret");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -1569,6 +1487,8 @@ int ssh_make_sessionid(ssh_session session)
|
||||
ssh_log_hexdump("hash buffer", ssh_buffer_get(buf), ssh_buffer_get_len(buf));
|
||||
#endif
|
||||
|
||||
/* Set rc for the following switch statement in case we goto error. */
|
||||
rc = SSH_ERROR;
|
||||
switch (session->next_crypto->kex_type) {
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
@@ -1616,7 +1536,6 @@ int ssh_make_sessionid(ssh_session session)
|
||||
case SSH_KEX_DH_GROUP16_SHA512:
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
|
||||
session->next_crypto->digest_len = SHA512_DIGEST_LENGTH;
|
||||
session->next_crypto->digest_type = SSH_KDF_SHA512;
|
||||
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
|
||||
@@ -1629,6 +1548,7 @@ int ssh_make_sessionid(ssh_session session)
|
||||
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.
|
||||
@@ -1637,6 +1557,7 @@ int ssh_make_sessionid(ssh_session session)
|
||||
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
|
||||
if (session->next_crypto->session_id == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
rc = SSH_ERROR;
|
||||
goto error;
|
||||
}
|
||||
memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,
|
||||
@@ -1753,12 +1674,7 @@ int ssh_generate_session_keys(ssh_session session)
|
||||
size_t intkey_srv_to_cli_len = 0;
|
||||
int rc = -1;
|
||||
|
||||
if (session->next_crypto->kex_type == SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM) {
|
||||
k_string = ssh_make_padded_bignum_string(crypto->shared_secret,
|
||||
SHA512_DIGEST_LEN);
|
||||
} else {
|
||||
k_string = ssh_make_bignum_string(crypto->shared_secret);
|
||||
}
|
||||
k_string = ssh_make_bignum_string(crypto->shared_secret);
|
||||
if (k_string == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
|
||||
@@ -171,7 +171,7 @@ static int known_hosts_read_line(FILE *fp,
|
||||
size_t *buf_len,
|
||||
size_t *lineno)
|
||||
{
|
||||
while (fgets(buf, (int)buf_size, fp) != NULL) {
|
||||
while (fgets(buf, buf_size, fp) != NULL) {
|
||||
size_t len;
|
||||
if (buf[0] == '\0') {
|
||||
continue;
|
||||
|
||||
@@ -49,8 +49,9 @@
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/hmac.h>
|
||||
#else
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/param_build.h>
|
||||
#include <openssl/provider.h>
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
#include <openssl/rand.h>
|
||||
#if defined(WITH_PKCS11_URI) && !defined(WITH_PKCS11_PROVIDER)
|
||||
@@ -96,7 +97,37 @@ void ssh_reseed(void){
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WITH_PKCS11_URI) && !defined(WITH_PKCS11_PROVIDER)
|
||||
#if defined(WITH_PKCS11_URI)
|
||||
#if defined(WITH_PKCS11_PROVIDER)
|
||||
static OSSL_PROVIDER *provider = NULL;
|
||||
static bool pkcs11_provider_failed = false;
|
||||
|
||||
int pki_load_pkcs11_provider(void)
|
||||
{
|
||||
if (OSSL_PROVIDER_available(NULL, "pkcs11") == 1) {
|
||||
/* the provider is already available.
|
||||
* Loaded through a configuration file? */
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
if (pkcs11_provider_failed) {
|
||||
/* the loading failed previously -- do not retry */
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
provider = OSSL_PROVIDER_try_load(NULL, "pkcs11", 1);
|
||||
if (provider != NULL) {
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to load the pkcs11 provider: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
/* Do not attempt to load it again */
|
||||
pkcs11_provider_failed = true;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#else
|
||||
static ENGINE *engine = NULL;
|
||||
|
||||
ENGINE *pki_get_engine(void)
|
||||
@@ -128,7 +159,8 @@ ENGINE *pki_get_engine(void)
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
#endif /* defined(WITH_PKCS11_URI) && !defined(WITH_PKCS11_PROVIDER) */
|
||||
#endif /* defined(WITH_PKCS11_PROVIDER) */
|
||||
#endif /* defined(WITH_PKCS11_URI) */
|
||||
|
||||
#ifdef HAVE_OPENSSL_EVP_KDF_CTX
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
@@ -317,7 +349,7 @@ HMACCTX hmac_init(const void *key, size_t len, enum ssh_hmac_e type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, (int)len);
|
||||
pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, len);
|
||||
if (pkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
@@ -603,7 +635,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
(unsigned char *)out + aadlen,
|
||||
&tmplen,
|
||||
(unsigned char *)in + aadlen,
|
||||
(int)(len - aadlen));
|
||||
(int)len - aadlen);
|
||||
outlen = tmplen;
|
||||
if (rc != 1 || outlen != (int)len - aadlen) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptUpdate failed");
|
||||
@@ -621,7 +653,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_GET_TAG,
|
||||
(int)authlen,
|
||||
authlen,
|
||||
(unsigned char *)tag);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_GET_TAG failed");
|
||||
@@ -659,7 +691,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
/* set tag for authentication */
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_SET_TAG,
|
||||
(int)authlen,
|
||||
authlen,
|
||||
(unsigned char *)complete_packet + aadlen + encrypted_size);
|
||||
if (rc == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_TAG failed");
|
||||
@@ -684,7 +716,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
(unsigned char *)out,
|
||||
&outlen,
|
||||
(unsigned char *)complete_packet + aadlen,
|
||||
(int)encrypted_size /* already subtracted aadlen */);
|
||||
encrypted_size /* already subtracted aadlen */);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptUpdate failed");
|
||||
return SSH_ERROR;
|
||||
@@ -966,7 +998,7 @@ chacha20_poly1305_aead_decrypt_length(struct ssh_cipher_struct *cipher,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rv = EVP_CipherUpdate(ctx->header_evp, out, &outlen, in, (int)len);
|
||||
rv = EVP_CipherUpdate(ctx->header_evp, out, &outlen, in, len);
|
||||
if (rv != 1 || outlen != sizeof(uint32_t)) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
|
||||
return SSH_ERROR;
|
||||
@@ -1053,11 +1085,9 @@ chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
|
||||
/* Decrypt the message */
|
||||
rv = EVP_CipherUpdate(ctx->main_evp,
|
||||
out,
|
||||
&len,
|
||||
rv = EVP_CipherUpdate(ctx->main_evp, out, &len,
|
||||
(uint8_t *)complete_packet + sizeof(uint32_t),
|
||||
(int)encrypted_size);
|
||||
encrypted_size);
|
||||
if (rv != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
|
||||
goto out;
|
||||
@@ -1124,7 +1154,7 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
out_packet->payload,
|
||||
&outlen,
|
||||
in_packet->payload,
|
||||
(int)(len - sizeof(uint32_t)));
|
||||
len - sizeof(uint32_t));
|
||||
if (ret != 1) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
|
||||
return;
|
||||
@@ -1404,6 +1434,14 @@ void ssh_crypto_finalize(void)
|
||||
engine = NULL;
|
||||
}
|
||||
#endif
|
||||
#if defined(WITH_PKCS11_URI)
|
||||
#if defined(WITH_PKCS11_PROVIDER)
|
||||
if (provider != NULL) {
|
||||
OSSL_PROVIDER_unload(provider);
|
||||
provider = NULL;
|
||||
}
|
||||
#endif /* WITH_PKCS11_PROVIDER */
|
||||
#endif /* WITH_PKCS11_URI */
|
||||
|
||||
libcrypto_initialized = 0;
|
||||
}
|
||||
@@ -1548,12 +1586,6 @@ int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote)
|
||||
{
|
||||
return evp_dup_pkey("EC", key, demote, new_key);
|
||||
}
|
||||
|
||||
int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote)
|
||||
{
|
||||
return evp_dup_pkey("ED25519", key, demote, new_key);
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
ssh_string
|
||||
|
||||
@@ -966,8 +966,7 @@ int ssh_crypto_init(void)
|
||||
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
|
||||
|
||||
if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P, 0)) {
|
||||
gcry_control(GCRYCTL_USE_SECURE_RNDPOOL);
|
||||
gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0);
|
||||
gcry_control(GCRYCTL_INIT_SECMEM, 4096);
|
||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -481,15 +481,3 @@ LIBSSH_4_10_0 # Released
|
||||
ssh_pki_export_privkey_file_format;
|
||||
ssh_request_no_more_sessions;
|
||||
} LIBSSH_4_9_0;
|
||||
|
||||
LIBSSH_AFTER_4_10_0
|
||||
{
|
||||
global:
|
||||
sftp_get_users_groups_by_id;
|
||||
sftp_name_id_map_free;
|
||||
sftp_name_id_map_new;
|
||||
ssh_get_supported_methods;
|
||||
sshsig_sign;
|
||||
sshsig_verify;
|
||||
} LIBSSH_4_10_0;
|
||||
|
||||
|
||||
10
src/log.c
10
src/log.c
@@ -59,22 +59,22 @@ static int current_timestring(int hires, char *buf, size_t len)
|
||||
{
|
||||
char tbuf[64];
|
||||
struct timeval tv;
|
||||
struct tm tm, *tm_ptr = NULL;
|
||||
struct tm *tm;
|
||||
time_t t;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
t = (time_t) tv.tv_sec;
|
||||
|
||||
tm_ptr = localtime_r(&t, &tm);
|
||||
if (tm_ptr == NULL) {
|
||||
tm = localtime(&t);
|
||||
if (tm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hires) {
|
||||
strftime(tbuf, sizeof(tbuf), "%Y/%m/%d %H:%M:%S", &tm);
|
||||
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
|
||||
snprintf(buf, len, "%s.%06ld", tbuf, (long)tv.tv_usec);
|
||||
} else {
|
||||
strftime(tbuf, sizeof(tbuf), "%Y/%m/%d %H:%M:%S", &tm);
|
||||
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
|
||||
snprintf(buf, len, "%s", tbuf);
|
||||
}
|
||||
|
||||
|
||||
@@ -205,10 +205,8 @@ int match_pattern_list(const char *string, const char *pattern,
|
||||
* Returns -1 if negation matches, 1 if there is a positive match, 0 if there
|
||||
* is no match at all.
|
||||
*/
|
||||
int
|
||||
match_hostname(const char *host, const char *pattern, size_t len)
|
||||
{
|
||||
return match_pattern_list(host, pattern, len, 1);
|
||||
int match_hostname(const char *host, const char *pattern, unsigned int len) {
|
||||
return match_pattern_list(host, pattern, len, 1);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
@@ -5,17 +5,13 @@
|
||||
* v3 defines the version inside build_info.h so if it isn't defined
|
||||
* in version.h we should have v3
|
||||
*/
|
||||
#include <mbedtls/cipher.h>
|
||||
#include <mbedtls/version.h>
|
||||
|
||||
#ifndef MBEDTLS_VERSION_MAJOR
|
||||
#include <mbedtls/build_info.h>
|
||||
#endif /* MBEDTLS_VERSION_MAJOR */
|
||||
|
||||
#include <mbedtls/cipher.h>
|
||||
#ifdef MBEDTLS_VERSION_MAJOR
|
||||
#if MBEDTLS_VERSION_MAJOR < 3
|
||||
|
||||
static inline size_t
|
||||
mbedtls_cipher_info_get_key_bitlen(const mbedtls_cipher_info_t *info)
|
||||
static inline size_t mbedtls_cipher_info_get_key_bitlen(
|
||||
const mbedtls_cipher_info_t *info)
|
||||
{
|
||||
if (info == NULL) {
|
||||
return 0;
|
||||
@@ -23,8 +19,8 @@ mbedtls_cipher_info_get_key_bitlen(const mbedtls_cipher_info_t *info)
|
||||
return info->key_bitlen;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
mbedtls_cipher_info_get_iv_size(const mbedtls_cipher_info_t *info)
|
||||
static inline size_t mbedtls_cipher_info_get_iv_size(
|
||||
const mbedtls_cipher_info_t *info)
|
||||
{
|
||||
if (info == NULL) {
|
||||
return 0;
|
||||
@@ -33,24 +29,11 @@ mbedtls_cipher_info_get_iv_size(const mbedtls_cipher_info_t *info)
|
||||
}
|
||||
|
||||
#define MBEDTLS_PRIVATE(X) X
|
||||
|
||||
#ifdef HAVE_MBEDTLS_CURVE25519
|
||||
#include <mbedtls/ecdh.h>
|
||||
|
||||
#define MBEDTLS_ECDH_PRIVATE(X) X
|
||||
#define MBEDTLS_ECDH_PARAMS(X) X
|
||||
typedef mbedtls_ecdh_context mbedtls_ecdh_params;
|
||||
#endif /* HAVE_MBEDTLS_CURVE25519 */
|
||||
|
||||
#else /* MBEDTLS_VERSION_MAJOR < 3 */
|
||||
|
||||
#ifdef HAVE_MBEDTLS_CURVE25519
|
||||
#include <mbedtls/ecdh.h>
|
||||
|
||||
#define MBEDTLS_ECDH_PRIVATE(X) MBEDTLS_PRIVATE(X)
|
||||
#define MBEDTLS_ECDH_PARAMS(X) X.MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh)
|
||||
typedef mbedtls_ecdh_context_mbed mbedtls_ecdh_params;
|
||||
#endif /* HAVE_MBEDTLS_CURVE25519 */
|
||||
|
||||
#endif /* MBEDTLS_VERSION_MAJOR < 3 */
|
||||
#else /* MBEDTLS_VERSION_MAJOR */
|
||||
#include <mbedtls/build_info.h>
|
||||
#if MBEDTLS_VERSION_MAJOR < 3
|
||||
#define MBEDTLS_PRIVATE(X) X
|
||||
#endif /* MBEDTLS_VERSION_MAJOR < 3 */
|
||||
#endif /* MBEDTLS_VERSION_MAJOR */
|
||||
#endif /* MBEDCRYPTO_COMPAT_H */
|
||||
|
||||
651
src/messages.c
651
src/messages.c
@@ -204,35 +204,8 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
|
||||
ssh_message_reply_default(msg);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
#define CB channel_open_request_direct_tcpip_function
|
||||
} else if (msg->channel_request_open.type == SSH_CHANNEL_DIRECT_TCPIP &&
|
||||
ssh_callbacks_exists(session->server_callbacks, CB)) {
|
||||
struct ssh_channel_request_open *rq = &msg->channel_request_open;
|
||||
channel = session->server_callbacks->CB(session,
|
||||
rq->destination,
|
||||
rq->destination_port,
|
||||
rq->originator,
|
||||
rq->originator_port,
|
||||
session->server_callbacks->userdata);
|
||||
#undef CB
|
||||
if (channel != NULL) {
|
||||
rc = ssh_message_channel_request_open_reply_accept_channel(
|
||||
msg,
|
||||
channel);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to send reply for accepting a channel "
|
||||
"open");
|
||||
}
|
||||
return SSH_OK;
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
break;
|
||||
case SSH_REQUEST_CHANNEL:
|
||||
channel = msg->channel_request.channel;
|
||||
@@ -546,36 +519,30 @@ static void ssh_message_queue(ssh_session session, ssh_message message)
|
||||
*
|
||||
* @returns The head message or NULL if it doesn't exist.
|
||||
*/
|
||||
ssh_message ssh_message_pop_head(ssh_session session)
|
||||
{
|
||||
ssh_message msg = NULL;
|
||||
struct ssh_iterator *i = NULL;
|
||||
|
||||
if (session->ssh_message_list == NULL)
|
||||
return NULL;
|
||||
|
||||
i = ssh_list_get_iterator(session->ssh_message_list);
|
||||
if (i != NULL) {
|
||||
msg = ssh_iterator_value(ssh_message, i);
|
||||
ssh_list_remove(session->ssh_message_list, i);
|
||||
}
|
||||
return msg;
|
||||
ssh_message ssh_message_pop_head(ssh_session session){
|
||||
ssh_message msg=NULL;
|
||||
struct ssh_iterator *i = NULL;
|
||||
if(session->ssh_message_list == NULL)
|
||||
return NULL;
|
||||
i=ssh_list_get_iterator(session->ssh_message_list);
|
||||
if(i != NULL){
|
||||
msg=ssh_iterator_value(ssh_message,i);
|
||||
ssh_list_remove(session->ssh_message_list,i);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* Returns 1 if there is a message available */
|
||||
static int ssh_message_termination(void *s)
|
||||
{
|
||||
ssh_session session = s;
|
||||
struct ssh_iterator *it = NULL;
|
||||
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
return 1;
|
||||
|
||||
it = ssh_list_get_iterator(session->ssh_message_list);
|
||||
if (!it)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
static int ssh_message_termination(void *s){
|
||||
ssh_session session = s;
|
||||
struct ssh_iterator *it = NULL;
|
||||
if(session->session_state == SSH_SESSION_STATE_ERROR)
|
||||
return 1;
|
||||
it = ssh_list_get_iterator(session->ssh_message_list);
|
||||
if(!it)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
/**
|
||||
* @brief Retrieve a SSH message from a SSH session.
|
||||
@@ -675,7 +642,6 @@ void ssh_message_free(ssh_message msg){
|
||||
SAFE_FREE(msg->auth_request.password);
|
||||
}
|
||||
ssh_key_free(msg->auth_request.pubkey);
|
||||
ssh_key_free(msg->auth_request.server_pubkey);
|
||||
break;
|
||||
case SSH_REQUEST_CHANNEL_OPEN:
|
||||
SAFE_FREE(msg->channel_request_open.originator);
|
||||
@@ -767,12 +733,11 @@ error:
|
||||
static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
|
||||
ssh_message msg,
|
||||
const char *service,
|
||||
ssh_string algo,
|
||||
const char *method)
|
||||
ssh_string algo)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
ssh_buffer buffer = NULL;
|
||||
ssh_string str = NULL;
|
||||
ssh_string str=NULL;
|
||||
int rc;
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
|
||||
@@ -798,10 +763,10 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
|
||||
SSH2_MSG_USERAUTH_REQUEST, /* type */
|
||||
msg->auth_request.username,
|
||||
service,
|
||||
method,
|
||||
"publickey", /* method */
|
||||
1, /* has to be signed (true) */
|
||||
ssh_string_get_char(algo), /* pubkey algorithm */
|
||||
str); /* public key as a blob */
|
||||
str); /* public key as a blob */
|
||||
|
||||
SSH_STRING_FREE(str);
|
||||
if (rc != SSH_OK) {
|
||||
@@ -810,25 +775,6 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Add server public key for hostbound extension */
|
||||
if (strcmp(method, "publickey-hostbound-v00@openssh.com") == 0 &&
|
||||
msg->auth_request.server_pubkey != NULL) {
|
||||
|
||||
rc = ssh_pki_export_pubkey_blob(msg->auth_request.server_pubkey, &str);
|
||||
if (rc < 0) {
|
||||
SSH_BUFFER_FREE(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_add_ssh_string(buffer, str);
|
||||
SSH_STRING_FREE(str);
|
||||
if (rc < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
SSH_BUFFER_FREE(buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -838,334 +784,263 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
|
||||
* @brief Handle a SSH_MSG_MSG_USERAUTH_REQUEST packet and queue a
|
||||
* SSH Message
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_request)
|
||||
{
|
||||
ssh_message msg = NULL;
|
||||
ssh_signature sig = NULL;
|
||||
char *service = NULL;
|
||||
char *method = NULL;
|
||||
int cmp;
|
||||
int rc;
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
ssh_message msg = NULL;
|
||||
ssh_signature sig = NULL;
|
||||
char *service = NULL;
|
||||
char *method = NULL;
|
||||
int cmp;
|
||||
int rc;
|
||||
|
||||
(void)user;
|
||||
(void)type;
|
||||
(void)user;
|
||||
(void)type;
|
||||
|
||||
msg = ssh_message_new(session);
|
||||
if (msg == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
msg = ssh_message_new(session);
|
||||
if (msg == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
msg->type = SSH_REQUEST_AUTH;
|
||||
rc = ssh_buffer_unpack(packet,
|
||||
"sss",
|
||||
&msg->auth_request.username,
|
||||
&service,
|
||||
&method);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Auth request for service %s, method %s for user '%s'",
|
||||
service, method,
|
||||
msg->auth_request.username);
|
||||
|
||||
cmp = strcmp(service, "ssh-connection");
|
||||
if (cmp != 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid service request: %s",
|
||||
service);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "none") == 0) {
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_NONE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "password") == 0) {
|
||||
uint8_t tmp;
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD;
|
||||
rc = ssh_buffer_unpack(packet, "bs", &tmp, &msg->auth_request.password);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
msg->type = SSH_REQUEST_AUTH;
|
||||
rc = ssh_buffer_unpack(packet,
|
||||
"sss",
|
||||
&msg->auth_request.username,
|
||||
&service,
|
||||
&method);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "keyboard-interactive") == 0) {
|
||||
ssh_string lang = NULL;
|
||||
ssh_string submethods = NULL;
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_INTERACTIVE;
|
||||
lang = ssh_buffer_get_ssh_string(packet);
|
||||
if (lang == NULL) {
|
||||
goto error;
|
||||
}
|
||||
/* from the RFC 4256
|
||||
* 3.1. Initial Exchange
|
||||
* "The language tag is deprecated and SHOULD be the empty string."
|
||||
*/
|
||||
SSH_STRING_FREE(lang);
|
||||
|
||||
submethods = ssh_buffer_get_ssh_string(packet);
|
||||
if (submethods == NULL) {
|
||||
goto error;
|
||||
}
|
||||
/* from the RFC 4256
|
||||
* 3.1. Initial Exchange
|
||||
* "One possible implementation strategy of the submethods field on the
|
||||
* server is that, unless the user may use multiple different
|
||||
* submethods, the server ignores this field."
|
||||
*/
|
||||
SSH_STRING_FREE(submethods);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "publickey") == 0) {
|
||||
ssh_string algo = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
uint8_t has_sign;
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY;
|
||||
SAFE_FREE(method);
|
||||
rc = ssh_buffer_unpack(packet, "bSS",
|
||||
&has_sign,
|
||||
&algo,
|
||||
&pubkey_blob
|
||||
);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_pubkey_blob(pubkey_blob, &msg->auth_request.pubkey);
|
||||
SSH_STRING_FREE(pubkey_blob);
|
||||
pubkey_blob = NULL;
|
||||
if (rc < 0) {
|
||||
SSH_STRING_FREE(algo);
|
||||
algo = NULL;
|
||||
goto error;
|
||||
}
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
|
||||
msg->auth_request.sigtype = strdup(ssh_string_get_char(algo));
|
||||
if (msg->auth_request.sigtype == NULL) {
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
|
||||
SSH_STRING_FREE(algo);
|
||||
algo = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Auth request for service %s, method %s for user '%s'",
|
||||
service,
|
||||
method,
|
||||
msg->auth_request.username);
|
||||
// has a valid signature ?
|
||||
if(has_sign) {
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_buffer digest = NULL;
|
||||
|
||||
cmp = strcmp(service, "ssh-connection");
|
||||
if (cmp != 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid service request: %s", service);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "none") == 0) {
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_NONE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "password") == 0) {
|
||||
uint8_t tmp;
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD;
|
||||
rc = ssh_buffer_unpack(packet, "bs", &tmp, &msg->auth_request.password);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "keyboard-interactive") == 0) {
|
||||
ssh_string lang = NULL;
|
||||
ssh_string submethods = NULL;
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_INTERACTIVE;
|
||||
lang = ssh_buffer_get_ssh_string(packet);
|
||||
if (lang == NULL) {
|
||||
goto error;
|
||||
}
|
||||
/* from the RFC 4256
|
||||
* 3.1. Initial Exchange
|
||||
* "The language tag is deprecated and SHOULD be the empty string."
|
||||
*/
|
||||
SSH_STRING_FREE(lang);
|
||||
|
||||
submethods = ssh_buffer_get_ssh_string(packet);
|
||||
if (submethods == NULL) {
|
||||
goto error;
|
||||
}
|
||||
/* from the RFC 4256
|
||||
* 3.1. Initial Exchange
|
||||
* "One possible implementation strategy of the submethods field on the
|
||||
* server is that, unless the user may use multiple different
|
||||
* submethods, the server ignores this field."
|
||||
*/
|
||||
SSH_STRING_FREE(submethods);
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(method, "publickey") == 0 ||
|
||||
strcmp(method, "publickey-hostbound-v00@openssh.com") == 0) {
|
||||
ssh_string algo = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string server_pubkey_blob = NULL;
|
||||
uint8_t has_sign;
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY;
|
||||
|
||||
rc = ssh_buffer_unpack(packet, "bSS", &has_sign, &algo, &pubkey_blob);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
cmp = strcmp(method, "publickey-hostbound-v00@openssh.com");
|
||||
if (cmp == 0) {
|
||||
server_pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (server_pubkey_blob == NULL) {
|
||||
SSH_STRING_FREE(pubkey_blob);
|
||||
SSH_STRING_FREE(algo);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_pubkey_blob(server_pubkey_blob,
|
||||
&msg->auth_request.server_pubkey);
|
||||
SSH_STRING_FREE(server_pubkey_blob);
|
||||
|
||||
if (rc < 0) {
|
||||
SSH_STRING_FREE(pubkey_blob);
|
||||
SSH_STRING_FREE(algo);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_pubkey_blob(pubkey_blob, &msg->auth_request.pubkey);
|
||||
SSH_STRING_FREE(pubkey_blob);
|
||||
pubkey_blob = NULL;
|
||||
if (rc < 0) {
|
||||
SSH_STRING_FREE(algo);
|
||||
algo = NULL;
|
||||
goto error;
|
||||
}
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
|
||||
msg->auth_request.sigtype = strdup(ssh_string_get_char(algo));
|
||||
if (msg->auth_request.sigtype == NULL) {
|
||||
sig_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if(sig_blob == NULL) {
|
||||
SSH_LOG(SSH_LOG_PACKET, "Invalid signature packet from peer");
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
|
||||
SSH_STRING_FREE(algo);
|
||||
algo = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// has a valid signature ?
|
||||
if (has_sign) {
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_buffer digest = NULL;
|
||||
digest = ssh_msg_userauth_build_digest(session, msg, service, algo);
|
||||
SSH_STRING_FREE(algo);
|
||||
algo = NULL;
|
||||
if (digest == NULL) {
|
||||
SSH_STRING_FREE(sig_blob);
|
||||
SSH_LOG(SSH_LOG_PACKET, "Failed to get digest");
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
sig_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (sig_blob == NULL) {
|
||||
SSH_LOG(SSH_LOG_PACKET, "Invalid signature packet from peer");
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
|
||||
SSH_STRING_FREE(algo);
|
||||
algo = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
digest = ssh_msg_userauth_build_digest(session,
|
||||
msg,
|
||||
service,
|
||||
algo,
|
||||
method);
|
||||
SSH_STRING_FREE(algo);
|
||||
algo = NULL;
|
||||
if (digest == NULL) {
|
||||
SSH_STRING_FREE(sig_blob);
|
||||
SSH_LOG(SSH_LOG_PACKET, "Failed to get digest");
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_signature_blob(sig_blob,
|
||||
msg->auth_request.pubkey,
|
||||
&sig);
|
||||
if (rc == SSH_OK) {
|
||||
/* Check if the signature from client matches server preferences
|
||||
*/
|
||||
if (session->opts.pubkey_accepted_types) {
|
||||
cmp = match_group(session->opts.pubkey_accepted_types,
|
||||
sig->type_c);
|
||||
if (cmp != 1) {
|
||||
ssh_set_error(
|
||||
session,
|
||||
rc = ssh_pki_import_signature_blob(sig_blob,
|
||||
msg->auth_request.pubkey,
|
||||
&sig);
|
||||
if (rc == SSH_OK) {
|
||||
/* Check if the signature from client matches server preferences */
|
||||
if (session->opts.pubkey_accepted_types) {
|
||||
cmp = match_group(session->opts.pubkey_accepted_types,
|
||||
sig->type_c);
|
||||
if (cmp != 1) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Public key from client (%s) doesn't match server "
|
||||
"preference (%s)",
|
||||
sig->type_c,
|
||||
session->opts.pubkey_accepted_types);
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == SSH_OK) {
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
sig,
|
||||
msg->auth_request.pubkey,
|
||||
ssh_buffer_get(digest),
|
||||
ssh_buffer_get_len(digest));
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
}
|
||||
SSH_STRING_FREE(sig_blob);
|
||||
SSH_BUFFER_FREE(digest);
|
||||
ssh_signature_free(sig);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Received an invalid signature from peer");
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
|
||||
goto error;
|
||||
|
||||
if (rc == SSH_OK) {
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
sig,
|
||||
msg->auth_request.pubkey,
|
||||
ssh_buffer_get(digest),
|
||||
ssh_buffer_get_len(digest));
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Valid signature received");
|
||||
|
||||
cmp = strcmp(method, "publickey-hostbound-v00@openssh.com");
|
||||
if (cmp == 0) {
|
||||
ssh_key server_key = NULL;
|
||||
|
||||
if (msg->auth_request.server_pubkey == NULL) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Server public key not provided by client");
|
||||
msg->auth_request.signature_state =
|
||||
SSH_PUBLICKEY_STATE_WRONG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_get_server_publickey(session, &server_key);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Failed to get server public key for hostbound "
|
||||
"verification");
|
||||
msg->auth_request.signature_state =
|
||||
SSH_PUBLICKEY_STATE_ERROR;
|
||||
ssh_key_free(server_key);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ssh_key_cmp(server_key,
|
||||
msg->auth_request.server_pubkey,
|
||||
SSH_KEY_CMP_PUBLIC) != 0) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Server public key doesn't match the one provided "
|
||||
"by client");
|
||||
msg->auth_request.signature_state =
|
||||
SSH_PUBLICKEY_STATE_WRONG;
|
||||
ssh_key_free(server_key);
|
||||
goto error;
|
||||
}
|
||||
ssh_key_free(server_key);
|
||||
}
|
||||
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_VALID;
|
||||
}
|
||||
SSH_STRING_FREE(sig_blob);
|
||||
SSH_BUFFER_FREE(digest);
|
||||
ssh_signature_free(sig);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(
|
||||
SSH_LOG_PACKET,
|
||||
"Received an invalid signature from peer");
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
SAFE_FREE(method);
|
||||
SSH_STRING_FREE(algo);
|
||||
goto end;
|
||||
SSH_LOG(SSH_LOG_PACKET, "Valid signature received");
|
||||
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_VALID;
|
||||
}
|
||||
SSH_STRING_FREE(algo);
|
||||
goto end;
|
||||
}
|
||||
#ifdef WITH_GSSAPI
|
||||
if (strcmp(method, "gssapi-with-mic") == 0) {
|
||||
uint32_t n_oid;
|
||||
ssh_string *oids = NULL;
|
||||
ssh_string oid = NULL;
|
||||
char *hexa = NULL;
|
||||
int i;
|
||||
ssh_buffer_get_u32(packet, &n_oid);
|
||||
n_oid = ntohl(n_oid);
|
||||
if (n_oid > 100) {
|
||||
ssh_set_error(
|
||||
session,
|
||||
SSH_FATAL,
|
||||
"USERAUTH_REQUEST: gssapi-with-mic OID count too big (%d)",
|
||||
n_oid);
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PACKET, "gssapi: %d OIDs", n_oid);
|
||||
oids = calloc(n_oid, sizeof(ssh_string));
|
||||
if (oids == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
for (i = 0; i < (int)n_oid; ++i) {
|
||||
oid = ssh_buffer_get_ssh_string(packet);
|
||||
if (oid == NULL) {
|
||||
for (i = i - 1; i >= 0; --i) {
|
||||
SAFE_FREE(oids[i]);
|
||||
}
|
||||
SAFE_FREE(oids);
|
||||
ssh_set_error(session,
|
||||
SSH_LOG_PACKET,
|
||||
"USERAUTH_REQUEST: gssapi-with-mic missing OID");
|
||||
goto error;
|
||||
}
|
||||
oids[i] = oid;
|
||||
if (session->common.log_verbosity >= SSH_LOG_PACKET) {
|
||||
hexa = ssh_get_hexa(ssh_string_data(oid), ssh_string_len(oid));
|
||||
SSH_LOG(SSH_LOG_PACKET, "gssapi: OID %d: %s", i, hexa);
|
||||
SAFE_FREE(hexa);
|
||||
}
|
||||
}
|
||||
ssh_gssapi_handle_userauth(session,
|
||||
msg->auth_request.username,
|
||||
n_oid,
|
||||
oids);
|
||||
if (strcmp(method, "gssapi-with-mic") == 0) {
|
||||
uint32_t n_oid;
|
||||
ssh_string *oids = NULL;
|
||||
ssh_string oid = NULL;
|
||||
char *hexa = NULL;
|
||||
int i;
|
||||
ssh_buffer_get_u32(packet, &n_oid);
|
||||
n_oid=ntohl(n_oid);
|
||||
if(n_oid > 100){
|
||||
ssh_set_error(session, SSH_FATAL, "USERAUTH_REQUEST: gssapi-with-mic OID count too big (%d)",n_oid);
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PACKET, "gssapi: %d OIDs", n_oid);
|
||||
oids = calloc(n_oid, sizeof(ssh_string));
|
||||
if (oids == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
for (i=0;i<(int) n_oid;++i){
|
||||
oid=ssh_buffer_get_ssh_string(packet);
|
||||
if(oid == NULL){
|
||||
for(i=i-1;i>=0;--i){
|
||||
SAFE_FREE(oids[i]);
|
||||
}
|
||||
SAFE_FREE(oids);
|
||||
ssh_set_error(session, SSH_LOG_PACKET, "USERAUTH_REQUEST: gssapi-with-mic missing OID");
|
||||
goto error;
|
||||
}
|
||||
oids[i] = oid;
|
||||
if(session->common.log_verbosity >= SSH_LOG_PACKET){
|
||||
hexa = ssh_get_hexa(ssh_string_data(oid), ssh_string_len(oid));
|
||||
SSH_LOG(SSH_LOG_PACKET,"gssapi: OID %d: %s",i, hexa);
|
||||
SAFE_FREE(hexa);
|
||||
}
|
||||
}
|
||||
ssh_gssapi_handle_userauth(session, msg->auth_request.username, n_oid, oids);
|
||||
|
||||
for (i = 0; i < (int)n_oid; ++i) {
|
||||
SAFE_FREE(oids[i]);
|
||||
}
|
||||
SAFE_FREE(oids);
|
||||
/* bypass the message queue thing */
|
||||
SAFE_FREE(service);
|
||||
SAFE_FREE(method);
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
for(i=0;i<(int)n_oid;++i){
|
||||
SAFE_FREE(oids[i]);
|
||||
}
|
||||
SAFE_FREE(oids);
|
||||
/* bypass the message queue thing */
|
||||
SAFE_FREE(service);
|
||||
SAFE_FREE(method);
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
#endif
|
||||
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN;
|
||||
SAFE_FREE(method);
|
||||
goto end;
|
||||
msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN;
|
||||
SAFE_FREE(method);
|
||||
goto end;
|
||||
error:
|
||||
SAFE_FREE(service);
|
||||
SAFE_FREE(method);
|
||||
SAFE_FREE(service);
|
||||
SAFE_FREE(method);
|
||||
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_PACKET_USED;
|
||||
end:
|
||||
SAFE_FREE(service);
|
||||
SAFE_FREE(method);
|
||||
SAFE_FREE(service);
|
||||
SAFE_FREE(method);
|
||||
|
||||
ssh_message_queue(session, msg);
|
||||
ssh_message_queue(session,msg);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
@@ -1426,9 +1301,7 @@ end:
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
*/
|
||||
int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg,
|
||||
ssh_channel chan)
|
||||
{
|
||||
int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_channel chan) {
|
||||
ssh_session session = NULL;
|
||||
int rc;
|
||||
|
||||
@@ -1479,25 +1352,25 @@ int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg,
|
||||
*
|
||||
* @returns NULL in case of error
|
||||
*/
|
||||
ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg)
|
||||
{
|
||||
ssh_channel chan = NULL;
|
||||
int rc;
|
||||
ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) {
|
||||
ssh_channel chan = NULL;
|
||||
int rc;
|
||||
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chan = ssh_channel_new(msg->session);
|
||||
if (chan == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
rc = ssh_message_channel_request_open_reply_accept_channel(msg, chan);
|
||||
if (rc < 0) {
|
||||
ssh_channel_free(chan);
|
||||
chan = NULL;
|
||||
}
|
||||
return chan;
|
||||
|
||||
chan = ssh_channel_new(msg->session);
|
||||
if (chan == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
rc = ssh_message_channel_request_open_reply_accept_channel(msg, chan);
|
||||
if (rc < 0) {
|
||||
ssh_channel_free(chan);
|
||||
chan = NULL;
|
||||
}
|
||||
return chan;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
105
src/misc.c
105
src/misc.c
@@ -178,35 +178,6 @@ int ssh_gettimeofday(struct timeval *__p, void *__t)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Convert time in seconds since the Epoch to broken-down local time
|
||||
*
|
||||
* This is a helper used to provide localtime_r() like function interface
|
||||
* on Windows.
|
||||
*
|
||||
* @param timer Pointer to a location storing the time_t which
|
||||
* represents the time in seconds since the Epoch.
|
||||
*
|
||||
* @param result Pointer to a location where the broken-down time
|
||||
* (expressed as local time) should be stored.
|
||||
*
|
||||
* @returns A pointer to the structure pointed to by the parameter
|
||||
* <tt>result</tt> on success, NULL on error with the errno
|
||||
* set to indicate the error.
|
||||
*/
|
||||
struct tm *ssh_localtime(const time_t *timer, struct tm *result)
|
||||
{
|
||||
errno_t rc;
|
||||
rc = localtime_s(result, timer);
|
||||
if (rc != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
char *ssh_get_local_username(void)
|
||||
{
|
||||
DWORD size = 0;
|
||||
@@ -430,22 +401,22 @@ int ssh_is_ipaddr(const char *str)
|
||||
|
||||
char *ssh_lowercase(const char* str)
|
||||
{
|
||||
char *new = NULL, *p = NULL;
|
||||
char *new = NULL, *p = NULL;
|
||||
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = strdup(str);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
new = strdup(str);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (p = new; *p; p++) {
|
||||
*p = tolower(*p);
|
||||
}
|
||||
for (p = new; *p; p++) {
|
||||
*p = tolower(*p);
|
||||
}
|
||||
|
||||
return new;
|
||||
return new;
|
||||
}
|
||||
|
||||
char *ssh_hostport(const char *host, int port)
|
||||
@@ -865,32 +836,32 @@ int ssh_list_prepend(struct ssh_list *list, const void *data)
|
||||
|
||||
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator)
|
||||
{
|
||||
struct ssh_iterator *ptr = NULL, *prev = NULL;
|
||||
struct ssh_iterator *ptr = NULL, *prev = NULL;
|
||||
|
||||
if (list == NULL) {
|
||||
return;
|
||||
}
|
||||
if (list == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
prev = NULL;
|
||||
ptr = list->root;
|
||||
while (ptr && ptr != iterator) {
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
if (!ptr) {
|
||||
/* we did not find the element */
|
||||
return;
|
||||
}
|
||||
/* unlink it */
|
||||
if (prev)
|
||||
prev->next = ptr->next;
|
||||
/* if iterator was the head */
|
||||
if (list->root == iterator)
|
||||
list->root = iterator->next;
|
||||
/* if iterator was the tail */
|
||||
if (list->end == iterator)
|
||||
list->end = prev;
|
||||
SAFE_FREE(iterator);
|
||||
prev=NULL;
|
||||
ptr=list->root;
|
||||
while(ptr && ptr != iterator){
|
||||
prev=ptr;
|
||||
ptr=ptr->next;
|
||||
}
|
||||
if(!ptr){
|
||||
/* we did not find the element */
|
||||
return;
|
||||
}
|
||||
/* unlink it */
|
||||
if(prev)
|
||||
prev->next=ptr->next;
|
||||
/* if iterator was the head */
|
||||
if(list->root == iterator)
|
||||
list->root=iterator->next;
|
||||
/* if iterator was the tail */
|
||||
if(list->end == iterator)
|
||||
list->end = prev;
|
||||
SAFE_FREE(iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1831,7 +1802,7 @@ int ssh_quote_file_name(const char *file_name, char *buf, size_t buf_len)
|
||||
/* Put the string terminator */
|
||||
*dst = '\0';
|
||||
|
||||
return (int)(dst - buf);
|
||||
return dst - buf;
|
||||
|
||||
error:
|
||||
return SSH_ERROR;
|
||||
@@ -1877,7 +1848,7 @@ int ssh_newline_vis(const char *string, char *buf, size_t buf_len)
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return (int)(out - buf);
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1814,8 +1814,6 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv)
|
||||
*
|
||||
* @param filename The options file to use, if NULL the default
|
||||
* ~/.ssh/config and /etc/ssh/ssh_config will be used.
|
||||
* If complied with support for hermetic-usr,
|
||||
* /usr/etc/ssh/ssh_config will be used last.
|
||||
*
|
||||
* @return 0 on success, < 0 on error.
|
||||
*
|
||||
@@ -1823,63 +1821,48 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv)
|
||||
*/
|
||||
int ssh_options_parse_config(ssh_session session, const char *filename)
|
||||
{
|
||||
char *expanded_filename = NULL;
|
||||
int r;
|
||||
FILE *fp = NULL;
|
||||
char *expanded_filename = NULL;
|
||||
int r;
|
||||
|
||||
if (session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
}
|
||||
if (session == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->opts.sshdir == NULL) {
|
||||
r = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
|
||||
if (r < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (session->opts.sshdir == NULL) {
|
||||
r = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
|
||||
if (r < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* set default filename */
|
||||
if (filename == NULL) {
|
||||
expanded_filename = ssh_path_expand_escape(session, "%d/config");
|
||||
} else {
|
||||
expanded_filename = ssh_path_expand_escape(session, filename);
|
||||
}
|
||||
if (expanded_filename == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* set default filename */
|
||||
if (filename == NULL) {
|
||||
expanded_filename = ssh_path_expand_escape(session, "%d/config");
|
||||
} else {
|
||||
expanded_filename = ssh_path_expand_escape(session, filename);
|
||||
}
|
||||
if (expanded_filename == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = ssh_config_parse_file(session, expanded_filename);
|
||||
if (r < 0) {
|
||||
goto out;
|
||||
}
|
||||
if (filename == NULL) {
|
||||
if ((fp = fopen(GLOBAL_CLIENT_CONFIG, "r")) != NULL) {
|
||||
filename = GLOBAL_CLIENT_CONFIG;
|
||||
#ifdef USR_GLOBAL_CLIENT_CONFIG
|
||||
} else if ((fp = fopen(USR_GLOBAL_CLIENT_CONFIG, "r")) != NULL) {
|
||||
filename = USR_GLOBAL_CLIENT_CONFIG;
|
||||
#endif
|
||||
}
|
||||
r = ssh_config_parse_file(session, expanded_filename);
|
||||
if (r < 0) {
|
||||
goto out;
|
||||
}
|
||||
if (filename == NULL) {
|
||||
r = ssh_config_parse_file(session, GLOBAL_CLIENT_CONFIG);
|
||||
}
|
||||
|
||||
if (fp) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Reading configuration data from %s",
|
||||
filename);
|
||||
r = ssh_config_parse(session, fp, true);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not process the default configuration as part of connection again */
|
||||
session->opts.config_processed = true;
|
||||
/* Do not process the default configuration as part of connection again */
|
||||
session->opts.config_processed = true;
|
||||
out:
|
||||
free(expanded_filename);
|
||||
return r;
|
||||
free(expanded_filename);
|
||||
return r;
|
||||
}
|
||||
|
||||
int ssh_options_apply(ssh_session session)
|
||||
@@ -2723,13 +2706,7 @@ int ssh_bind_options_parse_config(ssh_bind sshbind, const char *filename)
|
||||
/* If the global default configuration hasn't been processed yet, process it
|
||||
* before the provided configuration. */
|
||||
if (!(sshbind->config_processed)) {
|
||||
if (ssh_file_readaccess_ok(GLOBAL_BIND_CONFIG)) {
|
||||
rc = ssh_bind_config_parse_file(sshbind, GLOBAL_BIND_CONFIG);
|
||||
#ifdef USR_GLOBAL_BIND_CONFIG
|
||||
} else {
|
||||
rc = ssh_bind_config_parse_file(sshbind, USR_GLOBAL_BIND_CONFIG);
|
||||
#endif
|
||||
}
|
||||
rc = ssh_bind_config_parse_file(sshbind, GLOBAL_BIND_CONFIG);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
20
src/packet.c
20
src/packet.c
@@ -294,6 +294,7 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
|
||||
* or session_state == SSH_SESSION_STATE_INITIAL_KEX
|
||||
* - dh_handshake_state == DH_STATE_INIT
|
||||
* or dh_handshake_state == DH_STATE_INIT_SENT (re-exchange)
|
||||
* or dh_handshake_state == DH_STATE_REQUEST_SENT (dh-gex)
|
||||
* or dh_handshake_state == DH_STATE_FINISHED (re-exchange)
|
||||
*
|
||||
* Transitions:
|
||||
@@ -313,6 +314,7 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
|
||||
|
||||
if ((session->dh_handshake_state != DH_STATE_INIT) &&
|
||||
(session->dh_handshake_state != DH_STATE_INIT_SENT) &&
|
||||
(session->dh_handshake_state != DH_STATE_REQUEST_SENT) &&
|
||||
(session->dh_handshake_state != DH_STATE_FINISHED))
|
||||
{
|
||||
rc = SSH_PACKET_DENIED;
|
||||
@@ -1158,7 +1160,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
uint32_t lenfield_blocksize = 8;
|
||||
size_t current_macsize = 0;
|
||||
uint8_t *ptr = NULL;
|
||||
ssize_t to_be_read;
|
||||
long to_be_read;
|
||||
int rc;
|
||||
uint8_t *cleartext_packet = NULL;
|
||||
uint8_t *packet_second_block = NULL;
|
||||
@@ -1268,7 +1270,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
/* remote sshd sends invalid sizes? */
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Given numbers of bytes left to be read < 0 (%zd)!",
|
||||
"Given numbers of bytes left to be read < 0 (%ld)!",
|
||||
to_be_read);
|
||||
goto error;
|
||||
}
|
||||
@@ -1286,7 +1288,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
/* give up, not enough data in buffer */
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"packet: partial packet (read len) "
|
||||
"[len=%" PRIu32 ", receivedlen=%zu, to_be_read=%zd]",
|
||||
"[len=%" PRIu32 ", receivedlen=%zu, to_be_read=%ld]",
|
||||
packet_len,
|
||||
receivedlen,
|
||||
to_be_read);
|
||||
@@ -1300,7 +1302,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
/* remaining encrypted bytes from the packet, MAC not included */
|
||||
packet_remaining = packet_len - (packet_offset - sizeof(uint32_t));
|
||||
cleartext_packet = ssh_buffer_allocate(session->in_buffer,
|
||||
(uint32_t)packet_remaining);
|
||||
packet_remaining);
|
||||
if (cleartext_packet == NULL) {
|
||||
goto error;
|
||||
}
|
||||
@@ -1476,7 +1478,6 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
|
||||
session->packet_state = PACKET_STATE_INIT;
|
||||
if (processed < receivedlen) {
|
||||
size_t num;
|
||||
/* Handle a potential packet left in socket buffer */
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Processing %zu bytes left in socket buffer",
|
||||
@@ -1484,10 +1485,9 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
|
||||
|
||||
ptr = ((uint8_t*)data) + processed;
|
||||
|
||||
num = ssh_packet_socket_callback(ptr,
|
||||
receivedlen - processed,
|
||||
user);
|
||||
processed += num;
|
||||
rc = ssh_packet_socket_callback(ptr, receivedlen - processed,
|
||||
user);
|
||||
processed += rc;
|
||||
}
|
||||
|
||||
ok = ssh_packet_need_rekey(session, 0);
|
||||
@@ -1856,7 +1856,7 @@ static int packet_send2(ssh_session session)
|
||||
if (hmac != NULL) {
|
||||
rc = ssh_buffer_add_data(session->out_buffer,
|
||||
hmac,
|
||||
(uint32_t)hmac_digest_len(hmac_type));
|
||||
hmac_digest_len(hmac_type));
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -291,6 +291,7 @@ SSH_PACKET_CALLBACK(ssh_packet_ext_info)
|
||||
for (i = 0; i < nr_extensions; i++) {
|
||||
char *name = NULL;
|
||||
char *value = NULL;
|
||||
int cmp;
|
||||
|
||||
rc = ssh_buffer_unpack(packet, "ss", &name, &value);
|
||||
if (rc != SSH_OK) {
|
||||
@@ -298,7 +299,8 @@ SSH_PACKET_CALLBACK(ssh_packet_ext_info)
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
if (strcmp(name, "server-sig-algs") == 0) {
|
||||
cmp = strcmp(name, "server-sig-algs");
|
||||
if (cmp == 0) {
|
||||
/* TODO check for NULL bytes */
|
||||
SSH_LOG(SSH_LOG_PACKET, "Extension: %s=<%s>", name, value);
|
||||
|
||||
@@ -311,9 +313,6 @@ SSH_PACKET_CALLBACK(ssh_packet_ext_info)
|
||||
if (rc == 1) {
|
||||
session->extensions |= SSH_EXT_SIG_RSA_SHA256;
|
||||
}
|
||||
} else if (strcmp(name, "publickey-hostbound@openssh.com") == 0) {
|
||||
SSH_LOG(SSH_LOG_PACKET, "Extension: %s=<%s>", name, value);
|
||||
session->extensions |= SSH_EXT_PUBLICKEY_HOSTBOUND;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_PACKET, "Unknown extension: %s", name);
|
||||
}
|
||||
|
||||
696
src/pki.c
696
src/pki.c
@@ -143,13 +143,18 @@ void ssh_key_clean (ssh_key key)
|
||||
|
||||
pki_key_clean(key);
|
||||
|
||||
#ifndef HAVE_LIBCRYPTO
|
||||
if (key->ed25519_privkey != NULL) {
|
||||
if (key->ed25519_privkey != NULL){
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
/* In OpenSSL implementation the private key is only the private
|
||||
* original seed. In the internal implementation the private key is the
|
||||
* concatenation of the original private seed with the public key.*/
|
||||
explicit_bzero(key->ed25519_privkey, ED25519_KEY_LEN);
|
||||
#else
|
||||
explicit_bzero(key->ed25519_privkey, sizeof(ed25519_privkey));
|
||||
#endif /* HAVE_LIBCRYPTO*/
|
||||
SAFE_FREE(key->ed25519_privkey);
|
||||
}
|
||||
SAFE_FREE(key->ed25519_pubkey);
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
if (key->cert != NULL) {
|
||||
SSH_BUFFER_FREE(key->cert);
|
||||
}
|
||||
@@ -405,59 +410,6 @@ bool ssh_key_size_allowed(ssh_session session, ssh_key key)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a key type to a hash type.
|
||||
*
|
||||
* @param[in] type The type to convert.
|
||||
*
|
||||
* @return A hash type to be used.
|
||||
*
|
||||
* @warning This helper function is available for use without session (for
|
||||
* example for signing commits) and might cause interoperability issues
|
||||
* when used within session! It is recommended to use
|
||||
* ssh_key_type_to_hash() instead of this helper directly when a
|
||||
* session is available.
|
||||
*
|
||||
* @note In order to follow current security best practises for RSA, defaults
|
||||
* to SHA-2 with SHA-512 digest (RFC8332) instead of the default for
|
||||
* the SSH protocol (SHA1 with RSA ; RFC 4253).
|
||||
*
|
||||
* @see ssh_key_type_to_hash()
|
||||
*/
|
||||
static enum ssh_digest_e key_type_to_hash(enum ssh_keytypes_e type)
|
||||
{
|
||||
switch (type) {
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
case SSH_KEYTYPE_RSA:
|
||||
return SSH_DIGEST_SHA512;
|
||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
return SSH_DIGEST_SHA256;
|
||||
case SSH_KEYTYPE_ECDSA_P384_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
return SSH_DIGEST_SHA384;
|
||||
case SSH_KEYTYPE_ECDSA_P521_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
return SSH_DIGEST_SHA512;
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
return SSH_DIGEST_AUTO;
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_DSS: /* deprecated */
|
||||
case SSH_KEYTYPE_DSS_CERT01: /* deprecated */
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Digest algorithm to be used with key type %u "
|
||||
"is not defined",
|
||||
type);
|
||||
}
|
||||
|
||||
/* We should never reach this */
|
||||
return SSH_DIGEST_AUTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a key type to a hash type. This is usually unambiguous
|
||||
* for all the key types, unless the SHA2 extension (RFC 8332) is
|
||||
@@ -501,8 +453,26 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
||||
/* Default algorithm for RSA is SHA1 */
|
||||
return SSH_DIGEST_SHA1;
|
||||
|
||||
case SSH_KEYTYPE_ECDSA_P256_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P256:
|
||||
return SSH_DIGEST_SHA256;
|
||||
case SSH_KEYTYPE_ECDSA_P384_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P384:
|
||||
return SSH_DIGEST_SHA384;
|
||||
case SSH_KEYTYPE_ECDSA_P521_CERT01:
|
||||
case SSH_KEYTYPE_ECDSA_P521:
|
||||
return SSH_DIGEST_SHA512;
|
||||
case SSH_KEYTYPE_ED25519_CERT01:
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
return SSH_DIGEST_AUTO;
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_DSS: /* deprecated */
|
||||
case SSH_KEYTYPE_DSS_CERT01: /* deprecated */
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
return key_type_to_hash(type);
|
||||
SSH_LOG(SSH_LOG_TRACE, "Digest algorithm to be used with key type %u "
|
||||
"is not defined", type);
|
||||
}
|
||||
|
||||
/* We should never reach this */
|
||||
@@ -731,12 +701,10 @@ int ssh_key_cmp(const ssh_key k1,
|
||||
ssh_buffer_get_len(k1->cert));
|
||||
}
|
||||
|
||||
#ifndef HAVE_LIBCRYPTO
|
||||
if (k1->type == SSH_KEYTYPE_ED25519 ||
|
||||
k1->type == SSH_KEYTYPE_SK_ED25519) {
|
||||
return pki_ed25519_key_cmp(k1, k2, what);
|
||||
}
|
||||
#endif
|
||||
|
||||
return pki_key_compare(k1, k2, what);
|
||||
}
|
||||
@@ -1375,12 +1343,6 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type,
|
||||
{
|
||||
ssh_string pubkey = NULL, privkey = NULL;
|
||||
|
||||
if (ssh_fips_mode()) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Ed25519 keys not supported in FIPS mode");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_unpack(buffer, "SS", &pubkey, &privkey);
|
||||
if (rc != SSH_OK){
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unpack error");
|
||||
@@ -1527,14 +1489,17 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = pki_pubkey_build_ed25519(key, pubkey);
|
||||
ssh_string_burn(pubkey);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to build ED25519 public key");
|
||||
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
ssh_string_burn(pubkey);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
|
||||
ssh_string_burn(pubkey);
|
||||
SSH_STRING_FREE(pubkey);
|
||||
|
||||
if (type == SSH_KEYTYPE_SK_ED25519) {
|
||||
ssh_string application = ssh_buffer_get_ssh_string(buffer);
|
||||
if (application == NULL) {
|
||||
@@ -1555,7 +1520,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown public key type %d", type);
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unknown public key protocol %d", type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -1734,9 +1699,8 @@ int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_add_data(buffer,
|
||||
ssh_string_data(key_blob),
|
||||
(uint32_t)ssh_string_len(key_blob));
|
||||
rc = ssh_buffer_add_data(buffer, ssh_string_data(key_blob),
|
||||
ssh_string_len(key_blob));
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Out of memory!");
|
||||
goto fail;
|
||||
@@ -2346,43 +2310,42 @@ int ssh_pki_export_pubkey_file(const ssh_key key,
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_ERROR otherwise.
|
||||
**/
|
||||
int ssh_pki_copy_cert_to_privkey(const ssh_key certkey, ssh_key privkey)
|
||||
{
|
||||
ssh_buffer cert_buffer = NULL;
|
||||
int rc, cmp;
|
||||
int ssh_pki_copy_cert_to_privkey(const ssh_key certkey, ssh_key privkey) {
|
||||
ssh_buffer cert_buffer = NULL;
|
||||
int rc, cmp;
|
||||
|
||||
if (certkey == NULL || privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (certkey == NULL || privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (privkey->cert != NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (privkey->cert != NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (certkey->cert == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (certkey->cert == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* make sure the public keys match */
|
||||
cmp = ssh_key_cmp(certkey, privkey, SSH_KEY_CMP_PUBLIC);
|
||||
if (cmp != 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* make sure the public keys match */
|
||||
cmp = ssh_key_cmp(certkey, privkey, SSH_KEY_CMP_PUBLIC);
|
||||
if (cmp != 0) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
cert_buffer = ssh_buffer_new();
|
||||
if (cert_buffer == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
cert_buffer = ssh_buffer_new();
|
||||
if (cert_buffer == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_add_buffer(cert_buffer, certkey->cert);
|
||||
if (rc != 0) {
|
||||
SSH_BUFFER_FREE(cert_buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
rc = ssh_buffer_add_buffer(cert_buffer, certkey->cert);
|
||||
if (rc != 0) {
|
||||
SSH_BUFFER_FREE(cert_buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
privkey->cert = cert_buffer;
|
||||
privkey->cert_type = certkey->type;
|
||||
return SSH_OK;
|
||||
privkey->cert = cert_buffer;
|
||||
privkey->cert_type = certkey->type;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_pki_export_signature_blob(const ssh_signature sig,
|
||||
@@ -2470,7 +2433,7 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob,
|
||||
|
||||
rc = ssh_buffer_add_data(buf,
|
||||
ssh_string_data(sig_blob),
|
||||
(uint32_t)ssh_string_len(sig_blob));
|
||||
ssh_string_len(sig_blob));
|
||||
if (rc < 0) {
|
||||
SSH_BUFFER_FREE(buf);
|
||||
return SSH_ERROR;
|
||||
@@ -2724,529 +2687,6 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
return pki_sign_data(privkey, hash_type, input, input_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encodes a binary signature blob as an sshsig armored signature
|
||||
*
|
||||
* @param blob The binary signature blob to encode
|
||||
* @param out_str Pointer to store the allocated base64 encoded string
|
||||
* Must be freed with ssh_string_free_char()
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
static int sshsig_armor(ssh_buffer blob, char **out_str)
|
||||
{
|
||||
char *b64_data = NULL;
|
||||
char *armored = NULL;
|
||||
const unsigned char *data = NULL;
|
||||
size_t len, b64_len, armored_len, num_lines;
|
||||
size_t i, j;
|
||||
|
||||
if (blob == NULL || out_str == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid input parameters");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
*out_str = NULL;
|
||||
|
||||
data = ssh_buffer_get(blob);
|
||||
len = ssh_buffer_get_len(blob);
|
||||
|
||||
b64_data = (char *)bin_to_base64(data, len);
|
||||
if (b64_data == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to base64 encode signature blob");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
b64_len = strlen(b64_data);
|
||||
|
||||
/* Calculate space needed: header + data with line breaks + footer */
|
||||
num_lines = (b64_len + SSHSIG_LINE_LENGTH - 1) /
|
||||
SSHSIG_LINE_LENGTH; /* Round up division */
|
||||
armored_len = strlen(SSHSIG_BEGIN_SIGNATURE) + 1 + /* header + \n */
|
||||
b64_len + num_lines + /* data + line breaks */
|
||||
strlen(SSHSIG_END_SIGNATURE) + 1; /* footer + \0 */
|
||||
|
||||
armored = calloc(armored_len, 1);
|
||||
if (armored == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to allocate %zu bytes for armored signature",
|
||||
armored_len);
|
||||
SAFE_FREE(b64_data);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
j = snprintf(armored, armored_len, SSHSIG_BEGIN_SIGNATURE "\n");
|
||||
for (i = 0; i < b64_len; i++) {
|
||||
if (i > 0 && i % SSHSIG_LINE_LENGTH == 0) {
|
||||
armored[j++] = '\n';
|
||||
}
|
||||
armored[j++] = b64_data[i];
|
||||
}
|
||||
armored[j++] = '\n';
|
||||
snprintf(armored + j, armored_len - j, SSHSIG_END_SIGNATURE);
|
||||
|
||||
SAFE_FREE(b64_data);
|
||||
|
||||
*out_str = armored;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dearmor an sshsig signature from ASCII armored format to binary
|
||||
*
|
||||
* @param[in] signature The armored sshsig signature string
|
||||
* @param[out] out Pointer to store the allocated binary buffer
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
static int sshsig_dearmor(const char *signature, ssh_buffer *out)
|
||||
{
|
||||
const char *begin = NULL;
|
||||
const char *end = NULL;
|
||||
char *clean_b64 = NULL;
|
||||
ssh_buffer decoded_buffer = NULL;
|
||||
int i, j;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
if (signature == NULL || out == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid input parameters");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
*out = NULL;
|
||||
|
||||
rc = strncmp(signature,
|
||||
SSHSIG_BEGIN_SIGNATURE,
|
||||
strlen(SSHSIG_BEGIN_SIGNATURE));
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Signature does not start with expected header");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
begin = signature + strlen(SSHSIG_BEGIN_SIGNATURE);
|
||||
while (isspace(*begin)) {
|
||||
begin++;
|
||||
}
|
||||
|
||||
end = strstr(begin, SSHSIG_END_SIGNATURE);
|
||||
if (end == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Signature end marker not found");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Backtrack to find the real end of data */
|
||||
while (end > begin && (isspace(*(end - 1)))) {
|
||||
end--;
|
||||
}
|
||||
|
||||
clean_b64 = calloc(end - begin + 1, 1);
|
||||
if (clean_b64 == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to allocate %td bytes for clean base64 data",
|
||||
end - begin + 1);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; begin + i < end; i++) {
|
||||
if (!isspace(begin[i])) {
|
||||
clean_b64[j++] = begin[i];
|
||||
}
|
||||
}
|
||||
clean_b64[j] = '\0';
|
||||
|
||||
decoded_buffer = base64_to_bin(clean_b64);
|
||||
SAFE_FREE(clean_b64);
|
||||
|
||||
if (decoded_buffer == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to decode base64 signature data");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
*out = decoded_buffer;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Common helper function to prepare the data in sshsig format
|
||||
*
|
||||
* This function handles the common logic to prepare the sshsig format:
|
||||
* 1. Hash the input data using the specified algorithm
|
||||
* 2. Build the data buffer to sign
|
||||
*
|
||||
* @param data The raw data to process
|
||||
* @param data_length The length of the data
|
||||
* @param hash_alg The hash algorithm to use (sha256 or sha512)
|
||||
* @param sig_namespace The signature namespace
|
||||
* @param tosign_buf Pointer to store the allocated to-sign buffer
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
static int sshsig_prepare_data(const void *data,
|
||||
size_t data_length,
|
||||
const char *hash_alg,
|
||||
const char *sig_namespace,
|
||||
ssh_buffer *tosign_buf)
|
||||
{
|
||||
ssh_buffer tosign = NULL;
|
||||
ssh_string hash_string = NULL;
|
||||
char hash[SHA512_DIGEST_LEN];
|
||||
size_t hash_len;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
if (data == NULL || hash_alg == NULL || sig_namespace == NULL ||
|
||||
tosign_buf == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid input parameters");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
*tosign_buf = NULL;
|
||||
|
||||
if (strcmp(hash_alg, "sha256") == 0) {
|
||||
hash_len = SHA256_DIGEST_LEN;
|
||||
rc = sha256(data, data_length, (unsigned char *)hash);
|
||||
} else if (strcmp(hash_alg, "sha512") == 0) {
|
||||
hash_len = SHA512_DIGEST_LEN;
|
||||
rc = sha512(data, data_length, (unsigned char *)hash);
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unsupported hash algorithm: %s", hash_alg);
|
||||
goto cleanup;
|
||||
}
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to compute %s hash of data", hash_alg);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
hash_string = ssh_string_new(hash_len);
|
||||
if (hash_string == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to allocate ssh_string for hash");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = ssh_string_fill(hash_string, hash, hash_len);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to fill ssh_string with hash data");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
tosign = ssh_buffer_new();
|
||||
if (tosign == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to allocate buffer for signing data");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(tosign,
|
||||
"tsssS",
|
||||
SSHSIG_MAGIC_PREAMBLE,
|
||||
sig_namespace,
|
||||
"",
|
||||
hash_alg,
|
||||
hash_string);
|
||||
|
||||
if (rc == SSH_OK) {
|
||||
*tosign_buf = tosign;
|
||||
tosign = NULL;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to pack signing data into buffer");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
SSH_BUFFER_FREE(tosign);
|
||||
SSH_STRING_FREE(hash_string);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Signs data in sshsig compatible format
|
||||
*
|
||||
* @param data The data to sign
|
||||
* @param data_length The length of the data
|
||||
* @param privkey The private key to sign with
|
||||
* @param hash_alg The hash algorithm to use (SSHSIG_DIGEST_SHA2_256 or
|
||||
* SSHSIG_DIGEST_SHA2_512)
|
||||
* @param sig_namespace The signature namespace (e.g. "file", "email", etc.)
|
||||
* @param signature Pointer to store the allocated signature string in the
|
||||
* armored format. Must be freed with
|
||||
* ssh_string_free_char()
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int sshsig_sign(const void *data,
|
||||
size_t data_length,
|
||||
ssh_key privkey,
|
||||
const char *sig_namespace,
|
||||
enum sshsig_digest_e hash_alg,
|
||||
char **signature)
|
||||
{
|
||||
ssh_buffer tosign = NULL;
|
||||
ssh_buffer signature_blob = NULL;
|
||||
ssh_signature sig = NULL;
|
||||
ssh_string sig_string = NULL;
|
||||
ssh_string pub_blob = NULL;
|
||||
enum ssh_digest_e digest_type;
|
||||
const char *hash_alg_str = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
|
||||
if (privkey == NULL || data == NULL || sig_namespace == NULL ||
|
||||
signature == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid parameters provided to sshsig_sign");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (strlen(sig_namespace) == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid parameters provided to sshsig_sign: empty namespace "
|
||||
"string");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
*signature = NULL;
|
||||
|
||||
if (hash_alg == SSHSIG_DIGEST_SHA2_256) {
|
||||
hash_alg_str = "sha256";
|
||||
} else if (hash_alg == SSHSIG_DIGEST_SHA2_512) {
|
||||
hash_alg_str = "sha512";
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid hash algorithm %d", hash_alg);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = sshsig_prepare_data(data,
|
||||
data_length,
|
||||
hash_alg_str,
|
||||
sig_namespace,
|
||||
&tosign);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to prepare data for sshsig signing");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
digest_type = key_type_to_hash(ssh_key_type_plain(privkey->type));
|
||||
sig = pki_sign_data(privkey,
|
||||
digest_type,
|
||||
ssh_buffer_get(tosign),
|
||||
ssh_buffer_get_len(tosign));
|
||||
if (sig == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to sign data with private key");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = ssh_pki_export_pubkey_blob(privkey, &pub_blob);
|
||||
if (rc != SSH_OK || pub_blob == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to export public key blob from private key");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = ssh_pki_export_signature_blob(sig, &sig_string);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to export signature blob");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
signature_blob = ssh_buffer_new();
|
||||
if (signature_blob == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to allocate signature buffer");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(signature_blob,
|
||||
"tdSsssS",
|
||||
SSHSIG_MAGIC_PREAMBLE,
|
||||
SSHSIG_VERSION,
|
||||
pub_blob,
|
||||
sig_namespace,
|
||||
"",
|
||||
hash_alg_str,
|
||||
sig_string);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to pack signature blob");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = sshsig_armor(signature_blob, signature);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to armor signature blob");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
SSH_BUFFER_FREE(tosign);
|
||||
SSH_BUFFER_FREE(signature_blob);
|
||||
SSH_SIGNATURE_FREE(sig);
|
||||
SSH_STRING_FREE(sig_string);
|
||||
SSH_STRING_FREE(pub_blob);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verifies an sshsig formatted signature against data
|
||||
*
|
||||
* @param data The data to verify
|
||||
* @param data_length The length of the data
|
||||
* @param signature The armored sshsig signature
|
||||
* @param sig_namespace The expected signature namespace
|
||||
* @param sign_key If not NULL, returns the allocated public key that was
|
||||
* used for signing this data. Must be freed with
|
||||
* ssh_key_free(). Note that this is an output parameter
|
||||
* and is not checked against "allowed signers". The
|
||||
* caller needs to compare it with expected signer key
|
||||
* using ssh_key_cmp().
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on verification failure
|
||||
*/
|
||||
int sshsig_verify(const void *data,
|
||||
size_t data_length,
|
||||
const char *signature,
|
||||
const char *sig_namespace,
|
||||
ssh_key *sign_key)
|
||||
{
|
||||
ssh_buffer sig_buf = NULL;
|
||||
ssh_buffer tosign = NULL;
|
||||
ssh_key key = NULL;
|
||||
char *hash_alg_str = NULL;
|
||||
ssh_string sig_data = NULL;
|
||||
ssh_string sig_namespace_str = NULL;
|
||||
ssh_string reserved_str = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
ssh_signature signature_obj = NULL;
|
||||
uint32_t sig_version;
|
||||
|
||||
if (sign_key != NULL) {
|
||||
*sign_key = NULL;
|
||||
}
|
||||
|
||||
if (signature == NULL || data == NULL || sig_namespace == NULL) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid parameters provided to sshsig_verify");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (strlen(sig_namespace) == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid parameters provided to sshsig_verify: empty namespace "
|
||||
"string");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = sshsig_dearmor(signature, &sig_buf);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to dearmor signature");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (ssh_buffer_get_len(sig_buf) < SSHSIG_MAGIC_PREAMBLE_LEN ||
|
||||
memcmp(ssh_buffer_get(sig_buf),
|
||||
SSHSIG_MAGIC_PREAMBLE,
|
||||
SSHSIG_MAGIC_PREAMBLE_LEN) != 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid signature magic preamble");
|
||||
SSH_BUFFER_FREE(sig_buf);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ssh_buffer_pass_bytes(sig_buf, SSHSIG_MAGIC_PREAMBLE_LEN);
|
||||
rc = ssh_buffer_unpack(sig_buf,
|
||||
"dSSSsS",
|
||||
&sig_version,
|
||||
&pubkey_blob,
|
||||
&sig_namespace_str,
|
||||
&reserved_str,
|
||||
&hash_alg_str,
|
||||
&sig_data);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to unpack signature buffer");
|
||||
SSH_BUFFER_FREE(sig_buf);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (sig_version != SSHSIG_VERSION) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Unsupported signature version %u, expected %u",
|
||||
sig_version,
|
||||
SSHSIG_VERSION);
|
||||
rc = SSH_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_pubkey_blob(pubkey_blob, &key);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to import public key from signature");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ssh_string_len(sig_namespace_str) != strlen(sig_namespace) ||
|
||||
memcmp(ssh_string_data(sig_namespace_str),
|
||||
sig_namespace,
|
||||
strlen(sig_namespace)) != 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Signature namespace mismatch: expected '%s', got '%s'",
|
||||
sig_namespace,
|
||||
ssh_string_get_char(sig_namespace_str));
|
||||
rc = SSH_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (strcmp(hash_alg_str, "sha256") != 0 &&
|
||||
strcmp(hash_alg_str, "sha512") != 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Unsupported hash algorithm '%s'", hash_alg_str);
|
||||
rc = SSH_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = sshsig_prepare_data(data,
|
||||
data_length,
|
||||
hash_alg_str,
|
||||
sig_namespace,
|
||||
&tosign);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Failed to prepare data for sshsig verification");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = ssh_pki_import_signature_blob(sig_data, key, &signature_obj);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Failed to import signature blob");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = pki_verify_data_signature(signature_obj,
|
||||
key,
|
||||
ssh_buffer_get(tosign),
|
||||
ssh_buffer_get_len(tosign));
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Signature verification failed");
|
||||
goto cleanup;
|
||||
}
|
||||
if (strlen(sig_namespace) == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Invalid parameters provided to sshsig_verify: empty namespace "
|
||||
"string");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (sign_key != NULL) {
|
||||
*sign_key = key;
|
||||
key = NULL; /* Transferred ownership */
|
||||
}
|
||||
|
||||
cleanup:
|
||||
SSH_STRING_FREE(pubkey_blob);
|
||||
SSH_STRING_FREE(sig_namespace_str);
|
||||
SSH_STRING_FREE(reserved_str);
|
||||
SSH_STRING_FREE(sig_data);
|
||||
SSH_BUFFER_FREE(tosign);
|
||||
SSH_BUFFER_FREE(sig_buf);
|
||||
SSH_KEY_FREE(key);
|
||||
SAFE_FREE(hash_alg_str);
|
||||
SSH_SIGNATURE_FREE(signature_obj);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function signs the session id as a string then
|
||||
* the content of sigbuf */
|
||||
|
||||
@@ -155,7 +155,7 @@ static int pki_private_key_decrypt(ssh_string blob,
|
||||
}
|
||||
rc = ssh_buffer_add_data(buffer,
|
||||
ssh_string_data(kdfoptions),
|
||||
(uint32_t)ssh_string_len(kdfoptions));
|
||||
ssh_string_len(kdfoptions));
|
||||
if (rc != SSH_ERROR){
|
||||
rc = ssh_buffer_unpack(buffer, "Sd", &salt, &rounds);
|
||||
}
|
||||
@@ -339,7 +339,7 @@ ssh_pki_openssh_import(const char *text_key,
|
||||
ssh_buffer_set_secure(privkey_buffer);
|
||||
ssh_buffer_add_data(privkey_buffer,
|
||||
ssh_string_data(privkeys),
|
||||
(uint32_t)ssh_string_len(privkeys));
|
||||
ssh_string_len(privkeys));
|
||||
|
||||
rc = ssh_buffer_unpack(privkey_buffer, "dd", &checkint1, &checkint2);
|
||||
if (rc == SSH_ERROR || checkint1 != checkint2) {
|
||||
|
||||
1219
src/pki_crypto.c
1219
src/pki_crypto.c
File diff suppressed because it is too large
Load Diff
@@ -28,205 +28,6 @@
|
||||
#include "libssh/ed25519.h"
|
||||
#include "libssh/buffer.h"
|
||||
|
||||
int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey)
|
||||
{
|
||||
if (ssh_string_len(pubkey) != ED25519_KEY_LEN) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int pki_privkey_build_ed25519(ssh_key key,
|
||||
ssh_string pubkey,
|
||||
ssh_string privkey)
|
||||
{
|
||||
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
|
||||
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* In the internal implementation, the private key is the concatenation of
|
||||
* the private seed with the public key. */
|
||||
key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
|
||||
if (key->ed25519_privkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(key->ed25519_privkey, ssh_string_data(privkey), 2 * ED25519_KEY_LEN);
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
SAFE_FREE(key->ed25519_privkey);
|
||||
SAFE_FREE(key->ed25519_pubkey);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Compare ed25519 keys if they are equal.
|
||||
*
|
||||
* @param[in] k1 The first key to compare.
|
||||
*
|
||||
* @param[in] k2 The second key to compare.
|
||||
*
|
||||
* @param[in] what What part or type of the key do you want to compare.
|
||||
*
|
||||
* @return 0 if equal, 1 if not.
|
||||
*/
|
||||
int
|
||||
pki_ed25519_key_cmp(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
switch (what) {
|
||||
case SSH_KEY_CMP_PRIVATE:
|
||||
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
|
||||
return 1;
|
||||
}
|
||||
/* In the internal implementation, the private key is the concatenation
|
||||
* of the private seed with the public key. */
|
||||
cmp = memcmp(k1->ed25519_privkey,
|
||||
k2->ed25519_privkey,
|
||||
2 * ED25519_KEY_LEN);
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
case SSH_KEY_CMP_PUBLIC:
|
||||
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
|
||||
return 1;
|
||||
}
|
||||
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case SSH_KEY_CMP_CERTIFICATE:
|
||||
/* handled globally */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Duplicate an Ed25519 key
|
||||
*
|
||||
* @param[out] new Pre-initialized ssh_key structure
|
||||
*
|
||||
* @param[in] key Key to copy
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key)
|
||||
{
|
||||
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (key->ed25519_privkey != NULL) {
|
||||
/* In the internal implementation, the private key is the concatenation
|
||||
* of the private seed with the public key. */
|
||||
new_key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
|
||||
if (new_key->ed25519_privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(new_key->ed25519_privkey,
|
||||
key->ed25519_privkey,
|
||||
2 * ED25519_KEY_LEN);
|
||||
}
|
||||
|
||||
if (key->ed25519_pubkey != NULL) {
|
||||
new_key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (new_key->ed25519_pubkey == NULL) {
|
||||
SAFE_FREE(new_key->ed25519_privkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(new_key->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Outputs an Ed25519 public key in a blob buffer.
|
||||
*
|
||||
* @param[out] buffer Output buffer
|
||||
*
|
||||
* @param[in] key Key to output
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(buffer,
|
||||
"dP",
|
||||
(uint32_t)ED25519_KEY_LEN,
|
||||
(size_t)ED25519_KEY_LEN,
|
||||
key->ed25519_pubkey);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief exports a ed25519 private key to a string blob.
|
||||
* @param[in] privkey private key to convert
|
||||
* @param[out] buffer buffer to write the blob in.
|
||||
* @returns SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (privkey->type != SSH_KEYTYPE_ED25519) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (privkey->ed25519_privkey == NULL || privkey->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
rc = ssh_buffer_pack(buffer,
|
||||
"dPdPP",
|
||||
(uint32_t)ED25519_KEY_LEN,
|
||||
(size_t)ED25519_KEY_LEN,
|
||||
privkey->ed25519_pubkey,
|
||||
(uint32_t)(2 * ED25519_KEY_LEN),
|
||||
(size_t)ED25519_KEY_LEN,
|
||||
privkey->ed25519_privkey,
|
||||
(size_t)ED25519_KEY_LEN,
|
||||
privkey->ed25519_pubkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int pki_key_generate_ed25519(ssh_key key)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -27,6 +27,213 @@
|
||||
#include "libssh/pki_priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
|
||||
int pki_privkey_build_ed25519(ssh_key key,
|
||||
ssh_string pubkey,
|
||||
ssh_string privkey)
|
||||
{
|
||||
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
|
||||
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN))
|
||||
{
|
||||
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
/* In OpenSSL implementation, the private key is the original private seed,
|
||||
* without the public key. */
|
||||
key->ed25519_privkey = malloc(ED25519_KEY_LEN);
|
||||
#else
|
||||
/* In the internal implementation, the private key is the concatenation of
|
||||
* the private seed with the public key. */
|
||||
key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
if (key->ed25519_privkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
|
||||
ED25519_KEY_LEN);
|
||||
#else
|
||||
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
|
||||
2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
|
||||
ED25519_KEY_LEN);
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
SAFE_FREE(key->ed25519_privkey);
|
||||
SAFE_FREE(key->ed25519_pubkey);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Compare ed25519 keys if they are equal.
|
||||
*
|
||||
* @param[in] k1 The first key to compare.
|
||||
*
|
||||
* @param[in] k2 The second key to compare.
|
||||
*
|
||||
* @param[in] what What part or type of the key do you want to compare.
|
||||
*
|
||||
* @return 0 if equal, 1 if not.
|
||||
*/
|
||||
int pki_ed25519_key_cmp(const ssh_key k1,
|
||||
const ssh_key k2,
|
||||
enum ssh_keycmp_e what)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
switch(what) {
|
||||
case SSH_KEY_CMP_PRIVATE:
|
||||
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
|
||||
return 1;
|
||||
}
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
/* In OpenSSL implementation, the private key is the original private
|
||||
* seed, without the public key. */
|
||||
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_KEY_LEN);
|
||||
#else
|
||||
/* In the internal implementation, the private key is the concatenation
|
||||
* of the private seed with the public key. */
|
||||
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey,
|
||||
2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
FALL_THROUGH;
|
||||
case SSH_KEY_CMP_PUBLIC:
|
||||
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
|
||||
return 1;
|
||||
}
|
||||
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case SSH_KEY_CMP_CERTIFICATE:
|
||||
/* handled globally */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Duplicate an Ed25519 key
|
||||
*
|
||||
* @param[out] new Pre-initialized ssh_key structure
|
||||
*
|
||||
* @param[in] key Key to copy
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key)
|
||||
{
|
||||
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (key->ed25519_privkey != NULL) {
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
/* In OpenSSL implementation, the private key is the original private
|
||||
* seed, without the public key. */
|
||||
new_key->ed25519_privkey = malloc(ED25519_KEY_LEN);
|
||||
#else
|
||||
/* In the internal implementation, the private key is the concatenation
|
||||
* of the private seed with the public key. */
|
||||
new_key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
if (new_key->ed25519_privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
memcpy(new_key->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN);
|
||||
#else
|
||||
memcpy(new_key->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (key->ed25519_pubkey != NULL) {
|
||||
new_key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
|
||||
if (new_key->ed25519_pubkey == NULL) {
|
||||
SAFE_FREE(new_key->ed25519_privkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(new_key->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Outputs an Ed25519 public key in a blob buffer.
|
||||
*
|
||||
* @param[out] buffer Output buffer
|
||||
*
|
||||
* @param[in] key Key to output
|
||||
*
|
||||
* @return SSH_ERROR on error, SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (key->ed25519_pubkey == NULL){
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(buffer,
|
||||
"dP",
|
||||
(uint32_t)ED25519_KEY_LEN,
|
||||
(size_t)ED25519_KEY_LEN, key->ed25519_pubkey);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief exports a ed25519 private key to a string blob.
|
||||
* @param[in] privkey private key to convert
|
||||
* @param[out] buffer buffer to write the blob in.
|
||||
* @returns SSH_OK on success
|
||||
*/
|
||||
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (privkey->type != SSH_KEYTYPE_ED25519) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (privkey->ed25519_privkey == NULL ||
|
||||
privkey->ed25519_pubkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
rc = ssh_buffer_pack(buffer,
|
||||
"dPdPP",
|
||||
(uint32_t)ED25519_KEY_LEN,
|
||||
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey,
|
||||
(uint32_t)(2 * ED25519_KEY_LEN),
|
||||
(size_t)ED25519_KEY_LEN, privkey->ed25519_privkey,
|
||||
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
|
||||
2135
src/pki_gcrypt.c
2135
src/pki_gcrypt.c
File diff suppressed because it is too large
Load Diff
51
src/poll.c
51
src/poll.c
@@ -422,7 +422,7 @@ void ssh_poll_set_events(ssh_poll_handle p, short events)
|
||||
{
|
||||
p->events = events;
|
||||
if (p->ctx != NULL) {
|
||||
if (p->lock_cnt == 0) {
|
||||
if (!ssh_poll_is_locked(p)) {
|
||||
p->ctx->pollfds[p->x.idx].events = events;
|
||||
} else if (!(p->ctx->pollfds[p->x.idx].events & POLLOUT)) {
|
||||
/* if locked, allow only setting POLLOUT to prevent recursive
|
||||
@@ -560,30 +560,29 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx)
|
||||
|
||||
static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size)
|
||||
{
|
||||
ssh_poll_handle *pollptrs = NULL;
|
||||
ssh_pollfd_t *pollfds = NULL;
|
||||
ssh_poll_handle *pollptrs = NULL;
|
||||
ssh_pollfd_t *pollfds = NULL;
|
||||
|
||||
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * new_size);
|
||||
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * new_size);
|
||||
if (pollptrs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->pollptrs = pollptrs;
|
||||
|
||||
pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
|
||||
if (pollfds == NULL) {
|
||||
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * ctx->polls_allocated);
|
||||
if (pollptrs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->pollptrs = pollptrs;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
|
||||
if (pollfds == NULL) {
|
||||
pollptrs = realloc(ctx->pollptrs,
|
||||
sizeof(ssh_poll_handle) * ctx->polls_allocated);
|
||||
if (pollptrs == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ctx->pollptrs = pollptrs;
|
||||
return -1;
|
||||
}
|
||||
ctx->pollfds = pollfds;
|
||||
ctx->polls_allocated = new_size;
|
||||
|
||||
ctx->pollfds = pollfds;
|
||||
ctx->polls_allocated = new_size;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -670,6 +669,20 @@ void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns if a poll object is locked.
|
||||
*
|
||||
* @param p Pointer to an already allocated poll object.
|
||||
* @returns true if the poll object is locked; false otherwise.
|
||||
*/
|
||||
bool ssh_poll_is_locked(ssh_poll_handle p)
|
||||
{
|
||||
if (p == NULL) {
|
||||
return false;
|
||||
}
|
||||
return p->lock_cnt > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Poll all the sockets associated through a poll object with a
|
||||
* poll context. If any of the events are set after the poll, the
|
||||
@@ -704,7 +717,7 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout)
|
||||
* output buffer */
|
||||
for (i = 0; i < ctx->polls_used; i++) {
|
||||
/* The lock allows only POLLOUT events: drop the rest */
|
||||
if (ctx->pollptrs[i]->lock_cnt > 0) {
|
||||
if (ssh_poll_is_locked(ctx->pollptrs[i])) {
|
||||
ctx->pollfds[i].events &= POLLOUT;
|
||||
}
|
||||
}
|
||||
|
||||
12
src/server.c
12
src/server.c
@@ -230,13 +230,11 @@ static int ssh_server_send_extensions(ssh_session session)
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bdssss",
|
||||
"bdss",
|
||||
SSH2_MSG_EXT_INFO,
|
||||
2, /* nr. of extensions */
|
||||
1, /* nr. of extensions */
|
||||
"server-sig-algs",
|
||||
hostkey_algorithms,
|
||||
"publickey-hostbound@openssh.com",
|
||||
"0");
|
||||
hostkey_algorithms);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
@@ -485,8 +483,8 @@ static size_t callback_receive_banner(const void *data, size_t len, void *user)
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_IN,
|
||||
buffer,
|
||||
(uint32_t)(i + 1),
|
||||
(uint32_t)(i + 1));
|
||||
i + 1,
|
||||
i + 1);
|
||||
}
|
||||
#endif
|
||||
if (buffer[i] == '\r') {
|
||||
|
||||
224
src/session.c
224
src/session.c
@@ -429,34 +429,28 @@ const char* ssh_get_kex_algo(ssh_session session) {
|
||||
}
|
||||
|
||||
switch (session->current_crypto->kex_type) {
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
return "diffie-hellman-group1-sha1";
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
return "diffie-hellman-group14-sha1";
|
||||
case SSH_KEX_DH_GROUP14_SHA256:
|
||||
return "diffie-hellman-group14-sha256";
|
||||
case SSH_KEX_DH_GROUP16_SHA512:
|
||||
return "diffie-hellman-group16-sha512";
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
return "diffie-hellman-group18-sha512";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
return "ecdh-sha2-nistp256";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
return "ecdh-sha2-nistp384";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
return "ecdh-sha2-nistp521";
|
||||
case SSH_KEX_CURVE25519_SHA256:
|
||||
return "curve25519-sha256";
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
return "curve25519-sha256@libssh.org";
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
|
||||
return "sntrup761x25519-sha512@openssh.com";
|
||||
#ifdef WITH_GEX
|
||||
case SSH_KEX_DH_GEX_SHA1:
|
||||
return "diffie-hellman-group-exchange-sha1";
|
||||
case SSH_KEX_DH_GEX_SHA256:
|
||||
return "diffie-hellman-group-exchange-sha256";
|
||||
#endif /* WITH_GEX */
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
return "diffie-hellman-group1-sha1";
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
return "diffie-hellman-group14-sha1";
|
||||
case SSH_KEX_DH_GROUP14_SHA256:
|
||||
return "diffie-hellman-group14-sha256";
|
||||
case SSH_KEX_DH_GROUP16_SHA512:
|
||||
return "diffie-hellman-group16-sha512";
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
return "diffie-hellman-group18-sha512";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
return "ecdh-sha2-nistp256";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
return "ecdh-sha2-nistp384";
|
||||
case SSH_KEX_ECDH_SHA2_NISTP521:
|
||||
return "ecdh-sha2-nistp521";
|
||||
case SSH_KEX_CURVE25519_SHA256:
|
||||
return "curve25519-sha256";
|
||||
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
|
||||
return "curve25519-sha256@libssh.org";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -1238,108 +1232,110 @@ int ssh_get_publickey_hash(const ssh_key key,
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SSH_PUBLICKEY_HASH_SHA1: {
|
||||
SHACTX ctx = NULL;
|
||||
case SSH_PUBLICKEY_HASH_SHA1:
|
||||
{
|
||||
SHACTX ctx = NULL;
|
||||
|
||||
h = calloc(1, SHA_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
h = calloc(1, SHA_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
ctx = sha1_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
sha1_ctx_free(ctx);
|
||||
goto out;
|
||||
}
|
||||
rc = sha1_final(h, ctx);
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
goto out;
|
||||
}
|
||||
rc = sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
sha1_ctx_free(ctx);
|
||||
goto out;
|
||||
}
|
||||
rc = sha1_final(h, ctx);
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*hlen = SHA_DIGEST_LEN;
|
||||
*hlen = SHA_DIGEST_LEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SSH_PUBLICKEY_HASH_SHA256: {
|
||||
SHA256CTX ctx = NULL;
|
||||
case SSH_PUBLICKEY_HASH_SHA256:
|
||||
{
|
||||
SHA256CTX ctx = NULL;
|
||||
|
||||
h = calloc(1, SHA256_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
h = calloc(1, SHA256_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx = sha256_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
ctx = sha256_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
sha256_ctx_free(ctx);
|
||||
goto out;
|
||||
}
|
||||
rc = sha256_final(h, ctx);
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
goto out;
|
||||
}
|
||||
rc = sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
sha256_ctx_free(ctx);
|
||||
goto out;
|
||||
}
|
||||
rc = sha256_final(h, ctx);
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*hlen = SHA256_DIGEST_LEN;
|
||||
*hlen = SHA256_DIGEST_LEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SSH_PUBLICKEY_HASH_MD5: {
|
||||
MD5CTX ctx = NULL;
|
||||
case SSH_PUBLICKEY_HASH_MD5:
|
||||
{
|
||||
MD5CTX ctx = NULL;
|
||||
|
||||
/* In FIPS mode, we cannot use MD5 */
|
||||
if (ssh_fips_mode()) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"In FIPS mode MD5 is not allowed."
|
||||
"Try using SSH_PUBLICKEY_HASH_SHA256");
|
||||
rc = SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
/* In FIPS mode, we cannot use MD5 */
|
||||
if (ssh_fips_mode()) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "In FIPS mode MD5 is not allowed."
|
||||
"Try using SSH_PUBLICKEY_HASH_SHA256");
|
||||
rc = SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
h = calloc(1, MD5_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
h = calloc(1, MD5_DIGEST_LEN);
|
||||
if (h == NULL) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx = md5_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
ctx = md5_init();
|
||||
if (ctx == NULL) {
|
||||
free(h);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
md5_ctx_free(ctx);
|
||||
goto out;
|
||||
}
|
||||
rc = md5_final(h, ctx);
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
goto out;
|
||||
}
|
||||
rc = md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
md5_ctx_free(ctx);
|
||||
goto out;
|
||||
}
|
||||
rc = md5_final(h, ctx);
|
||||
if (rc != SSH_OK) {
|
||||
free(h);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*hlen = MD5_DIGEST_LEN;
|
||||
*hlen = MD5_DIGEST_LEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rc = -1;
|
||||
goto out;
|
||||
|
||||
1107
src/sftp.c
1107
src/sftp.c
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
|
||||
sftp_session sftp = NULL;
|
||||
ssh_buffer buffer = NULL;
|
||||
sftp_aio aio_handle = NULL;
|
||||
uint32_t id, read_len;
|
||||
uint32_t id;
|
||||
int rc;
|
||||
|
||||
if (file == NULL ||
|
||||
@@ -73,12 +73,10 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Apply a cap on the length a user is allowed to read
|
||||
*
|
||||
* The limits are in theory uint64, but packet contain data length in uint32
|
||||
* so in practice, the limit will never be larger than UINT32_MAX
|
||||
*/
|
||||
read_len = (uint32_t)MIN(sftp->limits->max_read_length, len);
|
||||
/* Apply a cap on the length a user is allowed to read */
|
||||
if (len > sftp->limits->max_read_length) {
|
||||
len = sftp->limits->max_read_length;
|
||||
}
|
||||
|
||||
if (aio == NULL) {
|
||||
ssh_set_error(sftp->session, SSH_FATAL,
|
||||
@@ -102,7 +100,7 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
|
||||
id,
|
||||
file->handle,
|
||||
file->offset,
|
||||
read_len);
|
||||
len);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(sftp->session);
|
||||
@@ -121,7 +119,7 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
|
||||
|
||||
aio_handle->file = file;
|
||||
aio_handle->id = id;
|
||||
aio_handle->len = read_len;
|
||||
aio_handle->len = len;
|
||||
|
||||
rc = sftp_packet_write(sftp, SSH_FXP_READ, buffer);
|
||||
SSH_BUFFER_FREE(buffer);
|
||||
@@ -131,9 +129,9 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
|
||||
}
|
||||
|
||||
/* Assume we read len bytes from the file */
|
||||
file->offset += read_len;
|
||||
file->offset += len;
|
||||
*aio = aio_handle;
|
||||
return read_len;
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t sftp_aio_wait_read(sftp_aio *aio,
|
||||
@@ -204,15 +202,21 @@ ssize_t sftp_aio_wait_read(sftp_aio *aio,
|
||||
}
|
||||
|
||||
/* handle an existing request */
|
||||
rc = sftp_recv_response_msg(sftp, (*aio)->id, !file->nonblocking, &msg);
|
||||
if (rc == SSH_ERROR) {
|
||||
SFTP_AIO_FREE(*aio);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
while (msg == NULL) {
|
||||
if (file->nonblocking) {
|
||||
if (ssh_channel_poll(sftp->channel, 0) == 0) {
|
||||
/* we cannot block */
|
||||
return SSH_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == SSH_AGAIN) {
|
||||
/* return without freeing the (*aio) */
|
||||
return SSH_AGAIN;
|
||||
if (sftp_read_and_dispatch(sftp) < 0) {
|
||||
/* something nasty has happened */
|
||||
SFTP_AIO_FREE(*aio);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
msg = sftp_dequeue(sftp, (*aio)->id);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -311,7 +315,7 @@ ssize_t sftp_aio_begin_write(sftp_file file,
|
||||
sftp_session sftp = NULL;
|
||||
ssh_buffer buffer = NULL;
|
||||
sftp_aio aio_handle = NULL;
|
||||
uint32_t id, write_len;
|
||||
uint32_t id;
|
||||
int rc;
|
||||
|
||||
if (file == NULL ||
|
||||
@@ -337,12 +341,10 @@ ssize_t sftp_aio_begin_write(sftp_file file,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Apply a cap on the length a user is allowed to write
|
||||
*
|
||||
* The limits are in theory uint64, but packet contain data length in uint32
|
||||
* so in practice, the limit will never be larger than UINT32_MAX
|
||||
*/
|
||||
write_len = (uint32_t)MIN(sftp->limits->max_write_length, len);
|
||||
/* Apply a cap on the length a user is allowed to write */
|
||||
if (len > sftp->limits->max_write_length) {
|
||||
len = sftp->limits->max_write_length;
|
||||
}
|
||||
|
||||
if (aio == NULL) {
|
||||
ssh_set_error(sftp->session, SSH_FATAL,
|
||||
@@ -365,9 +367,8 @@ ssize_t sftp_aio_begin_write(sftp_file file,
|
||||
id,
|
||||
file->handle,
|
||||
file->offset,
|
||||
write_len, /* len of datastring */
|
||||
(size_t)write_len,
|
||||
buf);
|
||||
len, /* len of datastring */
|
||||
len, buf);
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(sftp->session);
|
||||
@@ -386,7 +387,7 @@ ssize_t sftp_aio_begin_write(sftp_file file,
|
||||
|
||||
aio_handle->file = file;
|
||||
aio_handle->id = id;
|
||||
aio_handle->len = write_len;
|
||||
aio_handle->len = len;
|
||||
|
||||
rc = sftp_packet_write(sftp, SSH_FXP_WRITE, buffer);
|
||||
SSH_BUFFER_FREE(buffer);
|
||||
@@ -396,9 +397,9 @@ ssize_t sftp_aio_begin_write(sftp_file file,
|
||||
}
|
||||
|
||||
/* Assume we wrote len bytes to the file */
|
||||
file->offset += write_len;
|
||||
file->offset += len;
|
||||
*aio = aio_handle;
|
||||
return write_len;
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t sftp_aio_wait_write(sftp_aio *aio)
|
||||
@@ -409,7 +410,6 @@ ssize_t sftp_aio_wait_write(sftp_aio *aio)
|
||||
sftp_session sftp = NULL;
|
||||
sftp_message msg = NULL;
|
||||
sftp_status_message status = NULL;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* This function releases the memory of the structure
|
||||
@@ -446,15 +446,21 @@ ssize_t sftp_aio_wait_write(sftp_aio *aio)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = sftp_recv_response_msg(sftp, (*aio)->id, !file->nonblocking, &msg);
|
||||
if (rc == SSH_ERROR) {
|
||||
SFTP_AIO_FREE(*aio);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
while (msg == NULL) {
|
||||
if (file->nonblocking) {
|
||||
if (ssh_channel_poll(sftp->channel, 0) == 0) {
|
||||
/* we cannot block */
|
||||
return SSH_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == SSH_AGAIN) {
|
||||
/* Return without freeing the (*aio) */
|
||||
return SSH_AGAIN;
|
||||
if (sftp_read_and_dispatch(sftp) < 0) {
|
||||
/* something nasty has happened */
|
||||
SFTP_AIO_FREE(*aio);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
msg = sftp_dequeue(sftp, (*aio)->id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -418,9 +418,6 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp,
|
||||
(attr->extended_type = ssh_buffer_get_ssh_string(buf)) &&
|
||||
(attr->extended_data = ssh_buffer_get_ssh_string(buf))) {
|
||||
attr->extended_count--;
|
||||
/* just ignore the extensions -- we can't interpret them */
|
||||
SSH_STRING_FREE(attr->extended_type);
|
||||
SSH_STRING_FREE(attr->extended_data);
|
||||
}
|
||||
|
||||
if (attr->extended_count) {
|
||||
@@ -862,94 +859,6 @@ int sftp_read_and_dispatch(sftp_session sftp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sftp_recv_response_msg(sftp_session sftp,
|
||||
uint32_t id,
|
||||
bool blocking,
|
||||
sftp_message *msg_ptr)
|
||||
{
|
||||
sftp_message msg = NULL;
|
||||
int rc;
|
||||
|
||||
if (sftp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (msg_ptr == NULL) {
|
||||
ssh_set_error_invalid(sftp->session);
|
||||
sftp_set_error(sftp, SSH_FX_FAILURE);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Trying to receive response of request id %" PRIu32 " in %s mode",
|
||||
id,
|
||||
blocking ? "blocking" : "non-blocking");
|
||||
|
||||
/*
|
||||
* We deliberately check the queue first for the response before
|
||||
* polling/blocking on the channel. The reason for this approach is
|
||||
* explained by the following example (And a similar scenario can occur when
|
||||
* the async sftp aio API is used, because it provides the control of which
|
||||
* responses to receive (and in what order) to the user via the
|
||||
* sftp_aio_wait_*() functions)
|
||||
*
|
||||
* Its possible that while this function is trying to receive some
|
||||
* specific response (based on request id), other responses have already
|
||||
* arrived (or may arrive) before that specific response on the channel. In
|
||||
* that case, this function would collect those other responses from the
|
||||
* channel, add them to the sftp response queue (using
|
||||
* sftp_read_and_dipatch()) and finally provide the caller with the
|
||||
* required specific response.
|
||||
*
|
||||
* Now, whenever the caller will call this function again to get one of
|
||||
* those other responses, it won't be on the channel, instead it would be
|
||||
* present in the queue.
|
||||
*
|
||||
* Assuming that no new response ever comes on the channel, if we don't
|
||||
* check the queue first and instead:
|
||||
* - (In non blocking mode) poll on the channel, then we'd always get 0
|
||||
* bytes of data and return SSH_AGAIN.
|
||||
* - (In blocking mode) wait on the channel, then
|
||||
* sftp_read_and_dispatch() would block infinitely by default if the
|
||||
* user has not set any timeout.
|
||||
*
|
||||
* Hence checking the queue for the response first and if not found there,
|
||||
* polling/blocking on the channel is advised.
|
||||
*/
|
||||
while (msg == NULL) {
|
||||
/*
|
||||
* Before trying to poll/block on the channel for data, probe the queue
|
||||
* to check whether the response is already present in it.
|
||||
*/
|
||||
msg = sftp_dequeue(sftp, id);
|
||||
if (msg != NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!blocking) {
|
||||
rc = ssh_channel_poll(sftp->channel, 0);
|
||||
if (rc == SSH_ERROR) {
|
||||
sftp_set_error(sftp, SSH_FX_FAILURE);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
/* nothing available and we cannot block */
|
||||
return SSH_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
rc = sftp_read_and_dispatch(sftp);
|
||||
if (rc == -1) {
|
||||
/* something nasty has happened */
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
*msg_ptr = msg;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
sftp_status_message parse_status_msg(sftp_message msg)
|
||||
{
|
||||
sftp_status_message status = NULL;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user