mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +09:00
Compare commits
343 Commits
libssh-0.1
...
63fbf00efe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63fbf00efe | ||
|
|
ae33ced0dc | ||
|
|
ee6e2c69e1 | ||
|
|
cefc4f8c97 | ||
|
|
b64e7f67d3 | ||
|
|
491cd81a32 | ||
|
|
3444f4c449 | ||
|
|
80541ab828 | ||
|
|
b042477f83 | ||
|
|
950abbbd81 | ||
|
|
b9c6701c68 | ||
|
|
a94df4bb8f | ||
|
|
41b8b3326c | ||
|
|
a9c8f942a5 | ||
|
|
d307bfa239 | ||
|
|
66e8491f73 | ||
|
|
e93c1f6a61 | ||
|
|
358553e976 | ||
|
|
07d099f652 | ||
|
|
f3d70e54e9 | ||
|
|
74d1bf51b5 | ||
|
|
00f1d6fac2 | ||
|
|
029754efb3 | ||
|
|
a49e0c2a84 | ||
|
|
8966e577ab | ||
|
|
dc45b8f3f1 | ||
|
|
c932790b82 | ||
|
|
8a0aa17bca | ||
|
|
ecb11f1a18 | ||
|
|
6aea779918 | ||
|
|
a51384fe4e | ||
|
|
c55140272f | ||
|
|
607dad040b | ||
|
|
55bb909252 | ||
|
|
08cbbea461 | ||
|
|
8c4e337ab7 | ||
|
|
8541b6584f | ||
|
|
2f77727796 | ||
|
|
a3c5d3b256 | ||
|
|
59a502ede6 | ||
|
|
c94e2efcf1 | ||
|
|
3d3b12891f | ||
|
|
6ca59307d4 | ||
|
|
e8bbd194c7 | ||
|
|
df4e907dff | ||
|
|
c99261437f | ||
|
|
53ac23ded4 | ||
|
|
ffed80f8c0 | ||
|
|
9ada7aa0e4 | ||
|
|
d357a9f3e2 | ||
|
|
c9d95ab0c7 | ||
|
|
ccff22d378 | ||
|
|
4310a696f2 | ||
|
|
771e19a7a9 | ||
|
|
118a747acd | ||
|
|
5691e0f609 | ||
|
|
5a6e2fd02a | ||
|
|
e8099375fe | ||
|
|
d00f267bc6 | ||
|
|
35d337834b | ||
|
|
ba1e8303f8 | ||
|
|
ef50a3c0f0 | ||
|
|
e7cffe7e1b | ||
|
|
d1bf9068a9 | ||
|
|
737f9ecc3c | ||
|
|
cc667021e5 | ||
|
|
f9f8c939bc | ||
|
|
aab6ce364a | ||
|
|
0cec257077 | ||
|
|
957efe51a2 | ||
|
|
bb85492d4f | ||
|
|
22c1b6970c | ||
|
|
09155adb19 | ||
|
|
95f8cbc7f0 | ||
|
|
3423399f98 | ||
|
|
ccbec9c275 | ||
|
|
ed52c88a03 | ||
|
|
0f0ac314d2 | ||
|
|
95e4c39e8a | ||
|
|
8c89633a45 | ||
|
|
8069679033 | ||
|
|
c2e9d39dbe | ||
|
|
ab44f606b2 | ||
|
|
444982b38a | ||
|
|
3df61a4e86 | ||
|
|
961c79637c | ||
|
|
7eefbbd478 | ||
|
|
c4c28c6473 | ||
|
|
08a32ac381 | ||
|
|
62762bbbc9 | ||
|
|
ab3e08c2b5 | ||
|
|
809898b980 | ||
|
|
51bd08027e | ||
|
|
0b4b71cc11 | ||
|
|
5d3ef7261c | ||
|
|
9817392e26 | ||
|
|
168302b9d6 | ||
|
|
82c8bbc504 | ||
|
|
1ea1782036 | ||
|
|
c17112f070 | ||
|
|
28c0056bca | ||
|
|
7e4f08e22a | ||
|
|
aeb0b2ec6f | ||
|
|
67cf8e3702 | ||
|
|
309f36fa83 | ||
|
|
7a2a743a39 | ||
|
|
ccb8cf88c8 | ||
|
|
b43392c31d | ||
|
|
5fc65e7270 | ||
|
|
8310b8cc2b | ||
|
|
b0063b52d8 | ||
|
|
33a947dcb0 | ||
|
|
72c282434b | ||
|
|
ba9642882d | ||
|
|
a6b73219e2 | ||
|
|
e2afe196d8 | ||
|
|
32833b40bc | ||
|
|
bc4804aa9b | ||
|
|
acb158e827 | ||
|
|
faf9caafc6 | ||
|
|
8dc29f140b | ||
|
|
7501ca1e08 | ||
|
|
2eb2af4426 | ||
|
|
5d27f69494 | ||
|
|
6fc1bf6901 | ||
|
|
a85813e6e6 | ||
|
|
f039edd85d | ||
|
|
1229ad650b | ||
|
|
937552aed2 | ||
|
|
f6709b03e6 | ||
|
|
96595d1674 | ||
|
|
c799a18d89 | ||
|
|
babd891e82 | ||
|
|
320e5154b2 | ||
|
|
986e0c593f | ||
|
|
d38007c4be | ||
|
|
c22bfa792f | ||
|
|
926d45b6dd | ||
|
|
681a5aaa26 | ||
|
|
e322e8f50c | ||
|
|
a4118ddc06 | ||
|
|
db7f101d1c | ||
|
|
ae8881dfe5 | ||
|
|
00f09acbec | ||
|
|
74eb01f26d | ||
|
|
4f239f79c6 | ||
|
|
b8e587e498 | ||
|
|
b314fd3e04 | ||
|
|
d1ad796496 | ||
|
|
e2064b743d | ||
|
|
6d2a3e4eb6 | ||
|
|
7c34fa783d | ||
|
|
2a2c714dfa | ||
|
|
12baa5200a | ||
|
|
f2b64abcbd | ||
|
|
4135154b6d | ||
|
|
ca4c874a9e | ||
|
|
c7b6ffad0e | ||
|
|
c1fb0d872d | ||
|
|
3a167a89b5 | ||
|
|
dfa9421e01 | ||
|
|
efc5bc633f | ||
|
|
3a4ba8b763 | ||
|
|
47db54b7c1 | ||
|
|
d1c2d3db9d | ||
|
|
dcb65fe584 | ||
|
|
d758990d39 | ||
|
|
bfae56634c | ||
|
|
3d0226cadc | ||
|
|
0bcd7d12d8 | ||
|
|
bd10ec1162 | ||
|
|
69c169e4cb | ||
|
|
f0b9db586b | ||
|
|
c735b44f83 | ||
|
|
3b4b8033de | ||
|
|
0068fdd594 | ||
|
|
344235c954 | ||
|
|
d00f7b1bf9 | ||
|
|
b14018ecab | ||
|
|
5e47b1c1c2 | ||
|
|
9ce885b168 | ||
|
|
184dad101d | ||
|
|
04a58919f8 | ||
|
|
b106211d92 | ||
|
|
af10857aa3 | ||
|
|
f3b389d112 | ||
|
|
18e7423e70 | ||
|
|
8c8d3ceef7 | ||
|
|
0d0ed4b1f8 | ||
|
|
8dc234c909 | ||
|
|
2e686c5cea | ||
|
|
d3706d5940 | ||
|
|
d92a057090 | ||
|
|
1434f24911 | ||
|
|
cce600f980 | ||
|
|
95150b1137 | ||
|
|
65b2591b91 | ||
|
|
a5e9529ca7 | ||
|
|
49a355c272 | ||
|
|
84d02e7440 | ||
|
|
0b91ba779c | ||
|
|
d02163546d | ||
|
|
a93e84efb9 | ||
|
|
a59d587060 | ||
|
|
6c4e4a9e1c | ||
|
|
aa681c268e | ||
|
|
fe381d6aa4 | ||
|
|
1f76cc0c6a | ||
|
|
bf2b8954e8 | ||
|
|
7e3935e7d2 | ||
|
|
d38b471fd8 | ||
|
|
735a4368c2 | ||
|
|
a25f9d211d | ||
|
|
3a52bf1679 | ||
|
|
f7bdd779d6 | ||
|
|
8ef249a4a4 | ||
|
|
d9da8f212d | ||
|
|
9613e9508d | ||
|
|
6b9a6529bd | ||
|
|
b14cde6d2a | ||
|
|
e01c32f41e | ||
|
|
dd6a711354 | ||
|
|
c1a7de78d1 | ||
|
|
9735f074ba | ||
|
|
b2b56151c0 | ||
|
|
de7903a633 | ||
|
|
a089513e40 | ||
|
|
ec9d7d13fd | ||
|
|
f14568262a | ||
|
|
257e8eb2c1 | ||
|
|
99fcd56135 | ||
|
|
8922e43578 | ||
|
|
e36ca61e36 | ||
|
|
02c092d3d9 | ||
|
|
520f758902 | ||
|
|
12b8eed093 | ||
|
|
3372c2ad78 | ||
|
|
6b83aa9a40 | ||
|
|
7f045e2d91 | ||
|
|
2b916b3b88 | ||
|
|
a10553ae57 | ||
|
|
d1ce336ae3 | ||
|
|
79ac8b85d8 | ||
|
|
9a9cafeed5 | ||
|
|
a0a5292692 | ||
|
|
1a64c577f6 | ||
|
|
c03d0d4823 | ||
|
|
d5456931cc | ||
|
|
dc18b41357 | ||
|
|
0f5dec7fb7 | ||
|
|
0cda1c0e83 | ||
|
|
1ea9708409 | ||
|
|
39fcaac3ca | ||
|
|
dab51d8e20 | ||
|
|
4becc8eb82 | ||
|
|
3468cc0dc5 | ||
|
|
4bd8d8d362 | ||
|
|
083a4781d8 | ||
|
|
7e3263d995 | ||
|
|
fbf02d5936 | ||
|
|
16fd55b4b2 | ||
|
|
799557384d | ||
|
|
c6be50cc97 | ||
|
|
af90168624 | ||
|
|
9dbd1ec80b | ||
|
|
9b9a2ea97d | ||
|
|
e9b76ff1bd | ||
|
|
e9046fc069 | ||
|
|
0cd749a533 | ||
|
|
e795849299 | ||
|
|
d887e1320a | ||
|
|
9eaa7a6394 | ||
|
|
4af88c84d4 | ||
|
|
00fce9cb6c | ||
|
|
a547b7f115 | ||
|
|
8bf908a56f | ||
|
|
b7018c17c7 | ||
|
|
a15c977cdc | ||
|
|
91e228b08b | ||
|
|
cbcd6d6f46 | ||
|
|
49b0c859f9 | ||
|
|
79ba546cde | ||
|
|
0ea982d4ec | ||
|
|
c043122655 | ||
|
|
5da8963c1d | ||
|
|
f3d80833fe | ||
|
|
874b75429f | ||
|
|
f8a6b1e2b3 | ||
|
|
5b9b901e48 | ||
|
|
2966a4a33c | ||
|
|
867630750c | ||
|
|
9a40d51162 | ||
|
|
259721e523 | ||
|
|
4bc40a47a3 | ||
|
|
f0b55391a8 | ||
|
|
d2e5b69b02 | ||
|
|
2971e122d0 | ||
|
|
e2524538f6 | ||
|
|
d0ecb5388c | ||
|
|
72b6fad284 | ||
|
|
258c2eef3b | ||
|
|
a02268a254 | ||
|
|
f16b3539da | ||
|
|
0306581f1c | ||
|
|
d8f00aca20 | ||
|
|
e0aa182e7e | ||
|
|
0e756306f0 | ||
|
|
904c3e024c | ||
|
|
b58cb9f72b | ||
|
|
861590192f | ||
|
|
9ad2f6b3b1 | ||
|
|
ef8e90863b | ||
|
|
d29ed23010 | ||
|
|
46d7417620 | ||
|
|
c73a8a824e | ||
|
|
7712c7d0f9 | ||
|
|
d7a0cbcfbb | ||
|
|
cb0237e85b | ||
|
|
5b0f480acd | ||
|
|
629ba3fd34 | ||
|
|
48d474f78c | ||
|
|
e298600303 | ||
|
|
8295945011 | ||
|
|
8363929104 | ||
|
|
71e1baeb5f | ||
|
|
82b363f294 | ||
|
|
8fb2c5d2fd | ||
|
|
9ce53b6972 | ||
|
|
7b89ff760a | ||
|
|
362ab3a684 | ||
|
|
ea97d41bbb | ||
|
|
c85268c38b | ||
|
|
c9cfeb9b83 | ||
|
|
deedc0e108 | ||
|
|
57073d588a | ||
|
|
d416ef533f | ||
|
|
2743b510ac | ||
|
|
41d370864e | ||
|
|
7e4ea0d111 | ||
|
|
b0b2e8fefd | ||
|
|
b804aa9286 | ||
|
|
ab10f5c2f7 | ||
|
|
9634668258 |
@@ -22,8 +22,8 @@ BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
# TODO with Clang 19, replace the below with
|
||||
# BreakAfterReturnType: ExceptShortType
|
||||
BreakAfterReturnType: ExceptShortType
|
||||
AlwaysBreakAfterReturnType: AllDefinitions
|
||||
AlignEscapedNewlines: Left
|
||||
ForEachMacros: ['ssh_callbacks_iterate']
|
||||
AlignConsecutiveMacros: 'Consecutive'
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ tags
|
||||
/build
|
||||
/obj*
|
||||
doc/tags.xml
|
||||
.DS_Store
|
||||
|
||||
166
.gitlab-ci.yml
166
.gitlab-ci.yml
@@ -3,6 +3,7 @@ variables:
|
||||
BUILD_IMAGES_PROJECT: libssh/build-images
|
||||
CENTOS8_BUILD: buildenv-c8s
|
||||
CENTOS9_BUILD: buildenv-c9s
|
||||
CENTOS10_BUILD: buildenv-c10s
|
||||
FEDORA_BUILD: buildenv-fedora
|
||||
MINGW_BUILD: buildenv-mingw
|
||||
TUMBLEWEED_BUILD: buildenv-tumbleweed
|
||||
@@ -26,13 +27,17 @@ workflow:
|
||||
when: never
|
||||
- if: '$CI_COMMIT_BRANCH'
|
||||
|
||||
.build:
|
||||
stage: build
|
||||
.build_options:
|
||||
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
|
||||
@@ -74,8 +79,6 @@ workflow:
|
||||
.fedora:
|
||||
extends: .tests
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON
|
||||
|
||||
.tumbleweed:
|
||||
extends: .tests
|
||||
@@ -107,7 +110,7 @@ review:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- ERROR=0
|
||||
codespell --ignore-words-list=keypair,sorce,ned,nd,ue || ERROR=1;
|
||||
codespell --ignore-words-list=keypair,sorce,ned,nd,ue,pendin || ERROR=1;
|
||||
./.gitlab-ci/clang-format-check.sh || ERROR=1;
|
||||
./.gitlab-ci/git-check-signoff-trailer.sh ${CI_MERGE_REQUEST_DIFF_BASE_SHA} || ERROR=1;
|
||||
./.gitlab-ci/shellcheck.sh || ERROR=1;
|
||||
@@ -122,7 +125,29 @@ review:
|
||||
###############################################################################
|
||||
# CentOS builds #
|
||||
###############################################################################
|
||||
centos9s/openssl_3.0.x/x86_64:
|
||||
centos10s/openssl_3.5.x/x86_64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
|
||||
extends: .tests
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||
script:
|
||||
- export OPENSSL_ENABLE_SHA1_SIGNATURES=1
|
||||
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
|
||||
centos10s/openssl_3.5.x/x86_64/fips:
|
||||
extends: .fips
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||
script:
|
||||
- export OPENSSL_ENABLE_SHA1_SIGNATURES=1
|
||||
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
|
||||
make -j$(nproc) &&
|
||||
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
|
||||
|
||||
centos9s/openssl_3.5.x/x86_64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||
extends: .tests
|
||||
variables:
|
||||
@@ -139,7 +164,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.0.x/x86_64/fips:
|
||||
centos9s/openssl_3.5.x/x86_64/fips:
|
||||
extends: .fips
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
|
||||
script:
|
||||
@@ -204,15 +229,15 @@ fedora/coverage:
|
||||
coverage_format: cobertura
|
||||
path: obj/coverage_xml.xml
|
||||
|
||||
fedora/openssl_3.0.x/x86_64:
|
||||
fedora/openssl_3.x/x86_64:
|
||||
extends: .fedora
|
||||
|
||||
fedora/openssl_3.0.x/x86_64/pkcs11-provider:
|
||||
fedora/openssl_3.x/x86_64/pkcs11-provider:
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
|
||||
extends: .fedora
|
||||
|
||||
fedora/openssl_3.0.x/x86_64/minimal:
|
||||
fedora/openssl_3.x/x86_64/minimal:
|
||||
extends: .fedora
|
||||
variables:
|
||||
script:
|
||||
@@ -328,7 +353,7 @@ fedora/mingw64:
|
||||
-DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
ctest --output-on-failure -E torture_rand
|
||||
|
||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||
# for MinGW
|
||||
@@ -345,7 +370,7 @@ fedora/mingw32:
|
||||
-DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
ctest --output-on-failure -E torture_rand
|
||||
|
||||
|
||||
###############################################################################
|
||||
@@ -384,7 +409,7 @@ fedora/mingw32:
|
||||
paths:
|
||||
- obj-csbuild/
|
||||
|
||||
fedora/csbuild/openssl_3.0.x:
|
||||
fedora/csbuild/openssl_3.x:
|
||||
extends: .csbuild
|
||||
script:
|
||||
- csbuild
|
||||
@@ -414,6 +439,62 @@ 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 #
|
||||
@@ -426,7 +507,7 @@ ubuntu/openssl_3.0.x/x86_64:
|
||||
###############################################################################
|
||||
# Alpine builds #
|
||||
###############################################################################
|
||||
alpine/openssl_3.0.x/musl:
|
||||
alpine/openssl_3.x/musl:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$ALPINE_BUILD
|
||||
extends: .tests
|
||||
script:
|
||||
@@ -443,10 +524,10 @@ alpine/openssl_3.0.x/musl:
|
||||
###############################################################################
|
||||
# Tumbleweed builds #
|
||||
###############################################################################
|
||||
tumbleweed/openssl_3.0.x/x86_64/gcc:
|
||||
tumbleweed/openssl_3.x/x86_64/gcc:
|
||||
extends: .tumbleweed
|
||||
|
||||
tumbleweed/openssl_3.0.x/x86/gcc:
|
||||
tumbleweed/openssl_3.x/x86/gcc:
|
||||
extends: .tumbleweed
|
||||
script:
|
||||
- cmake
|
||||
@@ -459,12 +540,12 @@ tumbleweed/openssl_3.0.x/x86/gcc:
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc)
|
||||
|
||||
tumbleweed/openssl_3.0.x/x86_64/gcc7:
|
||||
tumbleweed/openssl_3.x/x86_64/gcc7:
|
||||
extends: .tumbleweed
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7"
|
||||
|
||||
tumbleweed/openssl_3.0.x/x86/gcc7:
|
||||
tumbleweed/openssl_3.x/x86/gcc7:
|
||||
extends: .tumbleweed
|
||||
script:
|
||||
- cmake
|
||||
@@ -476,7 +557,7 @@ tumbleweed/openssl_3.0.x/x86/gcc7:
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
|
||||
tumbleweed/openssl_3.0.x/x86_64/clang:
|
||||
tumbleweed/openssl_3.x/x86_64/clang:
|
||||
extends: .tumbleweed
|
||||
variables:
|
||||
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
|
||||
@@ -486,6 +567,11 @@ 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
|
||||
@@ -547,9 +633,7 @@ 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: analysis
|
||||
needs: []
|
||||
allow_failure: true
|
||||
stage: test
|
||||
cache:
|
||||
key: vcpkg.${CI_JOB_NAME}
|
||||
paths:
|
||||
@@ -641,3 +725,41 @@ 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/
|
||||
|
||||
42
.gitlab-ci/checkabi.sh
Executable file
42
.gitlab-ci/checkabi.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/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
|
||||
16
.gitlab/merge_request_templates/default.md
Normal file
16
.gitlab/merge_request_templates/default.md
Normal file
@@ -0,0 +1,16 @@
|
||||
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
|
||||
@@ -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 CXX)
|
||||
project(libssh VERSION 0.11.00 LANGUAGES C)
|
||||
|
||||
# global needed variable
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
@@ -41,6 +41,8 @@ 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)
|
||||
@@ -66,6 +68,7 @@ find_package(Threads)
|
||||
|
||||
if (WITH_GSSAPI)
|
||||
find_package(GSSAPI)
|
||||
list(APPEND LIBSSH_PC_REQUIRES_PRIVATE ${GSSAPI_PC_REQUIRES})
|
||||
endif (WITH_GSSAPI)
|
||||
|
||||
if (WITH_NACL)
|
||||
@@ -190,12 +193,13 @@ endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
|
||||
|
||||
# Coverage
|
||||
if (WITH_COVERAGE)
|
||||
ENABLE_LANGUAGE(CXX)
|
||||
include(CodeCoverage)
|
||||
setup_target_for_coverage_lcov(
|
||||
NAME "coverage"
|
||||
EXECUTABLE make test
|
||||
DEPENDENCIES ssh tests)
|
||||
set(GCOVR_ADDITIONAL_ARGS --xml-pretty --exclude-unreachable-branches --print-summary)
|
||||
set(GCOVR_ADDITIONAL_ARGS --xml-pretty --exclude-unreachable-branches --print-summary --gcov-ignore-parse-errors)
|
||||
setup_target_for_coverage_gcovr_xml(
|
||||
NAME "coverage_xml"
|
||||
EXECUTABLE make test
|
||||
@@ -248,9 +252,15 @@ 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)
|
||||
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
|
||||
if (WITH_HERMETIC_USR)
|
||||
message(STATUS "User global bind config: ${USR_GLOBAL_BIND_CONFIG}")
|
||||
endif ()
|
||||
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
|
||||
endif()
|
||||
message(STATUS "********************************************")
|
||||
|
||||
|
||||
@@ -117,6 +117,25 @@ 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
|
||||
|
||||
@@ -517,6 +536,37 @@ 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!
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
|
||||
# SOURCE GENERATOR
|
||||
set(CPACK_SOURCE_GENERATOR "TXZ")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch")
|
||||
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]bare/;/[.]git/;/[.]git;/[.]clangd/;/[.]cache/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json;.*\.patch")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
### NSIS INSTALLER
|
||||
|
||||
@@ -16,7 +16,6 @@ if (UNIX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_c_compiler_flag("-std=gnu99" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wpedantic" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wall" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wshadow" SUPPORTED_COMPILER_FLAGS)
|
||||
@@ -49,6 +48,7 @@ if (UNIX)
|
||||
add_c_compiler_flag("-Werror=implicit-int" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wint-conversion" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Werror=int-conversion" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Werror=unused-variable" SUPPORTED_COMPILER_FLAGS)
|
||||
|
||||
check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT)
|
||||
if (REQUIRED_FLAGS_WFORMAT)
|
||||
@@ -92,9 +92,12 @@ if (UNIX)
|
||||
endif (WITH_STACK_PROTECTOR_STRONG)
|
||||
|
||||
if (NOT WINDOWS AND NOT CYGWIN)
|
||||
check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION)
|
||||
if (WITH_STACK_CLASH_PROTECTION)
|
||||
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection")
|
||||
# apple m* chips do not support this option
|
||||
if (NOT ${CMAKE_SYSTEM_PROCESSOR} STREQUAL arm64)
|
||||
check_c_compiler_flag_ssp("-fstack-clash-protection" WITH_STACK_CLASH_PROTECTION)
|
||||
if (WITH_STACK_CLASH_PROTECTION)
|
||||
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-clash-protection")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
|
||||
check_include_file(byteswap.h HAVE_BYTESWAP_H)
|
||||
check_include_file(glob.h HAVE_GLOB_H)
|
||||
check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
|
||||
check_include_file(ifaddrs.h HAVE_IFADDRS_H)
|
||||
|
||||
if (WIN32)
|
||||
check_include_file(io.h HAVE_IO_H)
|
||||
@@ -103,6 +104,11 @@ if (OPENSSL_FOUND)
|
||||
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
|
||||
check_function_exists(EVP_chacha20 HAVE_OPENSSL_EVP_CHACHA20)
|
||||
|
||||
# Check for ML-KEM768 availability (OpenSSL 3.5+)
|
||||
if (OPENSSL_VERSION VERSION_GREATER_EQUAL "3.5.0")
|
||||
set(HAVE_MLKEM 1)
|
||||
endif ()
|
||||
|
||||
unset(CMAKE_REQUIRED_INCLUDES)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif()
|
||||
@@ -225,6 +231,7 @@ 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)
|
||||
|
||||
@@ -235,6 +242,13 @@ 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,6 +27,7 @@ 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)
|
||||
@@ -59,6 +60,11 @@ 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,14 +38,16 @@ 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 -DUNIT_TESTING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
|
||||
make
|
||||
|
||||
On Windows you should choose a makefile 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
|
||||
|
||||
@@ -117,6 +117,7 @@ function(ADD_CMOCKA_TEST _TARGET_NAME)
|
||||
${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME}
|
||||
)
|
||||
if (WITH_COVERAGE)
|
||||
ENABLE_LANGUAGE(CXX)
|
||||
include(CodeCoverage)
|
||||
append_coverage_compiler_flags_to_target(${_TARGET_NAME})
|
||||
endif (WITH_COVERAGE)
|
||||
|
||||
@@ -39,6 +39,15 @@ find_path(GCRYPT_INCLUDE_DIR
|
||||
include
|
||||
)
|
||||
|
||||
find_path(GCRYPT_ERROR_INCLUDE_DIR
|
||||
NAMES
|
||||
gpg-error.h
|
||||
HINTS
|
||||
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
find_library(GCRYPT_LIBRARY
|
||||
NAMES
|
||||
gcrypt
|
||||
@@ -56,8 +65,10 @@ find_library(GCRYPT_ERROR_LIBRARY
|
||||
libgpg-error6-0
|
||||
HINTS
|
||||
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY} ${GCRYPT_ERROR_LIBRARY})
|
||||
set(GCRYPT_LIBRARIES ${GCRYPT_ERROR_LIBRARY} ${GCRYPT_LIBRARY})
|
||||
|
||||
if (GCRYPT_INCLUDE_DIR)
|
||||
file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]")
|
||||
@@ -83,5 +94,25 @@ else (GCRYPT_VERSION)
|
||||
GCRYPT_LIBRARIES)
|
||||
endif (GCRYPT_VERSION)
|
||||
|
||||
# show the GCRYPT_INCLUDE_DIRS and GCRYPT_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(GCRYPT_INCLUDE_DIR GCRYPT_LIBRARIES)
|
||||
# show the GCRYPT_INCLUDE_DIRS, GCRYPT_LIBRARIES and GCRYPT_ERROR_INCLUDE_DIR variables only in the advanced view
|
||||
mark_as_advanced(GCRYPT_INCLUDE_DIR GCRYPT_ERROR_INCLUDE_DIR GCRYPT_LIBRARIES)
|
||||
|
||||
if(GCRYPT_FOUND)
|
||||
if(NOT TARGET libgcrypt::libgcrypt)
|
||||
add_library(libgcrypt::libgcrypt UNKNOWN IMPORTED)
|
||||
set_target_properties(libgcrypt::libgcrypt PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${GCRYPT_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES libgcrypt::libgcrypt
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${GCRYPT_LIBRARY}")
|
||||
endif()
|
||||
|
||||
if(NOT TARGET libgpg-error::libgpg-error)
|
||||
add_library(libgpg-error::libgpg-error UNKNOWN IMPORTED)
|
||||
set_target_properties(libgpg-error::libgpg-error PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${GCRYPT_ERROR_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES libgpg-error::libgpg-error
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${GCRYPT_ERROR_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
# 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>
|
||||
@@ -24,12 +26,23 @@
|
||||
#=============================================================================
|
||||
#
|
||||
|
||||
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}
|
||||
)
|
||||
@@ -317,9 +330,15 @@ endif (GSSAPI_FLAVOR_HEIMDAL)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR)
|
||||
|
||||
if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
|
||||
set(GSSAPI_FOUND TRUE)
|
||||
endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
|
||||
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()
|
||||
|
||||
# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES)
|
||||
# show the GSSAPI_INCLUDE_DIR and GSSAPI_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(GSSAPI_INCLUDE_DIR GSSAPI_LIBRARIES)
|
||||
|
||||
@@ -72,21 +72,23 @@ 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}")
|
||||
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
|
||||
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
|
||||
"^#[\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)
|
||||
@@ -110,3 +112,32 @@ endif (MBEDTLS_VERSION)
|
||||
|
||||
# show the MBEDTLS_INCLUDE_DIRS and MBEDTLS_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(MBEDTLS_INCLUDE_DIR MBEDTLS_LIBRARIES)
|
||||
|
||||
if(MBEDTLS_FOUND)
|
||||
if(NOT TARGET MbedTLS::mbedcrypto)
|
||||
add_library(MbedTLS::mbedcrypto UNKNOWN IMPORTED)
|
||||
set_target_properties(MbedTLS::mbedcrypto PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES MbedTLS::mbedcrypto
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${MBEDTLS_CRYPTO_LIBRARY}")
|
||||
endif()
|
||||
|
||||
if(NOT TARGET MbedTLS::mbedx509)
|
||||
add_library(MbedTLS::mbedx509 UNKNOWN IMPORTED)
|
||||
set_target_properties(MbedTLS::mbedx509 PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES MbedTLS::mbedx509
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${MBEDTLS_X509_LIBRARY}")
|
||||
endif()
|
||||
|
||||
if(NOT TARGET MbedTLS::mbedtls)
|
||||
add_library(MbedTLS::mbedtls UNKNOWN IMPORTED)
|
||||
set_target_properties(MbedTLS::mbedtls PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${MBEDTLS_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES MbedTLS::mbedtls
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${MBEDTLS_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#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 *************************/
|
||||
@@ -58,6 +60,9 @@
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#cmakedefine HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <ifaddrs.h> header file. */
|
||||
#cmakedefine HAVE_IFADDRS_H 1
|
||||
|
||||
/* Define to 1 if you have the <openssl/aes.h> header file. */
|
||||
#cmakedefine HAVE_OPENSSL_AES_H 1
|
||||
|
||||
@@ -82,6 +87,9 @@
|
||||
/* 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
|
||||
|
||||
@@ -94,6 +102,9 @@
|
||||
/* 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. */
|
||||
@@ -180,6 +191,9 @@
|
||||
/* Define to 1 if we have support for blowfish */
|
||||
#cmakedefine HAVE_BLOWFISH 1
|
||||
|
||||
/* Define to 1 if we have support for ML-KEM */
|
||||
#cmakedefine HAVE_MLKEM 1
|
||||
|
||||
/*************************** LIBRARIES ***************************/
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
|
||||
@@ -105,7 +105,7 @@ Here is a small example of password authentication:
|
||||
@code
|
||||
int authenticate_password(ssh_session session)
|
||||
{
|
||||
char *password;
|
||||
char *password = NULL;
|
||||
int rc;
|
||||
|
||||
password = getpass("Enter your password: ");
|
||||
@@ -218,7 +218,7 @@ int authenticate_kbdint(ssh_session session)
|
||||
rc = ssh_userauth_kbdint(session, NULL, NULL);
|
||||
while (rc == SSH_AUTH_INFO)
|
||||
{
|
||||
const char *name, *instruction;
|
||||
const char *name = NULL, *instruction = NULL;
|
||||
int nprompts, iprompt;
|
||||
|
||||
name = ssh_userauth_kbdint_getname(session);
|
||||
@@ -231,7 +231,7 @@ int authenticate_kbdint(ssh_session session)
|
||||
printf("%s\n", instruction);
|
||||
for (iprompt = 0; iprompt < nprompts; iprompt++)
|
||||
{
|
||||
const char *prompt;
|
||||
const char *prompt = NULL;
|
||||
char echo;
|
||||
|
||||
prompt = ssh_userauth_kbdint_getprompt(session, iprompt, &echo);
|
||||
@@ -251,7 +251,7 @@ int authenticate_kbdint(ssh_session session)
|
||||
}
|
||||
else
|
||||
{
|
||||
char *ptr;
|
||||
char *ptr = NULL;
|
||||
|
||||
ptr = getpass(prompt);
|
||||
if (ssh_userauth_kbdint_setanswer(session, iprompt, ptr) < 0)
|
||||
@@ -354,7 +354,7 @@ The following example shows how to retrieve and dispose the issue banner:
|
||||
int display_banner(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
char *banner;
|
||||
char *banner = NULL;
|
||||
|
||||
/*
|
||||
*** Does not work without calling ssh_userauth_none() first ***
|
||||
|
||||
@@ -22,7 +22,7 @@ a SSH session that uses this channel:
|
||||
@code
|
||||
int show_remote_files(ssh_session session)
|
||||
{
|
||||
ssh_channel channel;
|
||||
ssh_channel channel = NULL;
|
||||
int rc;
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
@@ -91,4 +91,10 @@ 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.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
@@ -100,7 +100,7 @@ used to retrieve google's home page from the remote SSH server.
|
||||
@code
|
||||
int direct_forwarding(ssh_session session)
|
||||
{
|
||||
ssh_channel forwarding_channel;
|
||||
ssh_channel forwarding_channel = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
char *http_get = "GET / HTTP/1.1\nHost: www.google.com\n\n";
|
||||
int nbytes, nwritten;
|
||||
@@ -161,7 +161,7 @@ local libssh application, which handles them:
|
||||
int web_server(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
ssh_channel channel;
|
||||
ssh_channel channel = NULL;
|
||||
char buffer[256];
|
||||
int nbytes, nwritten;
|
||||
int port = 0;
|
||||
|
||||
@@ -79,7 +79,7 @@ Here is a small example of how to use it:
|
||||
|
||||
int main()
|
||||
{
|
||||
ssh_session my_ssh_session;
|
||||
ssh_session my_ssh_session = NULL;
|
||||
int verbosity = SSH_LOG_PROTOCOL;
|
||||
int port = 22;
|
||||
|
||||
@@ -126,7 +126,7 @@ Here's an example:
|
||||
|
||||
int main()
|
||||
{
|
||||
ssh_session my_ssh_session;
|
||||
ssh_session my_ssh_session = NULL;
|
||||
int rc;
|
||||
|
||||
my_ssh_session = ssh_new();
|
||||
@@ -190,8 +190,8 @@ int verify_knownhost(ssh_session session)
|
||||
ssh_key srv_pubkey = NULL;
|
||||
size_t hlen;
|
||||
char buf[10];
|
||||
char *hexa;
|
||||
char *p;
|
||||
char *hexa = NULL;
|
||||
char *p = NULL;
|
||||
int cmp;
|
||||
int rc;
|
||||
|
||||
@@ -317,9 +317,9 @@ The example below shows an authentication with password:
|
||||
|
||||
int main()
|
||||
{
|
||||
ssh_session my_ssh_session;
|
||||
ssh_session my_ssh_session = NULL;
|
||||
int rc;
|
||||
char *password;
|
||||
char *password = NULL;
|
||||
|
||||
// Open session and set options
|
||||
my_ssh_session = ssh_new();
|
||||
@@ -380,7 +380,7 @@ The example below shows how to execute a remote command:
|
||||
@code
|
||||
int show_remote_processes(ssh_session session)
|
||||
{
|
||||
ssh_channel channel;
|
||||
ssh_channel channel = NULL;
|
||||
int rc;
|
||||
char buffer[256];
|
||||
int nbytes;
|
||||
|
||||
@@ -19,7 +19,7 @@ the interesting functions as you go.
|
||||
|
||||
The libssh library provides:
|
||||
|
||||
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
|
||||
- <strong>Key Exchange Methods</strong>: <i>sntrup761x25519-sha512, sntrup761x25519-sha512@openssh.com, mlkem768x25519-sha256, 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
|
||||
|
||||
@@ -81,10 +81,6 @@ We recommend the users to provide a specific PKCS #11 URI so that it matches onl
|
||||
If the engine discovers multiple slots that could potentially contain the private keys referenced
|
||||
by the provided PKCS #11 URI, the engine will not try to authenticate.
|
||||
|
||||
For testing, the SoftHSM PKCS#11 library is used. But it has some issues with
|
||||
OpenSSL initialization/cleanup when used with OpenSSL 3.0 so we are using it
|
||||
indirectly through a p11-kit remoting as described in the following article:
|
||||
|
||||
https://p11-glue.github.io/p11-glue/p11-kit/manual/remoting.html
|
||||
For testing, the SoftHSM PKCS#11 library is used.
|
||||
|
||||
*/
|
||||
|
||||
@@ -26,7 +26,7 @@ The code sample below achieves these tasks:
|
||||
@code
|
||||
int shell_session(ssh_session session)
|
||||
{
|
||||
ssh_channel channel;
|
||||
ssh_channel channel = NULL;
|
||||
int rc;
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
|
||||
@@ -303,7 +303,6 @@ span.lineno {
|
||||
padding-right: 4px;
|
||||
text-align: right;
|
||||
color: black;
|
||||
height: 100px;
|
||||
white-space: pre;
|
||||
border-right: 3px solid #1d7567;
|
||||
background-color: #323232; }
|
||||
|
||||
@@ -30,9 +30,11 @@ if (UNIX AND NOT WIN32)
|
||||
target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(samplesftp ssh::ssh)
|
||||
|
||||
add_executable(sample_sftpserver sample_sftpserver.c ${examples_SRCS})
|
||||
target_compile_options(sample_sftpserver PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(sample_sftpserver ssh::ssh ${ARGP_LIBRARIES})
|
||||
if (WITH_SERVER)
|
||||
add_executable(sample_sftpserver sample_sftpserver.c ${examples_SRCS})
|
||||
target_compile_options(sample_sftpserver PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(sample_sftpserver ssh::ssh ${ARGP_LIBRARIES})
|
||||
endif (WITH_SERVER)
|
||||
endif (WITH_SFTP)
|
||||
|
||||
add_executable(ssh-client ssh_client.c ${examples_SRCS})
|
||||
|
||||
@@ -30,8 +30,8 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
||||
|
||||
err = ssh_userauth_kbdint(session, NULL, NULL);
|
||||
while (err == SSH_AUTH_INFO) {
|
||||
const char *instruction;
|
||||
const char *name;
|
||||
const char *instruction = NULL;
|
||||
const char *name = NULL;
|
||||
char buffer[128];
|
||||
int i, n;
|
||||
|
||||
@@ -48,8 +48,8 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const char *answer;
|
||||
const char *prompt;
|
||||
const char *answer = NULL;
|
||||
const char *prompt = NULL;
|
||||
char echo;
|
||||
|
||||
prompt = ssh_userauth_kbdint_getprompt(session, i, &echo);
|
||||
@@ -58,7 +58,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
||||
}
|
||||
|
||||
if (echo) {
|
||||
char *p;
|
||||
char *p = NULL;
|
||||
|
||||
printf("%s", prompt);
|
||||
|
||||
@@ -66,7 +66,6 @@ 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';
|
||||
}
|
||||
@@ -75,7 +74,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
memset(buffer, 0, strlen(buffer));
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
} else {
|
||||
if (password && strstr(prompt, "Password:")) {
|
||||
answer = password;
|
||||
@@ -143,11 +142,11 @@ int authenticate_console(ssh_session session)
|
||||
int rc;
|
||||
int method;
|
||||
char password[128] = {0};
|
||||
char *banner;
|
||||
char *banner = NULL;
|
||||
|
||||
// Try to authenticate
|
||||
rc = ssh_userauth_none(session, NULL);
|
||||
if (rc == SSH_AUTH_ERROR) {
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
error(session);
|
||||
return rc;
|
||||
}
|
||||
@@ -156,7 +155,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) {
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
error(session);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
@@ -166,7 +165,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) {
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
error(session);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
@@ -206,7 +205,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) {
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
error(session);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
@@ -221,7 +220,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) {
|
||||
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
|
||||
error(session);
|
||||
return rc;
|
||||
} else if (rc == SSH_AUTH_SUCCESS) {
|
||||
|
||||
@@ -21,47 +21,57 @@ 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;
|
||||
int auth=0;
|
||||
ssh_session connect_ssh(const char *host, const char *port, const char *user, int verbosity)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
int auth = 0;
|
||||
|
||||
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;
|
||||
session = ssh_new();
|
||||
if (session == NULL) {
|
||||
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));
|
||||
if (user != NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
|
||||
ssh_free(session);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (port != NULL) {
|
||||
if (ssh_options_set(session, SSH_OPTIONS_PORT_STR, port) < 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));
|
||||
}
|
||||
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,11 +16,11 @@ clients must be made or how a client should react.
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
/** Zero a structure */
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
#define ZERO_STRUCT(x) memset(&(x), 0, sizeof(x))
|
||||
|
||||
int authenticate_console(ssh_session session);
|
||||
int authenticate_kbdint(ssh_session session, const char *password);
|
||||
int verify_knownhost(ssh_session session);
|
||||
ssh_session connect_ssh(const char *hostname, const char *user, int verbosity);
|
||||
ssh_session connect_ssh(const char *hostname, const char *port, const char *user, int verbosity);
|
||||
|
||||
#endif /* EXAMPLES_COMMON_H_ */
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
#include "examples_common.h"
|
||||
|
||||
int main(void) {
|
||||
ssh_session session;
|
||||
ssh_channel channel;
|
||||
ssh_session session = NULL;
|
||||
ssh_channel channel = NULL;
|
||||
char buffer[256];
|
||||
int rbytes, wbytes, total = 0;
|
||||
int rc;
|
||||
|
||||
session = connect_ssh("localhost", NULL, 0);
|
||||
session = connect_ssh("localhost", NULL, NULL, 0);
|
||||
if (session == NULL) {
|
||||
ssh_finalize();
|
||||
return 1;
|
||||
|
||||
@@ -350,7 +350,12 @@ int main(int argc, char *argv[])
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (arguments.action_list && arguments.file) {
|
||||
if (arguments.file == NULL) {
|
||||
fprintf(stderr, "Error: Missing argument file\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (arguments.action_list) {
|
||||
list_fingerprint(arguments.file);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ int verify_knownhost(ssh_session session)
|
||||
char buf[10];
|
||||
unsigned char *hash = NULL;
|
||||
size_t hlen;
|
||||
ssh_key srv_pubkey;
|
||||
ssh_key srv_pubkey = NULL;
|
||||
int rc;
|
||||
|
||||
rc = ssh_get_server_publickey(session, &srv_pubkey);
|
||||
|
||||
@@ -26,10 +26,11 @@ program.
|
||||
#define BUF_SIZE 16384
|
||||
#endif
|
||||
|
||||
static char **sources;
|
||||
static char **sources = NULL;
|
||||
static int nsources;
|
||||
static char *destination;
|
||||
static char *destination = NULL;
|
||||
static int verbosity = 0;
|
||||
static char *port = NULL;
|
||||
|
||||
struct location {
|
||||
int is_ssh;
|
||||
@@ -49,9 +50,10 @@ enum {
|
||||
static void usage(const char *argv0) {
|
||||
fprintf(stderr, "Usage : %s [options] [[user@]host1:]file1 ... \n"
|
||||
" [[user@]host2:]destination\n"
|
||||
"sample scp client - libssh-%s\n",
|
||||
// "Options :\n",
|
||||
// " -r : use RSA to verify host public key\n",
|
||||
"sample scp client - libssh-%s\n"
|
||||
"Options :\n"
|
||||
" -P : use port to connect to remote host\n"
|
||||
" -v : increase verbosity of libssh. Can be used multiple times\n",
|
||||
argv0,
|
||||
ssh_version(0));
|
||||
exit(0);
|
||||
@@ -60,11 +62,14 @@ static void usage(const char *argv0) {
|
||||
static int opts(int argc, char **argv) {
|
||||
int i;
|
||||
|
||||
while((i = getopt(argc, argv, "v")) != -1) {
|
||||
while((i = getopt(argc, argv, "P:v")) != -1) {
|
||||
switch(i) {
|
||||
case 'v':
|
||||
verbosity++;
|
||||
break;
|
||||
case 'P':
|
||||
port = optarg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown option %c\n", optopt);
|
||||
usage(argv[0]);
|
||||
@@ -114,9 +119,14 @@ static void location_free(struct location *loc)
|
||||
}
|
||||
}
|
||||
|
||||
static struct location *parse_location(char *loc) {
|
||||
struct location *location;
|
||||
char *ptr;
|
||||
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) {
|
||||
@@ -178,7 +188,7 @@ static void close_location(struct location *loc) {
|
||||
|
||||
static int open_location(struct location *loc, int flag) {
|
||||
if (loc->is_ssh && flag == WRITE) {
|
||||
loc->session = connect_ssh(loc->host, loc->user, verbosity);
|
||||
loc->session = connect_ssh(loc->host, port, loc->user, verbosity);
|
||||
if (!loc->session) {
|
||||
fprintf(stderr, "Couldn't connect to %s\n", loc->host);
|
||||
return -1;
|
||||
@@ -204,7 +214,7 @@ static int open_location(struct location *loc, int flag) {
|
||||
}
|
||||
return 0;
|
||||
} else if (loc->is_ssh && flag == READ) {
|
||||
loc->session = connect_ssh(loc->host, loc->user, verbosity);
|
||||
loc->session = connect_ssh(loc->host, port, loc->user, verbosity);
|
||||
if (!loc->session) {
|
||||
fprintf(stderr, "Couldn't connect to %s\n", loc->host);
|
||||
return -1;
|
||||
|
||||
@@ -35,8 +35,8 @@ clients must be made or how a client should react.
|
||||
static int authenticated=0;
|
||||
static int tries = 0;
|
||||
static int error = 0;
|
||||
static ssh_channel chan=NULL;
|
||||
static char *username;
|
||||
static ssh_channel chan = NULL;
|
||||
static char *username = NULL;
|
||||
static ssh_gssapi_creds client_creds = NULL;
|
||||
|
||||
static int auth_password(ssh_session session, const char *user,
|
||||
@@ -204,11 +204,12 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
#endif /* HAVE_ARGP_H */
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
ssh_bind sshbind;
|
||||
ssh_event mainloop;
|
||||
ssh_session client_session;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
ssh_bind sshbind = NULL;
|
||||
ssh_event mainloop = NULL;
|
||||
ssh_session client_session = NULL;
|
||||
|
||||
struct ssh_server_callbacks_struct cb = {
|
||||
.userdata = NULL,
|
||||
@@ -219,7 +220,7 @@ int main(int argc, char **argv){
|
||||
|
||||
char buf[BUF_SIZE];
|
||||
char host[128]="";
|
||||
char *ptr;
|
||||
char *ptr = NULL;
|
||||
int i,r, rc;
|
||||
|
||||
sshbind=ssh_bind_new();
|
||||
@@ -336,4 +337,3 @@ int main(int argc, char **argv){
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
ssh_bind sshbind = state->input;
|
||||
static int no_default_keys = 0;
|
||||
static int rsa_already_set = 0, ecdsa_already_set = 0;
|
||||
static int verbosity = 0;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
@@ -176,8 +177,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
strncpy(authorizedkeys, arg, DEF_STR_SIZE - 1);
|
||||
break;
|
||||
case 'v':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||
"3");
|
||||
verbosity++;
|
||||
ssh_bind_options_set(sshbind,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||
&verbosity);
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num >= 1)
|
||||
@@ -213,10 +216,7 @@ static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
#endif /* HAVE_ARGP_H */
|
||||
|
||||
/* A userdata struct for channel. */
|
||||
struct channel_data_struct
|
||||
{
|
||||
/* Event which is used to poll the above descriptors. */
|
||||
ssh_event event;
|
||||
struct channel_data_struct {
|
||||
sftp_session sftp;
|
||||
};
|
||||
|
||||
@@ -378,18 +378,11 @@ static void handle_session(ssh_event event, ssh_session session)
|
||||
do {
|
||||
/* Poll the main event which takes care of the session, the channel and
|
||||
* even our child process's stdout/stderr (once it's started). */
|
||||
if (ssh_event_dopoll(event, -1) == SSH_ERROR) {
|
||||
if (ssh_event_dopoll(event, 100) == SSH_ERROR) {
|
||||
ssh_channel_close(sdata.channel);
|
||||
}
|
||||
|
||||
/* If child process's stdout/stderr has been registered with the event,
|
||||
* or the child process hasn't started yet, continue. */
|
||||
if (cdata.event != NULL) {
|
||||
continue;
|
||||
}
|
||||
/* FIXME The server keeps hanging in the poll above when the client
|
||||
* closes the channel */
|
||||
} while (ssh_channel_is_open(sdata.channel));
|
||||
} while (ssh_channel_is_open(sdata.channel) &&
|
||||
!ssh_channel_is_eof(sdata.channel));
|
||||
|
||||
ssh_channel_send_eof(sdata.channel);
|
||||
ssh_channel_close(sdata.channel);
|
||||
|
||||
@@ -244,10 +244,11 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
#endif /* HAVE_ARGP_H */
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
ssh_bind sshbind;
|
||||
ssh_event mainloop;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
ssh_bind sshbind = NULL;
|
||||
ssh_event mainloop = NULL;
|
||||
struct ssh_server_callbacks_struct cb = {
|
||||
.userdata = NULL,
|
||||
.auth_none_function = auth_none,
|
||||
@@ -339,4 +340,3 @@ int main(int argc, char **argv){
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,8 +174,8 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
#endif /* HAVE_ARGP_H */
|
||||
|
||||
static const char *name;
|
||||
static const char *instruction;
|
||||
static const char *name = NULL;
|
||||
static const char *instruction = NULL;
|
||||
static const char *prompts[2];
|
||||
static char echo[] = { 1, 0 };
|
||||
|
||||
@@ -279,11 +279,12 @@ static int authenticate(ssh_session session) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
ssh_bind sshbind;
|
||||
ssh_message message;
|
||||
ssh_channel chan=0;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
ssh_bind sshbind = NULL;
|
||||
ssh_message message = NULL;
|
||||
ssh_channel chan = NULL;
|
||||
char buf[BUF_SIZE];
|
||||
int auth=0;
|
||||
int shell=0;
|
||||
@@ -411,4 +412,3 @@ int main(int argc, char **argv){
|
||||
ssh_finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,151 +32,163 @@ 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",
|
||||
// "Options :\n",
|
||||
// " -r : use RSA to verify host public key\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",
|
||||
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);
|
||||
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)
|
||||
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;
|
||||
}
|
||||
}
|
||||
host = argv[optind];
|
||||
if(host == NULL)
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
if (opts(argc, argv) < 0)
|
||||
return EXIT_FAILURE;
|
||||
session = connect_ssh(host, NULL, 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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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, NULL, 0);
|
||||
if (session == NULL) {
|
||||
return 1;
|
||||
}
|
||||
if(total > LIMIT)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
printf("error : %s\n",ssh_get_error(session));
|
||||
|
||||
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);
|
||||
|
||||
ssh_disconnect(session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssh_channel_send_eof(channel);
|
||||
ssh_channel_close(channel);
|
||||
|
||||
ssh_disconnect(session);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
@@ -231,7 +232,7 @@ static void _logging_callback(int priority, const char *function,
|
||||
|
||||
milliseconds = _current_timestamp();
|
||||
|
||||
fprintf(fp, "[%s.%jd, %d] %s: %s\n", buf, milliseconds, priority,
|
||||
fprintf(fp, "[%s.%" PRId64 ", %d] %s: %s\n", buf, milliseconds, priority,
|
||||
function, buffer);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/sftp.h>
|
||||
|
||||
|
||||
#include "examples_common.h"
|
||||
#define MAXCMD 10
|
||||
@@ -53,7 +51,7 @@ static struct termios terminal;
|
||||
|
||||
static char *pcap_file = NULL;
|
||||
|
||||
static char *proxycommand;
|
||||
static char *proxycommand = NULL;
|
||||
|
||||
static int auth_callback(const char *prompt,
|
||||
char *buf,
|
||||
@@ -112,8 +110,8 @@ static int opts(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
while((i = getopt(argc,argv,"T:P:F:")) != -1) {
|
||||
switch(i){
|
||||
while ((i = getopt(argc, argv, "T:P:F:")) != -1) {
|
||||
switch (i) {
|
||||
case 'P':
|
||||
pcap_file = optarg;
|
||||
break;
|
||||
@@ -159,16 +157,14 @@ static void cfmakeraw(struct termios *termios_p)
|
||||
|
||||
static void do_cleanup(int i)
|
||||
{
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
(void)i;
|
||||
|
||||
tcsetattr(0, TCSANOW, &terminal);
|
||||
tcsetattr(0, TCSANOW, &terminal);
|
||||
}
|
||||
|
||||
static void do_exit(int i)
|
||||
{
|
||||
/* unused variable */
|
||||
(void) i;
|
||||
(void)i;
|
||||
|
||||
do_cleanup(0);
|
||||
exit(0);
|
||||
@@ -179,7 +175,7 @@ static int signal_delayed = 0;
|
||||
#ifdef SIGWINCH
|
||||
static void sigwindowchanged(int i)
|
||||
{
|
||||
(void) i;
|
||||
(void)i;
|
||||
signal_delayed = 1;
|
||||
}
|
||||
#endif
|
||||
@@ -213,18 +209,18 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
||||
/* stdin */
|
||||
connector_in = ssh_connector_new(session);
|
||||
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
|
||||
ssh_connector_set_in_fd(connector_in, 0);
|
||||
ssh_connector_set_in_fd(connector_in, STDIN_FILENO);
|
||||
ssh_event_add_connector(event, connector_in);
|
||||
|
||||
/* stdout */
|
||||
connector_out = ssh_connector_new(session);
|
||||
ssh_connector_set_out_fd(connector_out, 1);
|
||||
ssh_connector_set_out_fd(connector_out, STDOUT_FILENO);
|
||||
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
|
||||
ssh_event_add_connector(event, connector_out);
|
||||
|
||||
/* stderr */
|
||||
connector_err = ssh_connector_new(session);
|
||||
ssh_connector_set_out_fd(connector_err, 2);
|
||||
ssh_connector_set_out_fd(connector_err, STDERR_FILENO);
|
||||
ssh_connector_set_in_channel(connector_err, channel, SSH_CONNECTOR_STDERR);
|
||||
ssh_event_add_connector(event, connector_err);
|
||||
|
||||
@@ -251,9 +247,9 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
||||
|
||||
static void shell(ssh_session session)
|
||||
{
|
||||
ssh_channel channel;
|
||||
ssh_channel channel = NULL;
|
||||
struct termios terminal_local;
|
||||
int interactive=isatty(0);
|
||||
int interactive = isatty(0);
|
||||
|
||||
channel = ssh_channel_new(session);
|
||||
if (channel == NULL) {
|
||||
@@ -339,7 +335,7 @@ static void batch_shell(ssh_session session)
|
||||
static int client(ssh_session session)
|
||||
{
|
||||
int auth = 0;
|
||||
char *banner;
|
||||
char *banner = NULL;
|
||||
int state;
|
||||
|
||||
if (user) {
|
||||
@@ -423,7 +419,7 @@ static void cleanup_pcap(void)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ssh_session session;
|
||||
ssh_session session = NULL;
|
||||
|
||||
ssh_init();
|
||||
session = ssh_new();
|
||||
|
||||
@@ -192,9 +192,6 @@ 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) {
|
||||
@@ -202,16 +199,10 @@ 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') {
|
||||
@@ -256,12 +247,6 @@ 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 */
|
||||
|
||||
@@ -361,7 +361,7 @@ my_fd_data_function(UNUSED_PARAM(socket_t fd),
|
||||
{
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
ssh_channel channel = event_fd_data->channel;
|
||||
ssh_session session;
|
||||
ssh_session session = NULL;
|
||||
int len, i, wr;
|
||||
char buf[BUF_SIZE];
|
||||
int blocking;
|
||||
@@ -455,8 +455,8 @@ open_tcp_socket(ssh_message msg)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
int forwardsock = -1;
|
||||
struct hostent *host;
|
||||
const char *dest_hostname;
|
||||
struct hostent *host = NULL;
|
||||
const char *dest_hostname = NULL;
|
||||
int dest_port;
|
||||
|
||||
forwardsock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
@@ -499,8 +499,8 @@ message_callback(UNUSED_PARAM(ssh_session session),
|
||||
UNUSED_PARAM(void *userdata))
|
||||
{
|
||||
ssh_channel channel;
|
||||
int socket_fd, *pFd;
|
||||
struct ssh_channel_callbacks_struct *cb_chan;
|
||||
int socket_fd, *pFd = NULL;
|
||||
struct ssh_channel_callbacks_struct *cb_chan = NULL;
|
||||
struct event_fd_data_struct *event_fd_data;
|
||||
|
||||
_ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d",
|
||||
@@ -655,8 +655,8 @@ static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
ssh_session session;
|
||||
ssh_bind sshbind;
|
||||
ssh_session session = NULL;
|
||||
ssh_bind sshbind = NULL;
|
||||
struct ssh_server_callbacks_struct cb = {
|
||||
.userdata = NULL,
|
||||
.auth_password_function = auth_password,
|
||||
|
||||
@@ -39,223 +39,237 @@ clients must be made or how a client should react.
|
||||
#define BUF_SIZE 4096
|
||||
#endif
|
||||
|
||||
char *host;
|
||||
const char *desthost="localhost";
|
||||
const char *port="22";
|
||||
char *host = NULL;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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(channel && ssh_channel_is_closed(channel)){
|
||||
ssh_channel_free(channel);
|
||||
channel=NULL;
|
||||
}
|
||||
} while (ret==EINTR || ret==SSH_EINTR);
|
||||
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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){
|
||||
ssh_session session;
|
||||
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,6 +31,7 @@ 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
|
||||
|
||||
@@ -52,6 +52,7 @@ enum ssh_bind_config_opcode_e {
|
||||
BIND_CFG_MATCH,
|
||||
BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
BIND_CFG_HOSTKEY_ALGORITHMS,
|
||||
BIND_CFG_REQUIRED_RSA_SIZE,
|
||||
|
||||
BIND_CFG_MAX /* Keep this one last in the list */
|
||||
};
|
||||
|
||||
@@ -74,6 +74,8 @@ ssh_string ssh_buffer_get_ssh_string(ssh_buffer buffer);
|
||||
uint32_t ssh_buffer_pass_bytes_end(ssh_buffer buffer, uint32_t len);
|
||||
uint32_t ssh_buffer_pass_bytes(ssh_buffer buffer, uint32_t len);
|
||||
|
||||
ssh_buffer ssh_buffer_dup(const ssh_buffer buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -113,6 +113,17 @@ typedef void (*ssh_status_callback) (ssh_session session, float status,
|
||||
typedef void (*ssh_global_request_callback) (ssh_session session,
|
||||
ssh_message message, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief SSH connect status callback. These are functions that report the
|
||||
* status of the connection i,e. a function indicating the completed percentage
|
||||
* of the connection
|
||||
* steps.
|
||||
* @param userdata Userdata to be passed to the callback function.
|
||||
* @param status Percentage of connection status, going from 0.0 to 1.0
|
||||
* once connection is done.
|
||||
*/
|
||||
typedef void (*ssh_connect_status_callback)(void *userdata, float status);
|
||||
|
||||
/**
|
||||
* @brief Handles an SSH new channel open X11 request. This happens when the server
|
||||
* sends back an X11 connection attempt. This is a client-side API
|
||||
@@ -181,7 +192,7 @@ struct ssh_callbacks_struct {
|
||||
* This function gets called during connection time to indicate the
|
||||
* percentage of connection steps completed.
|
||||
*/
|
||||
void (*connect_status_function)(void *userdata, float status);
|
||||
ssh_connect_status_callback connect_status_function;
|
||||
/**
|
||||
* This function will be called each time a global request is received.
|
||||
*/
|
||||
@@ -325,6 +336,28 @@ 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.
|
||||
@@ -375,6 +408,12 @@ 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;
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ enum ssh_config_opcode_e {
|
||||
SOC_CONTROLMASTER,
|
||||
SOC_CONTROLPATH,
|
||||
SOC_CERTIFICATE,
|
||||
SOC_REQUIRED_RSA_SIZE,
|
||||
|
||||
SOC_MAX /* Keep this one last in the list */
|
||||
};
|
||||
|
||||
@@ -45,10 +45,14 @@
|
||||
#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/curve25519.h"
|
||||
#include "libssh/sntrup761.h"
|
||||
#ifdef HAVE_MLKEM
|
||||
#include "libssh/mlkem768.h"
|
||||
#endif
|
||||
|
||||
#define DIGEST_MAX_LEN 64
|
||||
|
||||
@@ -56,32 +60,40 @@
|
||||
#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,
|
||||
/* 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,
|
||||
/* sntrup761x25519-sha512 */
|
||||
SSH_KEX_SNTRUP761X25519_SHA512,
|
||||
#ifdef HAVE_MLKEM
|
||||
/* mlkem768x25519-sha256 */
|
||||
SSH_KEX_MLKEM768X25519_SHA256,
|
||||
#endif /* HAVE_MLKEM */
|
||||
};
|
||||
|
||||
enum ssh_cipher_e {
|
||||
@@ -125,9 +137,25 @@ 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_MLKEM
|
||||
ssh_mlkem768_privkey mlkem768_client_privkey;
|
||||
ssh_mlkem768_pubkey mlkem768_client_pubkey;
|
||||
ssh_mlkem768_ciphertext mlkem768_ciphertext;
|
||||
#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;
|
||||
@@ -223,9 +251,8 @@ 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ 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(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);
|
||||
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);
|
||||
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_ */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2024 by Aris Adamantiadis and the libssh team
|
||||
* Copyright (c) 2003-2025 by Aris Adamantiadis and the libssh team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -49,9 +49,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef int mode_t;
|
||||
@@ -843,6 +844,7 @@ LIBSSH_API int ssh_string_fill(ssh_string str, const void *data, size_t len);
|
||||
do { if ((x) != NULL) { ssh_string_free(x); x = NULL; } } while(0)
|
||||
LIBSSH_API void ssh_string_free(ssh_string str);
|
||||
LIBSSH_API ssh_string ssh_string_from_char(const char *what);
|
||||
LIBSSH_API ssh_string ssh_string_from_data(const void *data, size_t len);
|
||||
LIBSSH_API size_t ssh_string_len(ssh_string str);
|
||||
LIBSSH_API ssh_string ssh_string_new(size_t size);
|
||||
LIBSSH_API const char *ssh_string_get_char(ssh_string str);
|
||||
@@ -850,6 +852,7 @@ LIBSSH_API char *ssh_string_to_char(ssh_string str);
|
||||
#define SSH_STRING_FREE_CHAR(x) \
|
||||
do { if ((x) != NULL) { ssh_string_free_char(x); x = NULL; } } while(0)
|
||||
LIBSSH_API void ssh_string_free_char(char *s);
|
||||
LIBSSH_API int ssh_string_cmp(ssh_string s1, ssh_string s2);
|
||||
|
||||
LIBSSH_API int ssh_getpass(const char *prompt, char *buf, size_t len, int echo,
|
||||
int verify);
|
||||
@@ -874,6 +877,7 @@ 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);
|
||||
@@ -886,6 +890,27 @@ 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,6 +28,7 @@ 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;
|
||||
|
||||
63
include/libssh/mlkem768.h
Normal file
63
include/libssh/mlkem768.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2025 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Sahana Prasad <sahana@redhat.com>
|
||||
* Author: Claude (Anthropic)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MLKEM768_H_
|
||||
#define MLKEM768_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* ML-KEM768 key and ciphertext sizes as defined in FIPS 203 */
|
||||
#define MLKEM768_PUBLICKEY_SIZE 1184
|
||||
#define MLKEM768_SECRETKEY_SIZE 2400
|
||||
#define MLKEM768_CIPHERTEXT_SIZE 1088
|
||||
#define MLKEM768_SHARED_SECRET_SIZE 32
|
||||
|
||||
/* Hybrid ML-KEM768x25519 combined sizes */
|
||||
#define MLKEM768X25519_CLIENT_PUBKEY_SIZE \
|
||||
(MLKEM768_PUBLICKEY_SIZE + CURVE25519_PUBKEY_SIZE)
|
||||
#define MLKEM768X25519_SERVER_RESPONSE_SIZE \
|
||||
(MLKEM768_CIPHERTEXT_SIZE + CURVE25519_PUBKEY_SIZE)
|
||||
#define MLKEM768X25519_SHARED_SECRET_SIZE \
|
||||
(MLKEM768_SHARED_SECRET_SIZE + CURVE25519_PUBKEY_SIZE)
|
||||
|
||||
typedef unsigned char ssh_mlkem768_pubkey[MLKEM768_PUBLICKEY_SIZE];
|
||||
typedef unsigned char ssh_mlkem768_privkey[MLKEM768_SECRETKEY_SIZE];
|
||||
typedef unsigned char ssh_mlkem768_ciphertext[MLKEM768_CIPHERTEXT_SIZE];
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ML-KEM768x25519 key exchange functions */
|
||||
int ssh_client_mlkem768x25519_init(ssh_session session);
|
||||
void ssh_client_mlkem768x25519_remove_callbacks(ssh_session session);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
void ssh_server_mlkem768x25519_init(ssh_session session);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MLKEM768_H_ */
|
||||
@@ -25,6 +25,7 @@
|
||||
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,
|
||||
|
||||
@@ -58,6 +58,7 @@ extern "C" {
|
||||
SSH_PACKET_CALLBACK(ssh_packet_unimplemented);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_ignore_callback);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_debug_callback);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_dh_reply);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_newkeys);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_service_accept);
|
||||
|
||||
@@ -46,11 +46,24 @@
|
||||
#define MAX_PUBKEY_SIZE 0x100000 /* 1M */
|
||||
#define MAX_PRIVKEY_SIZE 0x400000 /* 4M */
|
||||
|
||||
#define RSA_MIN_KEY_SIZE 1024
|
||||
#define RSA_MIN_FIPS_KEY_SIZE 2048
|
||||
#define RSA_DEFAULT_KEY_SIZE 3072
|
||||
|
||||
#define SSH_KEY_FLAG_EMPTY 0x0
|
||||
#define SSH_KEY_FLAG_PUBLIC 0x0001
|
||||
#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;
|
||||
@@ -63,11 +76,12 @@ struct ssh_key_struct {
|
||||
mbedtls_pk_context *pk;
|
||||
mbedtls_ecdsa_context *ecdsa;
|
||||
#elif defined(HAVE_LIBCRYPTO)
|
||||
/* This holds either ENGINE key for PKCS#11 support or just key in
|
||||
* high-level format */
|
||||
/* This holds either ENGINE/PROVIDER 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;
|
||||
@@ -76,6 +90,11 @@ struct ssh_key_struct {
|
||||
ssh_string sk_application;
|
||||
ssh_buffer cert;
|
||||
enum ssh_keytypes_e cert_type;
|
||||
|
||||
/* Security Key specific private data */
|
||||
uint8_t sk_flags;
|
||||
ssh_string sk_key_handle;
|
||||
ssh_string sk_reserved;
|
||||
};
|
||||
|
||||
struct ssh_signature_struct {
|
||||
@@ -127,6 +146,11 @@ enum ssh_digest_e ssh_key_hash_from_name(const char *name);
|
||||
((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\
|
||||
(kt) <= SSH_KEYTYPE_ED25519_CERT01))
|
||||
|
||||
#define is_sk_key_type(kt) \
|
||||
((kt) == SSH_KEYTYPE_SK_ECDSA || (kt) == SSH_KEYTYPE_SK_ED25519 || \
|
||||
(kt) == SSH_KEYTYPE_SK_ECDSA_CERT01 || \
|
||||
(kt) == SSH_KEYTYPE_SK_ED25519_CERT01)
|
||||
|
||||
/* SSH Signature Functions */
|
||||
ssh_signature ssh_signature_new(void);
|
||||
void ssh_signature_free(ssh_signature sign);
|
||||
|
||||
@@ -61,6 +61,7 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
|
||||
/* SSH Key Functions */
|
||||
ssh_key pki_key_dup_common_init(const ssh_key key, int demote);
|
||||
ssh_key pki_key_dup(const ssh_key key, int demote);
|
||||
int pki_key_generate_rsa(ssh_key key, int parameter);
|
||||
int pki_key_generate_ecdsa(ssh_key key, int parameter);
|
||||
@@ -148,6 +149,7 @@ 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);
|
||||
@@ -162,6 +164,16 @@ int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type);
|
||||
#endif /* WITH_PKCS11_URI */
|
||||
|
||||
bool ssh_key_size_allowed_rsa(int min_size, ssh_key key);
|
||||
|
||||
/* Security Key Helper Functions */
|
||||
int pki_buffer_pack_sk_priv_data(ssh_buffer buffer, const ssh_key key);
|
||||
int pki_buffer_unpack_sk_priv_data(ssh_buffer buffer, ssh_key key);
|
||||
int pki_sk_signature_buffer_prepare(const ssh_key key,
|
||||
const ssh_signature sig,
|
||||
const unsigned char *input,
|
||||
size_t input_len,
|
||||
ssh_buffer *sk_buffer_out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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,10 +30,11 @@
|
||||
#define _LIBSSH_PRIV_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#if !defined(HAVE_STRTOULL)
|
||||
# if defined(HAVE___STRTOULL)
|
||||
@@ -164,6 +165,9 @@ 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
|
||||
@@ -329,7 +333,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, unsigned int len);
|
||||
int match_hostname(const char *host, const char *pattern, size_t len);
|
||||
#ifndef _WIN32
|
||||
int match_cidr_address_list(const char *address,
|
||||
const char *addrlist,
|
||||
@@ -353,10 +357,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((char *)&(x), 0, sizeof(x))
|
||||
#define ZERO_STRUCT(x) memset(&(x), 0, sizeof(x))
|
||||
|
||||
/** Zero a structure given a pointer to the structure */
|
||||
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
|
||||
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((x), 0, sizeof(*(x))); } while(0)
|
||||
|
||||
/** Get the size of an array */
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
@@ -365,6 +369,17 @@ int ssh_connector_remove_event(ssh_connector connector);
|
||||
void explicit_bzero(void *s, size_t n);
|
||||
#endif /* !HAVE_EXPLICIT_BZERO */
|
||||
|
||||
void burn_free(void *ptr, size_t len);
|
||||
|
||||
/** Free memory space after zeroing it */
|
||||
#define BURN_FREE(x, len) \
|
||||
do { \
|
||||
if ((x) != NULL) { \
|
||||
burn_free((x), (len)); \
|
||||
(x) = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* This is a hack to fix warnings. The idea is to use this everywhere that we
|
||||
* get the "discarding const" warning by the compiler. That doesn't actually
|
||||
@@ -384,6 +399,7 @@ void explicit_bzero(void *s, size_t n);
|
||||
*/
|
||||
#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
|
||||
|
||||
#ifndef __VA_NARG__
|
||||
/**
|
||||
* Get the argument count of variadic arguments
|
||||
*/
|
||||
@@ -415,6 +431,7 @@ void explicit_bzero(void *s, size_t n);
|
||||
29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
|
||||
19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
|
||||
9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#endif
|
||||
|
||||
#define CLOSE_SOCKET(s) do { if ((s) != SSH_INVALID_SOCKET) { _XCLOSESOCKET(s); (s) = SSH_INVALID_SOCKET;} } while(0)
|
||||
|
||||
|
||||
@@ -89,6 +89,9 @@ enum ssh_pending_call_e {
|
||||
#define SSH_SESSION_FLAG_KEX_STRICT 0x0010
|
||||
/* Unexpected packets have been sent while the session was still unencrypted */
|
||||
#define SSH_SESSION_FLAG_KEX_TAINTED 0x0020
|
||||
/* The scp on server can not handle quoted paths. Skip the mitigation for
|
||||
* CVE-2019-14889 when using scp */
|
||||
#define SSH_SESSION_FLAG_SCP_QUOTING_BROKEN 0x0040
|
||||
|
||||
/* codes to use with ssh_handle_packets*() */
|
||||
/* Infinite timeout */
|
||||
@@ -120,6 +123,8 @@ 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,6 +79,7 @@ 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;
|
||||
@@ -213,6 +214,22 @@ 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.
|
||||
*
|
||||
@@ -220,24 +237,30 @@ struct sftp_limits_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.
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
* @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 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);
|
||||
|
||||
@@ -1188,6 +1211,58 @@ 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,6 +21,8 @@
|
||||
#ifndef SFTP_PRIV_H
|
||||
#define SFTP_PRIV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -62,6 +64,39 @@ 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.
|
||||
|
||||
@@ -29,6 +29,10 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/sftp.h"
|
||||
|
||||
/**
|
||||
* @defgroup libssh_sftp_server The libssh SFTP server API
|
||||
*
|
||||
|
||||
86
include/libssh/sntrup761.h
Normal file
86
include/libssh/sntrup761.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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_ */
|
||||
@@ -33,7 +33,7 @@ void ssh_socket_cleanup(void);
|
||||
ssh_socket ssh_socket_new(ssh_session session);
|
||||
void ssh_socket_reset(ssh_socket s);
|
||||
void ssh_socket_free(ssh_socket s);
|
||||
void ssh_socket_set_fd(ssh_socket s, socket_t fd);
|
||||
int ssh_socket_set_fd(ssh_socket s, socket_t fd);
|
||||
socket_t ssh_socket_get_fd(ssh_socket s);
|
||||
void ssh_socket_set_connected(ssh_socket s, struct ssh_poll_handle_struct *p);
|
||||
int ssh_socket_unix(ssh_socket s, const char *path);
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#define SSH2_MSG_KEXDH_REPLY 31
|
||||
#define SSH2_MSG_KEX_ECDH_INIT 30
|
||||
#define SSH2_MSG_KEX_ECDH_REPLY 31
|
||||
#define SSH2_MSG_ECMQV_INIT 30
|
||||
#define SSH2_MSG_ECMQV_REPLY 31
|
||||
#define SSH2_MSG_KEX_HYBRID_INIT 30
|
||||
#define SSH2_MSG_KEX_HYBRID_REPLY 31
|
||||
|
||||
#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
|
||||
#define SSH2_MSG_KEX_DH_GEX_GROUP 31
|
||||
|
||||
@@ -129,6 +129,7 @@ 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,3 +8,4 @@ Description: The SSH Library
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs: -L${libdir} -lssh
|
||||
Cflags: -I${includedir}
|
||||
Requires.private: @LIBSSH_PC_REQUIRES_PRIVATE@
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
set(LIBSSH_PUBLIC_INCLUDE_DIRS ${libssh_SOURCE_DIR}/include)
|
||||
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${libssh_BINARY_DIR}/include
|
||||
${libssh_BINARY_DIR}
|
||||
)
|
||||
|
||||
@@ -12,27 +13,13 @@ if (TARGET OpenSSL::Crypto)
|
||||
list(APPEND LIBSSH_LINK_LIBRARIES OpenSSL::Crypto)
|
||||
endif ()
|
||||
|
||||
if (MBEDTLS_CRYPTO_LIBRARY)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
${MBEDTLS_INCLUDE_DIR}
|
||||
)
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
${MBEDTLS_CRYPTO_LIBRARY}
|
||||
)
|
||||
endif (MBEDTLS_CRYPTO_LIBRARY)
|
||||
if (TARGET MbedTLS::mbedcrypto)
|
||||
list(APPEND LIBSSH_LINK_LIBRARIES MbedTLS::mbedcrypto)
|
||||
endif ()
|
||||
|
||||
if (GCRYPT_LIBRARIES)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
${GCRYPT_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
${GCRYPT_LIBRARIES})
|
||||
endif()
|
||||
if (TARGET libgcrypt::libgcrypt)
|
||||
list(APPEND LIBSSH_LINK_LIBRARIES ${GCRYPT_LIBRARIES})
|
||||
endif ()
|
||||
|
||||
if (WITH_ZLIB)
|
||||
list(APPEND LIBSSH_LINK_LIBRARIES ZLIB::ZLIB)
|
||||
@@ -100,10 +87,12 @@ set(libssh_SRCS
|
||||
connector.c
|
||||
crypto_common.c
|
||||
curve25519.c
|
||||
sntrup761.c
|
||||
dh.c
|
||||
ecdh.c
|
||||
error.c
|
||||
getpass.c
|
||||
gzip.c
|
||||
init.c
|
||||
kdf.c
|
||||
kex.c
|
||||
@@ -186,6 +175,13 @@ 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}
|
||||
@@ -202,6 +198,7 @@ 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
|
||||
@@ -211,17 +208,24 @@ 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
|
||||
@@ -265,13 +269,6 @@ if (WITH_GEX)
|
||||
)
|
||||
endif (WITH_GEX)
|
||||
|
||||
if (WITH_ZLIB)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
gzip.c
|
||||
)
|
||||
endif(WITH_ZLIB)
|
||||
|
||||
if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
@@ -280,14 +277,22 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
if (NOT WITH_NACL)
|
||||
if (NOT HAVE_LIBCRYPTO)
|
||||
if (NOT (HAVE_LIBCRYPTO OR HAVE_MBEDTLS_CURVE25519 OR HAVE_GCRYPT_CURVE25519))
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
curve25519_fallback.c
|
||||
external/curve25519_ref.c
|
||||
)
|
||||
endif()
|
||||
endif (NOT WITH_NACL)
|
||||
|
||||
if (HAVE_MLKEM)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
mlkem768.c
|
||||
)
|
||||
endif (HAVE_MLKEM)
|
||||
|
||||
# Set the path to the default map file
|
||||
set(MAP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.map")
|
||||
|
||||
@@ -355,6 +360,8 @@ endif (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
|
||||
|
||||
set_target_properties(ssh
|
||||
PROPERTIES
|
||||
C_STANDARD
|
||||
99
|
||||
VERSION
|
||||
${LIBRARY_VERSION}
|
||||
SOVERSION
|
||||
|
||||
409
src/agent.c
409
src/agent.c
@@ -67,87 +67,94 @@
|
||||
(((x) == SSH_AGENT_FAILURE) || ((x) == SSH_COM_AGENT2_FAILURE) || \
|
||||
((x) == SSH2_AGENT_FAILURE))
|
||||
|
||||
static uint32_t atomicio(struct ssh_agent_struct *agent, void *buf, uint32_t n, int do_read) {
|
||||
char *b = buf;
|
||||
uint32_t pos = 0;
|
||||
ssize_t res;
|
||||
ssh_pollfd_t pfd;
|
||||
ssh_channel channel = agent->channel;
|
||||
socket_t fd;
|
||||
static uint32_t
|
||||
atomicio(struct ssh_agent_struct *agent, void *buf, uint32_t n, int do_read)
|
||||
{
|
||||
char *b = buf;
|
||||
uint32_t pos = 0;
|
||||
ssize_t res;
|
||||
ssh_pollfd_t pfd;
|
||||
ssh_channel channel = agent->channel;
|
||||
socket_t fd;
|
||||
|
||||
/* Using a socket ? */
|
||||
if (channel == NULL) {
|
||||
fd = ssh_socket_get_fd(agent->sock);
|
||||
pfd.fd = fd;
|
||||
pfd.events = do_read ? POLLIN : POLLOUT;
|
||||
/* Using a socket ? */
|
||||
if (channel == NULL) {
|
||||
fd = ssh_socket_get_fd(agent->sock);
|
||||
pfd.fd = fd;
|
||||
pfd.events = do_read ? POLLIN : POLLOUT;
|
||||
|
||||
while (n > pos) {
|
||||
if (do_read) {
|
||||
res = recv(fd, b + pos, n - pos, 0);
|
||||
} else {
|
||||
res = send(fd, b + pos, n - pos, 0);
|
||||
}
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
while (n > pos) {
|
||||
if (do_read) {
|
||||
res = recv(fd, b + pos, n - pos, 0);
|
||||
} else {
|
||||
res = send(fd, b + pos, n - pos, 0);
|
||||
}
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
#ifdef EWOULDBLOCK
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
#else
|
||||
if (errno == EAGAIN) {
|
||||
if (errno == EAGAIN) {
|
||||
#endif
|
||||
(void) ssh_poll(&pfd, 1, -1);
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
case 0:
|
||||
/* read returns 0 on end-of-file */
|
||||
errno = do_read ? 0 : EPIPE;
|
||||
return pos;
|
||||
default:
|
||||
pos += (uint32_t) res;
|
||||
(void)ssh_poll(&pfd, 1, -1);
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
case 0:
|
||||
/* read returns 0 on end-of-file */
|
||||
errno = do_read ? 0 : EPIPE;
|
||||
return pos;
|
||||
default:
|
||||
pos += (uint32_t)res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
return pos;
|
||||
} else {
|
||||
/* using an SSH channel */
|
||||
while (n > pos){
|
||||
if (do_read)
|
||||
res = ssh_channel_read(channel,b + pos, n-pos, 0);
|
||||
else
|
||||
res = ssh_channel_write(channel, b+pos, n-pos);
|
||||
if (res == SSH_AGAIN)
|
||||
continue;
|
||||
if (res == SSH_ERROR)
|
||||
return 0;
|
||||
pos += (uint32_t)res;
|
||||
}
|
||||
return pos;
|
||||
/* using an SSH channel */
|
||||
while (n > pos) {
|
||||
if (do_read) {
|
||||
res = ssh_channel_read(channel, b + pos, n - pos, 0);
|
||||
} else {
|
||||
res = ssh_channel_write(channel, b + pos, n - pos);
|
||||
}
|
||||
if (res == SSH_AGAIN) {
|
||||
continue;
|
||||
}
|
||||
if (res == SSH_ERROR) {
|
||||
return 0;
|
||||
}
|
||||
pos += (uint32_t)res;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
ssh_agent ssh_agent_new(struct ssh_session_struct *session) {
|
||||
ssh_agent agent = NULL;
|
||||
ssh_agent ssh_agent_new(struct ssh_session_struct *session)
|
||||
{
|
||||
ssh_agent agent = NULL;
|
||||
|
||||
agent = malloc(sizeof(struct ssh_agent_struct));
|
||||
if (agent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(agent);
|
||||
agent = calloc(1, sizeof(struct ssh_agent_struct));
|
||||
if (agent == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
agent->count = 0;
|
||||
agent->sock = ssh_socket_new(session);
|
||||
if (agent->sock == NULL) {
|
||||
SAFE_FREE(agent);
|
||||
return NULL;
|
||||
}
|
||||
agent->channel = NULL;
|
||||
return agent;
|
||||
agent->count = 0;
|
||||
agent->sock = ssh_socket_new(session);
|
||||
if (agent->sock == NULL) {
|
||||
SAFE_FREE(agent);
|
||||
return NULL;
|
||||
}
|
||||
agent->channel = NULL;
|
||||
return agent;
|
||||
}
|
||||
|
||||
static void agent_set_channel(struct ssh_agent_struct *agent, ssh_channel channel){
|
||||
agent->channel = channel;
|
||||
static void agent_set_channel(struct ssh_agent_struct *agent,
|
||||
ssh_channel channel)
|
||||
{
|
||||
agent->channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,15 +175,19 @@ static void agent_set_channel(struct ssh_agent_struct *agent, ssh_channel channe
|
||||
* @returns SSH_OK in case of success
|
||||
* SSH_ERROR in case of an error
|
||||
*/
|
||||
int ssh_set_agent_channel(ssh_session session, ssh_channel channel){
|
||||
if (!session)
|
||||
return SSH_ERROR;
|
||||
if (!session->agent){
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Session has no active agent");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
agent_set_channel(session->agent, channel);
|
||||
return SSH_OK;
|
||||
int ssh_set_agent_channel(ssh_session session, ssh_channel channel)
|
||||
{
|
||||
if (!session) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (!session->agent) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Session has no active agent");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
agent_set_channel(session->agent, channel);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @brief sets the SSH agent socket.
|
||||
@@ -187,64 +198,71 @@ int ssh_set_agent_channel(ssh_session session, ssh_channel channel){
|
||||
* @returns SSH_OK in case of success
|
||||
* SSH_ERROR in case of an error
|
||||
*/
|
||||
int ssh_set_agent_socket(ssh_session session, socket_t fd){
|
||||
if (!session)
|
||||
return SSH_ERROR;
|
||||
if (!session->agent){
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED, "Session has no active agent");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
int ssh_set_agent_socket(ssh_session session, socket_t fd)
|
||||
{
|
||||
if (!session) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (!session->agent) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Session has no active agent");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ssh_socket_set_fd(session->agent->sock, fd);
|
||||
return SSH_OK;
|
||||
return ssh_socket_set_fd(session->agent->sock, fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
void ssh_agent_close(struct ssh_agent_struct *agent) {
|
||||
if (agent == NULL) {
|
||||
return;
|
||||
}
|
||||
void ssh_agent_close(struct ssh_agent_struct *agent)
|
||||
{
|
||||
if (agent == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_socket_close(agent->sock);
|
||||
ssh_socket_close(agent->sock);
|
||||
}
|
||||
|
||||
void ssh_agent_free(ssh_agent agent) {
|
||||
if (agent) {
|
||||
if (agent->ident) {
|
||||
SSH_BUFFER_FREE(agent->ident);
|
||||
void ssh_agent_free(ssh_agent agent)
|
||||
{
|
||||
if (agent) {
|
||||
if (agent->ident) {
|
||||
SSH_BUFFER_FREE(agent->ident);
|
||||
}
|
||||
if (agent->sock) {
|
||||
ssh_agent_close(agent);
|
||||
ssh_socket_free(agent->sock);
|
||||
}
|
||||
SAFE_FREE(agent);
|
||||
}
|
||||
if (agent->sock) {
|
||||
ssh_agent_close(agent);
|
||||
ssh_socket_free(agent->sock);
|
||||
}
|
||||
SAFE_FREE(agent);
|
||||
}
|
||||
}
|
||||
|
||||
static int agent_connect(ssh_session session) {
|
||||
const char *auth_sock = NULL;
|
||||
static int agent_connect(ssh_session session)
|
||||
{
|
||||
const char *auth_sock = NULL;
|
||||
|
||||
if (session == NULL || session->agent == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->agent->channel != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth_sock = session->opts.agent_socket ? session->opts.agent_socket
|
||||
: getenv("SSH_AUTH_SOCK");
|
||||
|
||||
if (auth_sock && *auth_sock) {
|
||||
if (ssh_socket_unix(session->agent->sock, auth_sock) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (session == NULL || session->agent == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->agent->channel != NULL)
|
||||
return 0;
|
||||
|
||||
auth_sock = session->opts.agent_socket ?
|
||||
session->opts.agent_socket : getenv("SSH_AUTH_SOCK");
|
||||
|
||||
if (auth_sock && *auth_sock) {
|
||||
if (ssh_socket_unix(session->agent->sock, auth_sock) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -268,61 +286,66 @@ static int agent_decode_reply(struct ssh_session_struct *session, int type) {
|
||||
#endif
|
||||
|
||||
static int agent_talk(struct ssh_session_struct *session,
|
||||
struct ssh_buffer_struct *request, struct ssh_buffer_struct *reply) {
|
||||
uint32_t len = 0;
|
||||
uint8_t tmpbuf[4];
|
||||
uint8_t *payload = tmpbuf;
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
struct ssh_buffer_struct *request,
|
||||
struct ssh_buffer_struct *reply)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
uint8_t tmpbuf[4];
|
||||
uint8_t *payload = tmpbuf;
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
|
||||
len = ssh_buffer_get_len(request);
|
||||
SSH_LOG(SSH_LOG_TRACE, "Request length: %" PRIu32, len);
|
||||
PUSH_BE_U32(payload, 0, len);
|
||||
len = ssh_buffer_get_len(request);
|
||||
SSH_LOG(SSH_LOG_TRACE, "Request length: %" PRIu32, len);
|
||||
PUSH_BE_U32(payload, 0, len);
|
||||
|
||||
/* send length and then the request packet */
|
||||
if (atomicio(session->agent, payload, 4, 0) == 4) {
|
||||
if (atomicio(session->agent, ssh_buffer_get(request), len, 0)
|
||||
!= len) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "atomicio sending request failed: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
/* send length and then the request packet */
|
||||
if (atomicio(session->agent, payload, 4, 0) == 4) {
|
||||
if (atomicio(session->agent, ssh_buffer_get(request), len, 0) != len) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"atomicio sending request failed: %s",
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"atomicio sending request length failed: %s",
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"atomicio sending request length failed: %s",
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* wait for response, read the length of the response packet */
|
||||
if (atomicio(session->agent, payload, 4, 1) != 4) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "atomicio read response length failed: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/* wait for response, read the length of the response packet */
|
||||
if (atomicio(session->agent, payload, 4, 1) != 4) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"atomicio read response length failed: %s",
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = PULL_BE_U32(payload, 0);
|
||||
if (len > 256 * 1024) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Authentication response too long: %" PRIu32, len);
|
||||
return -1;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_TRACE, "Response length: %" PRIu32, len);
|
||||
len = PULL_BE_U32(payload, 0);
|
||||
if (len > 256 * 1024) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Authentication response too long: %" PRIu32,
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_TRACE, "Response length: %" PRIu32, len);
|
||||
|
||||
payload = ssh_buffer_allocate(reply, len);
|
||||
if (payload == NULL) {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Not enough space");
|
||||
return -1;
|
||||
}
|
||||
payload = ssh_buffer_allocate(reply, len);
|
||||
if (payload == NULL) {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Not enough space");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (atomicio(session->agent, payload, len, 1) != len) {
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Error reading response from authentication socket.");
|
||||
/* Rollback the unused space */
|
||||
ssh_buffer_pass_bytes_end(reply, len);
|
||||
return -1;
|
||||
}
|
||||
if (atomicio(session->agent, payload, len, 1) != len) {
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Error reading response from authentication socket.");
|
||||
/* Rollback the unused space */
|
||||
ssh_buffer_pass_bytes_end(reply, len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t ssh_agent_get_ident_count(struct ssh_session_struct *session)
|
||||
@@ -422,8 +445,9 @@ ssh_key ssh_agent_get_first_ident(struct ssh_session_struct *session,
|
||||
|
||||
/* caller has to free comment */
|
||||
ssh_key ssh_agent_get_next_ident(struct ssh_session_struct *session,
|
||||
char **comment) {
|
||||
struct ssh_key_struct *key;
|
||||
char **comment)
|
||||
{
|
||||
struct ssh_key_struct *key = NULL;
|
||||
struct ssh_string_struct *blob = NULL;
|
||||
struct ssh_string_struct *tmp = NULL;
|
||||
int rc;
|
||||
@@ -470,35 +494,37 @@ ssh_key ssh_agent_get_next_ident(struct ssh_session_struct *session,
|
||||
return key;
|
||||
}
|
||||
|
||||
int ssh_agent_is_running(ssh_session session) {
|
||||
if (session == NULL || session->agent == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ssh_socket_is_open(session->agent->sock)) {
|
||||
return 1;
|
||||
} else {
|
||||
if (agent_connect(session) < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
int ssh_agent_is_running(ssh_session session)
|
||||
{
|
||||
if (session == NULL || session->agent == NULL) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (ssh_socket_is_open(session->agent->sock)) {
|
||||
return 1;
|
||||
} else {
|
||||
if (agent_connect(session) < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
const ssh_key pubkey,
|
||||
struct ssh_buffer_struct *data)
|
||||
{
|
||||
ssh_buffer request;
|
||||
ssh_buffer reply;
|
||||
ssh_string key_blob;
|
||||
ssh_string sig_blob;
|
||||
ssh_buffer request = NULL;
|
||||
ssh_buffer reply = NULL;
|
||||
ssh_string key_blob = NULL;
|
||||
ssh_string sig_blob = NULL;
|
||||
unsigned int type = 0;
|
||||
unsigned int flags = 0;
|
||||
uint32_t dlen;
|
||||
size_t request_len;
|
||||
int rc;
|
||||
|
||||
request = ssh_buffer_new();
|
||||
@@ -524,11 +550,14 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
* - 2 x uint32_t
|
||||
* - 1 x ssh_string (uint8_t + data)
|
||||
*/
|
||||
rc = ssh_buffer_allocate_size(request,
|
||||
sizeof(uint8_t) * 2 +
|
||||
sizeof(uint32_t) * 2 +
|
||||
ssh_string_len(key_blob));
|
||||
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);
|
||||
if (rc < 0) {
|
||||
SSH_STRING_FREE(key_blob);
|
||||
SSH_BUFFER_FREE(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
275
src/auth.c
275
src/auth.c
@@ -195,8 +195,9 @@ static int ssh_userauth_get_response(ssh_session session)
|
||||
*
|
||||
* This banner should be shown to user prior to authentication
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner) {
|
||||
ssh_string banner;
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_banner)
|
||||
{
|
||||
ssh_string banner = NULL;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
@@ -462,6 +463,108 @@ 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.
|
||||
*
|
||||
@@ -508,29 +611,42 @@ 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
|
||||
* compatibility to make sure the possible EXT_INFO packet is processed,
|
||||
* extensions recorded and the right signature type is used below
|
||||
*/
|
||||
rc = ssh_userauth_request_service(session);
|
||||
if (rc == SSH_AGAIN) {
|
||||
return SSH_AUTH_AGAIN;
|
||||
} else if (rc == SSH_ERROR) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@@ -538,19 +654,15 @@ 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;
|
||||
}
|
||||
|
||||
rc = ssh_userauth_request_service(session);
|
||||
if (rc == SSH_AGAIN) {
|
||||
return SSH_AUTH_AGAIN;
|
||||
} else if (rc == SSH_ERROR) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
/* public key */
|
||||
rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_s);
|
||||
if (rc < 0) {
|
||||
@@ -558,20 +670,10 @@ int ssh_userauth_try_publickey(ssh_session session,
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Trying signature type %s", sig_type_c);
|
||||
/* 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 */
|
||||
);
|
||||
rc = build_pubkey_auth_request(session, username, 0, sig_type_c, pubkey_s);
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SSH_STRING_FREE(pubkey_s);
|
||||
|
||||
session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
|
||||
@@ -640,16 +742,28 @@ 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
|
||||
* compatibility to make sure the possible EXT_INFO packet is processed,
|
||||
* extensions recorded and the right signature type is used below
|
||||
*/
|
||||
rc = ssh_userauth_request_service(session);
|
||||
if (rc == SSH_AGAIN) {
|
||||
return SSH_AUTH_AGAIN;
|
||||
} else if (rc == SSH_ERROR) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
/* Cert auth requires presenting the cert type name (*-cert@openssh.com) */
|
||||
@@ -658,13 +772,15 @@ 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);
|
||||
@@ -672,19 +788,15 @@ 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;
|
||||
}
|
||||
|
||||
rc = ssh_userauth_request_service(session);
|
||||
if (rc == SSH_AGAIN) {
|
||||
return SSH_AUTH_AGAIN;
|
||||
} else if (rc == SSH_ERROR) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
/* get public key or cert */
|
||||
rc = ssh_pki_export_pubkey_blob(privkey, &str);
|
||||
if (rc < 0) {
|
||||
@@ -692,16 +804,7 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Sending signature type %s", sig_type_c);
|
||||
/* 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 */
|
||||
);
|
||||
rc = build_pubkey_auth_request(session, username, 1, sig_type_c, str);
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -769,6 +872,10 @@ static int ssh_userauth_agent_publickey(ssh_session session,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Note, that this is intentionally before checking the signature type
|
||||
* compatibility to make sure the possible EXT_INFO packet is processed,
|
||||
* extensions recorded and the right signature type is used below
|
||||
*/
|
||||
rc = ssh_userauth_request_service(session);
|
||||
if (rc == SSH_AGAIN) {
|
||||
return SSH_AUTH_AGAIN;
|
||||
@@ -785,14 +892,16 @@ 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);
|
||||
@@ -801,27 +910,21 @@ 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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
rc = build_pubkey_auth_request(session, username, 1, sig_type_c, 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);
|
||||
@@ -879,7 +982,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,8 +1008,7 @@ 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;
|
||||
@@ -925,12 +1027,11 @@ int ssh_userauth_agent(ssh_session session,
|
||||
}
|
||||
|
||||
if (!session->agent_state) {
|
||||
session->agent_state = malloc(sizeof(struct ssh_agent_state_struct));
|
||||
session->agent_state = calloc(1, sizeof(struct ssh_agent_state_struct));
|
||||
if (!session->agent_state) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
ZERO_STRUCTP(session->agent_state);
|
||||
session->agent_state->state = SSH_AGENT_STATE_NONE;
|
||||
}
|
||||
|
||||
@@ -1682,7 +1783,7 @@ int ssh_userauth_agent_pubkey(ssh_session session,
|
||||
const char *username,
|
||||
ssh_public_key publickey)
|
||||
{
|
||||
ssh_key key;
|
||||
ssh_key key = NULL;
|
||||
int rc;
|
||||
|
||||
key = ssh_key_new();
|
||||
|
||||
15
src/base64.c
15
src/base64.c
@@ -29,6 +29,9 @@
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/buffer.h"
|
||||
|
||||
/* Do not allow encoding more than 256MB of data */
|
||||
#define BASE64_MAX_INPUT_LEN 256 * 1024 * 1024
|
||||
|
||||
static
|
||||
const uint8_t alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
@@ -183,7 +186,7 @@ error:
|
||||
static int to_block4(unsigned long *block, const char *source, int num)
|
||||
{
|
||||
const char *ptr = NULL;
|
||||
unsigned int i;
|
||||
size_t i;
|
||||
|
||||
*block = 0;
|
||||
if (num < 1) {
|
||||
@@ -278,7 +281,15 @@ uint8_t *bin_to_base64(const uint8_t *source, size_t len)
|
||||
{
|
||||
uint8_t *base64 = NULL;
|
||||
uint8_t *ptr = NULL;
|
||||
size_t flen = len + (3 - (len % 3)); /* round to upper 3 multiple */
|
||||
size_t flen = 0;
|
||||
|
||||
/* Set the artificial upper limit for the input. Otherwise on 32b arch, the
|
||||
* following line could overflow for sizes larger than SIZE_MAX / 4 */
|
||||
if (len > BASE64_MAX_INPUT_LEN) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flen = len + (3 - (len % 3)); /* round to upper 3 multiple */
|
||||
flen = (4 * flen) / 3 + 1;
|
||||
|
||||
base64 = malloc(flen);
|
||||
|
||||
73
src/bignum.c
73
src/bignum.c
@@ -27,40 +27,52 @@
|
||||
#include "libssh/bignum.h"
|
||||
#include "libssh/string.h"
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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++;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
#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) {
|
||||
ptr->data[0] = 0;
|
||||
}
|
||||
/* We have a negative number so we need a leading zero */
|
||||
if (pad) {
|
||||
memset(ptr->data, 0, pad);
|
||||
}
|
||||
|
||||
bignum_bn2bin(num, len, ptr->data + pad);
|
||||
bignum_bn2bin(num, len, ptr->data + pad);
|
||||
|
||||
return ptr;
|
||||
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);
|
||||
}
|
||||
|
||||
bignum ssh_make_string_bn(ssh_string string)
|
||||
@@ -71,10 +83,11 @@ 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, len, &bn);
|
||||
bignum_bin2bn(string->data, (int)len, &bn);
|
||||
|
||||
return bn;
|
||||
}
|
||||
@@ -86,7 +99,9 @@ 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);
|
||||
}
|
||||
|
||||
44
src/bind.c
44
src/bind.c
@@ -74,7 +74,7 @@
|
||||
static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
|
||||
int port) {
|
||||
char port_c[6];
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *ai = NULL;
|
||||
struct addrinfo hints;
|
||||
int opt = 1;
|
||||
socket_t s;
|
||||
@@ -132,8 +132,9 @@ static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
|
||||
return s;
|
||||
}
|
||||
|
||||
ssh_bind ssh_bind_new(void) {
|
||||
ssh_bind ptr;
|
||||
ssh_bind ssh_bind_new(void)
|
||||
{
|
||||
ssh_bind ptr = NULL;
|
||||
|
||||
ptr = calloc(1, sizeof(struct ssh_bind_struct));
|
||||
if (ptr == NULL) {
|
||||
@@ -217,28 +218,12 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_bind_listen(ssh_bind sshbind) {
|
||||
const char *host;
|
||||
int ssh_bind_listen(ssh_bind sshbind)
|
||||
{
|
||||
const char *host = NULL;
|
||||
socket_t fd;
|
||||
int rc;
|
||||
|
||||
/* Apply global bind configurations, if it hasn't been applied before */
|
||||
rc = ssh_bind_options_parse_config(sshbind, NULL);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,"Could not parse global config");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Set default hostkey paths if no hostkey was found before */
|
||||
if (sshbind->ecdsakey == NULL &&
|
||||
sshbind->rsakey == NULL &&
|
||||
sshbind->ed25519key == NULL) {
|
||||
|
||||
sshbind->ecdsakey = strdup("/etc/ssh/ssh_host_ecdsa_key");
|
||||
sshbind->rsakey = strdup("/etc/ssh/ssh_host_rsa_key");
|
||||
sshbind->ed25519key = strdup("/etc/ssh/ssh_host_ed25519_key");
|
||||
}
|
||||
|
||||
/* Apply global bind configurations, if it hasn't been applied before */
|
||||
rc = ssh_bind_options_parse_config(sshbind, NULL);
|
||||
if (rc != 0) {
|
||||
@@ -288,10 +273,10 @@ int ssh_bind_listen(ssh_bind sshbind) {
|
||||
}
|
||||
|
||||
sshbind->bindfd = fd;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Using app-provided bind socket");
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Using app-provided bind socket");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ssh_bind_set_callbacks(ssh_bind sshbind, ssh_bind_callbacks callbacks, void *userdata)
|
||||
@@ -462,7 +447,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
|
||||
return SSH_ERROR;
|
||||
}
|
||||
} else {
|
||||
char *p;
|
||||
char *p = NULL;
|
||||
/* If something was set to the session prior to calling this
|
||||
* function, keep only what is allowed by the options set in
|
||||
* sshbind */
|
||||
@@ -504,7 +489,10 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
|
||||
ssh_set_error_oom(sshbind);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
ssh_socket_set_fd(session->socket, fd);
|
||||
rc = ssh_socket_set_fd(session->socket, fd);
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
handle = ssh_socket_get_poll_handle(session->socket);
|
||||
if (handle == NULL) {
|
||||
ssh_set_error_oom(sshbind);
|
||||
|
||||
@@ -104,6 +104,11 @@ ssh_bind_config_keyword_table[] = {
|
||||
.opcode = BIND_CFG_HOSTKEY_ALGORITHMS,
|
||||
.allowed_in_match = true
|
||||
},
|
||||
{
|
||||
.name = "requiredrsasize",
|
||||
.opcode = BIND_CFG_REQUIRED_RSA_SIZE,
|
||||
.allowed_in_match = true
|
||||
},
|
||||
{
|
||||
.opcode = BIND_CFG_UNKNOWN,
|
||||
}
|
||||
@@ -200,7 +205,7 @@ local_parse_file(ssh_bind bind,
|
||||
uint8_t *seen,
|
||||
unsigned int depth)
|
||||
{
|
||||
FILE *f;
|
||||
FILE *f = NULL;
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
int rv;
|
||||
@@ -293,6 +298,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
||||
const char *p = NULL;
|
||||
char *s = NULL, *x = NULL;
|
||||
char *keyword = NULL;
|
||||
long l;
|
||||
size_t len;
|
||||
|
||||
int rc = 0;
|
||||
@@ -594,6 +600,18 @@ ssh_bind_config_parse_line(ssh_bind bind,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_REQUIRED_RSA_SIZE:
|
||||
l = ssh_config_get_long(&s, -1);
|
||||
if (l >= 0 && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_RSA_MIN_SIZE, &l);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"line %d: Failed to set RequiredRSASize value '%ld'",
|
||||
count,
|
||||
l);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_NOT_ALLOWED_IN_MATCH:
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Option not allowed in Match block: %s, line: %d",
|
||||
keyword, count);
|
||||
@@ -626,7 +644,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const char *filename)
|
||||
{
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
FILE *f;
|
||||
FILE *f = NULL;
|
||||
uint32_t parser_flags;
|
||||
int rv;
|
||||
|
||||
@@ -669,7 +687,8 @@ 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, line_len;
|
||||
unsigned int line_num = 0;
|
||||
size_t line_len;
|
||||
uint32_t parser_flags;
|
||||
int rv;
|
||||
|
||||
@@ -698,8 +717,10 @@ 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: %u characters",
|
||||
line_num, line_len);
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Line %u too long: %zu characters",
|
||||
line_num,
|
||||
line_len);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(line, line_start, line_len);
|
||||
|
||||
152
src/buffer.c
152
src/buffer.c
@@ -371,7 +371,8 @@ int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer,
|
||||
*/
|
||||
void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
|
||||
{
|
||||
void *ptr;
|
||||
void *ptr = NULL;
|
||||
|
||||
buffer_verify(buffer);
|
||||
|
||||
if (buffer->used + len < len) {
|
||||
@@ -406,20 +407,26 @@ 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) {
|
||||
uint32_t len = 0;
|
||||
int
|
||||
ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
|
||||
struct ssh_string_struct *string)
|
||||
{
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
if (string == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (string == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = ssh_string_len(string);
|
||||
if (ssh_buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -610,6 +617,53 @@ uint32_t ssh_buffer_get_len(struct ssh_buffer_struct *buffer){
|
||||
return buffer->used - buffer->pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Duplicate an existing buffer.
|
||||
*
|
||||
* Creates a new ssh_buffer and copies all data from the source buffer.
|
||||
* The new buffer preserves the secure flag setting of the source.
|
||||
*
|
||||
* @param[in] buffer The buffer to duplicate. Can be NULL.
|
||||
*
|
||||
* @return A new buffer containing a copy of the data on success,
|
||||
* NULL on failure or if buffer is NULL.
|
||||
*
|
||||
* @see ssh_buffer_free()
|
||||
*/
|
||||
ssh_buffer ssh_buffer_dup(const ssh_buffer buffer)
|
||||
{
|
||||
ssh_buffer new_buffer = NULL;
|
||||
int rc;
|
||||
|
||||
if (buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer_verify(buffer);
|
||||
|
||||
new_buffer = ssh_buffer_new();
|
||||
if (new_buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_buffer->secure = buffer->secure;
|
||||
|
||||
if (ssh_buffer_get_len(buffer) > 0) {
|
||||
rc = ssh_buffer_add_data(new_buffer,
|
||||
ssh_buffer_get(buffer),
|
||||
ssh_buffer_get_len(buffer));
|
||||
if (rc != SSH_OK) {
|
||||
ssh_buffer_free(new_buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
buffer_verify(new_buffer);
|
||||
return new_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -822,6 +876,7 @@ 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;
|
||||
@@ -852,7 +907,7 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
||||
break;
|
||||
case 'S':
|
||||
string = va_arg(ap, ssh_string);
|
||||
needed_size += 4 + ssh_string_len(string);
|
||||
needed_size += sizeof(uint32_t) + ssh_string_len(string);
|
||||
string = NULL;
|
||||
break;
|
||||
case 's':
|
||||
@@ -866,13 +921,18 @@ 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':
|
||||
va_arg(ap, bignum);
|
||||
/*
|
||||
* Use a fixed size for a bignum
|
||||
* (they should normally be around 32)
|
||||
*/
|
||||
needed_size += 64;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
cstring = va_arg(ap, char *);
|
||||
@@ -926,7 +986,7 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
va_list ap)
|
||||
{
|
||||
int rc = SSH_ERROR;
|
||||
const char *p;
|
||||
const char *p = NULL;
|
||||
union {
|
||||
uint8_t byte;
|
||||
uint16_t word;
|
||||
@@ -935,7 +995,7 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
ssh_string string;
|
||||
void *data;
|
||||
} o;
|
||||
char *cstring;
|
||||
char *cstring = NULL;
|
||||
bignum b;
|
||||
size_t len;
|
||||
size_t count;
|
||||
@@ -978,24 +1038,40 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
case 's':
|
||||
cstring = va_arg(ap, char *);
|
||||
len = strlen(cstring);
|
||||
rc = ssh_buffer_add_u32(buffer, htonl(len));
|
||||
if (len > UINT32_MAX) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
o.dword = (uint32_t)len;
|
||||
rc = ssh_buffer_add_u32(buffer, htonl(o.dword));
|
||||
if (rc == SSH_OK){
|
||||
rc = ssh_buffer_add_data(buffer, cstring, len);
|
||||
rc = ssh_buffer_add_data(buffer, cstring, o.dword);
|
||||
}
|
||||
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, len);
|
||||
rc = ssh_buffer_add_data(buffer, o.data, (uint32_t)len);
|
||||
o.data = NULL;
|
||||
break;
|
||||
case 'F':
|
||||
case 'B':
|
||||
b = va_arg(ap, bignum);
|
||||
o.string = ssh_make_bignum_string(b);
|
||||
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);
|
||||
}
|
||||
if(o.string == NULL){
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
@@ -1006,7 +1082,11 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
case 't':
|
||||
cstring = va_arg(ap, char *);
|
||||
len = strlen(cstring);
|
||||
rc = ssh_buffer_add_data(buffer, cstring, len);
|
||||
if (len > UINT32_MAX) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rc = ssh_buffer_add_data(buffer, cstring, (uint32_t)len);
|
||||
cstring = NULL;
|
||||
break;
|
||||
default:
|
||||
@@ -1047,6 +1127,8 @@ 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
|
||||
@@ -1094,7 +1176,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
va_list ap)
|
||||
{
|
||||
int rc = SSH_ERROR;
|
||||
const char *p = format, *last;
|
||||
const char *p = format, *last = NULL;
|
||||
union {
|
||||
uint8_t *byte;
|
||||
uint16_t *word;
|
||||
@@ -1186,28 +1268,28 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
if (rlen != 4){
|
||||
break;
|
||||
}
|
||||
len = ntohl(u32len);
|
||||
if (len > max_len - 1) {
|
||||
u32len = ntohl(u32len);
|
||||
if (u32len > max_len - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_validate_length(buffer, len);
|
||||
rc = ssh_buffer_validate_length(buffer, u32len);
|
||||
if (rc != SSH_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
*o.cstring = malloc(len + 1);
|
||||
*o.cstring = malloc(u32len + 1);
|
||||
if (*o.cstring == NULL){
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rlen = ssh_buffer_get_data(buffer, *o.cstring, len);
|
||||
if (rlen != len){
|
||||
rlen = ssh_buffer_get_data(buffer, *o.cstring, u32len);
|
||||
if (rlen != u32len) {
|
||||
SAFE_FREE(*o.cstring);
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
(*o.cstring)[len] = '\0';
|
||||
(*o.cstring)[u32len] = '\0';
|
||||
o.cstring = NULL;
|
||||
rc = SSH_OK;
|
||||
break;
|
||||
@@ -1232,7 +1314,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
rlen = ssh_buffer_get_data(buffer, *o.data, len);
|
||||
rlen = ssh_buffer_get_data(buffer, *o.data, (uint32_t)len);
|
||||
if (rlen != len){
|
||||
SAFE_FREE(*o.data);
|
||||
rc = SSH_ERROR;
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/session.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,8 +45,7 @@ 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();
|
||||
@@ -54,26 +53,27 @@ _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;
|
||||
}
|
||||
@@ -122,14 +122,14 @@ int ssh_add_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
|
||||
|
||||
int ssh_remove_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
|
||||
{
|
||||
struct ssh_iterator *it;
|
||||
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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ static int chacha20_set_encrypt_key(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
void *IV)
|
||||
{
|
||||
struct chacha20_poly1305_keysched *sched;
|
||||
struct chacha20_poly1305_keysched *sched = NULL;
|
||||
uint8_t *u8key = key;
|
||||
(void)IV;
|
||||
|
||||
|
||||
1751
src/channels.c
1751
src/channels.c
File diff suppressed because it is too large
Load Diff
88
src/client.c
88
src/client.c
@@ -46,6 +46,15 @@
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/kex.h"
|
||||
#ifdef HAVE_MLKEM
|
||||
#include "libssh/mlkem768.h"
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef HAVE_PTHREAD
|
||||
extern int proxy_disconnect;
|
||||
#endif /* HAVE_PTHREAD */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#define set_status(session, status) do {\
|
||||
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
|
||||
@@ -220,7 +229,7 @@ int ssh_send_banner(ssh_session session, int server)
|
||||
terminator);
|
||||
}
|
||||
|
||||
rc = ssh_socket_write(session->socket, buffer, strlen(buffer));
|
||||
rc = ssh_socket_write(session->socket, buffer, (uint32_t)strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
goto end;
|
||||
}
|
||||
@@ -229,8 +238,8 @@ int ssh_send_banner(ssh_session session, int server)
|
||||
ssh_pcap_context_write(session->pcap_ctx,
|
||||
SSH_PCAP_DIR_OUT,
|
||||
buffer,
|
||||
strlen(buffer),
|
||||
strlen(buffer));
|
||||
(uint32_t)strlen(buffer),
|
||||
(uint32_t)strlen(buffer));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -248,45 +257,58 @@ 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;
|
||||
rc = ssh_client_curve25519_init(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_SNTRUP761
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512:
|
||||
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
|
||||
rc = ssh_client_sntrup761x25519_init(session);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_MLKEM
|
||||
case SSH_KEX_MLKEM768X25519_SHA256:
|
||||
rc = ssh_client_mlkem768x25519_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;
|
||||
@@ -294,15 +316,17 @@ 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)
|
||||
@@ -587,8 +611,7 @@ int ssh_connect(ssh_session session)
|
||||
|
||||
if (session->opts.fd != SSH_INVALID_SOCKET) {
|
||||
session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED;
|
||||
ssh_socket_set_fd(session->socket, session->opts.fd);
|
||||
ret = SSH_OK;
|
||||
ret = ssh_socket_set_fd(session->socket, session->opts.fd);
|
||||
#ifndef _WIN32
|
||||
#ifdef HAVE_PTHREAD
|
||||
} else if (ssh_libssh_proxy_jumps() &&
|
||||
@@ -765,8 +788,6 @@ ssh_session_set_disconnect_message(ssh_session session, const char *message)
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
extern int proxy_disconnect;
|
||||
|
||||
/**
|
||||
* @brief Disconnect from a session (client or server).
|
||||
*
|
||||
@@ -781,7 +802,7 @@ extern int proxy_disconnect;
|
||||
void
|
||||
ssh_disconnect(ssh_session session)
|
||||
{
|
||||
struct ssh_iterator *it;
|
||||
struct ssh_iterator *it = NULL;
|
||||
int rc;
|
||||
|
||||
if (session == NULL) {
|
||||
@@ -789,12 +810,14 @@ ssh_disconnect(ssh_session session)
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef HAVE_PTHREAD
|
||||
/* Only send the disconnect to all other threads when the root session calls
|
||||
* ssh_disconnect() */
|
||||
if (session->proxy_root) {
|
||||
proxy_disconnect = 1;
|
||||
}
|
||||
#endif
|
||||
#endif /* HAVE_PTHREAD */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
if (session->disconnect_message == NULL) {
|
||||
session->disconnect_message = strdup("Bye Bye") ;
|
||||
@@ -830,6 +853,7 @@ error:
|
||||
session->opts.fd = SSH_INVALID_SOCKET;
|
||||
session->session_state = SSH_SESSION_STATE_DISCONNECTED;
|
||||
session->pending_call_state = SSH_PENDING_CALL_NONE;
|
||||
session->packet_state = PACKET_STATE_INIT;
|
||||
|
||||
while ((it = ssh_list_get_iterator(session->channels)) != NULL) {
|
||||
ssh_channel_do_free(ssh_iterator_value(ssh_channel, it));
|
||||
@@ -889,7 +913,7 @@ error:
|
||||
*/
|
||||
const char *ssh_copyright(void)
|
||||
{
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2024 "
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2025 "
|
||||
"Aris Adamantiadis, Andreas Schneider "
|
||||
"and libssh contributors. "
|
||||
"Distributed under the LGPL, please refer to COPYING "
|
||||
|
||||
122
src/config.c
122
src/config.c
@@ -39,10 +39,12 @@
|
||||
# include <errno.h>
|
||||
# include <signal.h>
|
||||
# include <sys/wait.h>
|
||||
# include <ifaddrs.h>
|
||||
# include <net/if.h>
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/config_parser.h"
|
||||
#include "libssh/config.h"
|
||||
@@ -130,9 +132,9 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "verifyhostkeydns", SOC_UNSUPPORTED},
|
||||
{ "visualhostkey", SOC_UNSUPPORTED},
|
||||
{ "clearallforwardings", SOC_NA},
|
||||
{ "controlmaster", SOC_CONTROLMASTER},
|
||||
{ "controlmaster", SOC_NA},
|
||||
{ "controlpersist", SOC_NA},
|
||||
{ "controlpath", SOC_CONTROLPATH},
|
||||
{ "controlpath", SOC_NA},
|
||||
{ "dynamicforward", SOC_NA},
|
||||
{ "escapechar", SOC_NA},
|
||||
{ "exitonforwardfailure", SOC_NA},
|
||||
@@ -151,6 +153,7 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "tunneldevice", SOC_NA},
|
||||
{ "xauthlocation", SOC_NA},
|
||||
{ "pubkeyacceptedkeytypes", SOC_PUBKEYACCEPTEDKEYTYPES},
|
||||
{ "requiredrsasize", SOC_REQUIRED_RSA_SIZE},
|
||||
{ NULL, SOC_UNKNOWN }
|
||||
};
|
||||
|
||||
@@ -209,7 +212,7 @@ local_parse_file(ssh_session session,
|
||||
unsigned int depth,
|
||||
bool global)
|
||||
{
|
||||
FILE *f;
|
||||
FILE *f = NULL;
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
int rv;
|
||||
@@ -639,7 +642,7 @@ ssh_config_make_absolute(ssh_session session,
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
/**
|
||||
* @brief Checks if host address matches the local network specified.
|
||||
*
|
||||
@@ -730,7 +733,7 @@ ssh_match_localnetwork(const char *addrlist, bool negate)
|
||||
|
||||
return (found == (negate ? 0 : 1));
|
||||
}
|
||||
#endif
|
||||
#endif /* HAVE_IFADDRS_H */
|
||||
|
||||
static int
|
||||
ssh_config_parse_line(ssh_session session,
|
||||
@@ -892,9 +895,11 @@ ssh_config_parse_line(ssh_session session,
|
||||
/* Here we match only one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"line %d: ERROR - Match user keyword "
|
||||
"requires argument", count);
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"line %d: ERROR - Match localuser keyword "
|
||||
"requires argument",
|
||||
count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
@@ -955,7 +960,6 @@ ssh_config_parse_line(ssh_session session,
|
||||
args++;
|
||||
break;
|
||||
|
||||
#ifndef _WIN32
|
||||
case MATCH_LOCALNETWORK:
|
||||
/* Here we match only one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
@@ -968,6 +972,7 @@ ssh_config_parse_line(ssh_session session,
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
rv = match_cidr_address_list(NULL, p, -1);
|
||||
if (rv == -1) {
|
||||
ssh_set_error(session,
|
||||
@@ -992,23 +997,31 @@ ssh_config_parse_line(ssh_session session,
|
||||
}
|
||||
|
||||
result &= rv;
|
||||
#else /* HAVE_IFADDRS_H */
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"line %d: ERROR - match localnetwork "
|
||||
"not supported on this platform",
|
||||
count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
#endif /* HAVE_IFADDRS_H */
|
||||
args++;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case MATCH_UNKNOWN:
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"ERROR - Unknown argument '%s' for Match keyword", p);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Unknown argument '%s' for Match keyword. Not matching",
|
||||
p);
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
} while (p != NULL && p[0] != '\0');
|
||||
if (args == 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"ERROR - Match keyword requires an argument");
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"ERROR - Match keyword requires an argument. Not matching");
|
||||
result = 0;
|
||||
}
|
||||
*parsing = result;
|
||||
break;
|
||||
@@ -1427,6 +1440,12 @@ ssh_config_parse_line(ssh_session session,
|
||||
ssh_options_set(session, SSH_OPTIONS_CERTIFICATE, p);
|
||||
}
|
||||
break;
|
||||
case SOC_REQUIRED_RSA_SIZE:
|
||||
l = ssh_config_get_long(&s, -1);
|
||||
if (l >= 0 && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_RSA_MIN_SIZE, &l);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
|
||||
opcode);
|
||||
@@ -1439,6 +1458,32 @@ 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
|
||||
@@ -1448,36 +1493,32 @@ ssh_config_parse_line(ssh_session session,
|
||||
*/
|
||||
int ssh_config_parse_file(ssh_session session, const char *filename)
|
||||
{
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
FILE *f;
|
||||
int parsing, rv;
|
||||
FILE *fp = NULL;
|
||||
int rv;
|
||||
bool global = 0;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == 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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
rv = ssh_config_parse(session, fp, global);
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
fclose(fp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* @brief Parse configuration string and set the options to the given session
|
||||
@@ -1492,7 +1533,8 @@ 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, line_len;
|
||||
unsigned int line_num = 0;
|
||||
size_t line_len;
|
||||
int parsing, rv;
|
||||
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Reading configuration data from string:");
|
||||
@@ -1514,8 +1556,10 @@ 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: %u characters",
|
||||
line_num, line_len);
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Line %u too long: %zu characters",
|
||||
line_num,
|
||||
line_len);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
memcpy(line, line_start, line_len);
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
*/
|
||||
char *ssh_config_get_cmd(char **str)
|
||||
{
|
||||
register char *c;
|
||||
char *r;
|
||||
register char *c = NULL;
|
||||
char *r = NULL;
|
||||
|
||||
/* Ignore leading spaces */
|
||||
for (c = *str; *c; c++) {
|
||||
@@ -67,7 +67,7 @@ out:
|
||||
*/
|
||||
char *ssh_config_get_token(char **str)
|
||||
{
|
||||
register char *c;
|
||||
register char *c = NULL;
|
||||
bool had_equal = false;
|
||||
char *r = NULL;
|
||||
|
||||
@@ -82,6 +82,13 @@ char *ssh_config_get_token(char **str)
|
||||
if (*c == '\"') {
|
||||
for (r = ++c; *c; c++) {
|
||||
if (*c == '\"' || *c == '\n') {
|
||||
if (*c == '\"' && r != c && *(c - 1) == '\\') {
|
||||
/* Escaped quote: Move the remaining one char left */
|
||||
int remaining_len = strlen(c);
|
||||
memmove(c - 1, c, remaining_len);
|
||||
c[remaining_len - 1] = '\0';
|
||||
continue;
|
||||
}
|
||||
*c = '\0';
|
||||
c++;
|
||||
break;
|
||||
@@ -116,7 +123,7 @@ out:
|
||||
|
||||
long ssh_config_get_long(char **str, long notfound)
|
||||
{
|
||||
char *p, *endp;
|
||||
char *p = NULL, *endp = NULL;
|
||||
long i;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
@@ -133,7 +140,7 @@ long ssh_config_get_long(char **str, long notfound)
|
||||
|
||||
const char *ssh_config_get_str_tok(char **str, const char *def)
|
||||
{
|
||||
char *p;
|
||||
char *p = NULL;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
@@ -145,7 +152,7 @@ const char *ssh_config_get_str_tok(char **str, const char *def)
|
||||
|
||||
int ssh_config_get_yesno(char **str, int notfound)
|
||||
{
|
||||
const char *p;
|
||||
const char *p = NULL;
|
||||
|
||||
p = ssh_config_get_str_tok(str, NULL);
|
||||
if (p == NULL) {
|
||||
|
||||
@@ -189,8 +189,8 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
}
|
||||
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
struct addrinfo *bind_ai = NULL;
|
||||
struct addrinfo *bind_itr = NULL;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
@@ -209,7 +209,8 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
bind_itr != NULL;
|
||||
bind_itr = bind_itr->ai_next)
|
||||
{
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
rc = bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s",
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
|
||||
@@ -166,7 +166,7 @@ int ssh_connector_set_out_channel(ssh_connector connector,
|
||||
|
||||
/* Fallback to default value for invalid flags */
|
||||
if (!(flags & SSH_CONNECTOR_STDOUT) && !(flags & SSH_CONNECTOR_STDERR)) {
|
||||
connector->in_flags = SSH_CONNECTOR_STDOUT;
|
||||
connector->out_flags = SSH_CONNECTOR_STDOUT;
|
||||
}
|
||||
|
||||
return ssh_add_channel_callbacks(channel, &connector->out_channel_cb);
|
||||
@@ -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,
|
||||
r - total);
|
||||
(uint32_t)(r - total));
|
||||
} else {
|
||||
w = ssh_channel_write_stderr(connector->out_channel,
|
||||
buffer + total,
|
||||
r - total);
|
||||
(uint32_t)(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,
|
||||
r - total);
|
||||
(uint32_t)(r - total));
|
||||
if (w < 0) {
|
||||
ssh_connector_except(connector, connector->out_fd);
|
||||
return;
|
||||
@@ -340,8 +340,9 @@ 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,
|
||||
r - total);
|
||||
w = ssh_connector_fd_write(connector,
|
||||
buffer + total,
|
||||
(uint32_t)(r - total));
|
||||
if (w < 0) {
|
||||
ssh_connector_except(connector, connector->out_fd);
|
||||
return;
|
||||
@@ -381,15 +382,13 @@ ssh_connector_fd_out_cb(ssh_connector connector)
|
||||
*
|
||||
* @returns 0
|
||||
*/
|
||||
static int ssh_connector_fd_cb(ssh_poll_handle p,
|
||||
static int ssh_connector_fd_cb(UNUSED_PARAM(ssh_poll_handle p),
|
||||
socket_t fd,
|
||||
int revents,
|
||||
void *userdata)
|
||||
{
|
||||
ssh_connector connector = userdata;
|
||||
|
||||
(void)p;
|
||||
|
||||
if (revents & POLLERR) {
|
||||
ssh_connector_except(connector, fd);
|
||||
} else if((revents & (POLLIN|POLLHUP)) && fd == connector->in_fd) {
|
||||
@@ -408,6 +407,10 @@ static int ssh_connector_fd_cb(ssh_poll_handle p,
|
||||
*
|
||||
* @brief Callback called when data is received on channel.
|
||||
*
|
||||
* @param[in] session The SSH session
|
||||
*
|
||||
* @param[in] channel The channel data came from
|
||||
*
|
||||
* @param[in] data Pointer to the data
|
||||
*
|
||||
* @param[in] len Length of data
|
||||
@@ -419,7 +422,7 @@ static int ssh_connector_fd_cb(ssh_poll_handle p,
|
||||
* @returns Amount of data bytes consumed
|
||||
*/
|
||||
static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
ssh_channel channel,
|
||||
UNUSED_PARAM(ssh_channel channel),
|
||||
void *data,
|
||||
uint32_t len,
|
||||
int is_stderr,
|
||||
@@ -429,11 +432,11 @@ static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
int w;
|
||||
uint32_t window;
|
||||
|
||||
(void) session;
|
||||
(void) channel;
|
||||
(void) is_stderr;
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE,"connector data on channel");
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Received data (%" PRIu32 ") on channel (%" PRIu32 ":%" PRIu32 ")",
|
||||
len,
|
||||
channel->local_channel,
|
||||
channel->remote_channel);
|
||||
|
||||
if (is_stderr && !(connector->in_flags & SSH_CONNECTOR_STDERR)) {
|
||||
/* ignore stderr */
|
||||
@@ -447,6 +450,7 @@ static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
}
|
||||
|
||||
if (connector->out_wontblock) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Writing won't block");
|
||||
if (connector->out_channel != NULL) {
|
||||
uint32_t window_len;
|
||||
|
||||
@@ -476,9 +480,11 @@ 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) {
|
||||
w = ssh_connector_fd_write(connector, data, len);
|
||||
if (w < 0)
|
||||
ssize_t ws = ssh_connector_fd_write(connector, data, len);
|
||||
if (ws < 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;
|
||||
@@ -493,6 +499,7 @@ static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
|
||||
return w;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_TRACE, "Writing would block: wait?");
|
||||
connector->in_available = 1;
|
||||
|
||||
return 0;
|
||||
@@ -510,10 +517,11 @@ static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
*
|
||||
* @returns Amount of data bytes consumed
|
||||
*/
|
||||
static int ssh_connector_channel_write_wontblock_cb(ssh_session session,
|
||||
ssh_channel channel,
|
||||
uint32_t bytes,
|
||||
void *userdata)
|
||||
static int
|
||||
ssh_connector_channel_write_wontblock_cb(ssh_session session,
|
||||
UNUSED_PARAM(ssh_channel channel),
|
||||
uint32_t bytes,
|
||||
void *userdata)
|
||||
{
|
||||
ssh_connector connector = userdata;
|
||||
uint8_t buffer[CHUNKSIZE];
|
||||
@@ -521,7 +529,12 @@ static int ssh_connector_channel_write_wontblock_cb(ssh_session session,
|
||||
|
||||
(void) channel;
|
||||
|
||||
SSH_LOG(SSH_LOG_TRACE, "Channel write won't block");
|
||||
SSH_LOG(SSH_LOG_TRACE,
|
||||
"Write won't block (%" PRIu32 ") on channel (%" PRIu32 ":%" PRIu32 ")",
|
||||
bytes,
|
||||
channel->local_channel,
|
||||
channel->remote_channel);
|
||||
|
||||
if (connector->in_available) {
|
||||
if (connector->in_channel != NULL) {
|
||||
uint32_t len = MIN(CHUNKSIZE, bytes);
|
||||
@@ -532,7 +545,7 @@ static int ssh_connector_channel_write_wontblock_cb(ssh_session session,
|
||||
0);
|
||||
if (r == SSH_ERROR) {
|
||||
ssh_connector_except_channel(connector, connector->in_channel);
|
||||
} else if(r == 0 && ssh_channel_is_eof(connector->in_channel)){
|
||||
} else if (r == 0 && ssh_channel_is_eof(connector->in_channel)) {
|
||||
ssh_channel_send_eof(connector->out_channel);
|
||||
} else if (r > 0) {
|
||||
w = ssh_channel_write(connector->out_channel, buffer, r);
|
||||
@@ -603,15 +616,15 @@ int ssh_connector_set_event(ssh_connector connector, ssh_event event)
|
||||
}
|
||||
}
|
||||
if (connector->in_channel != NULL) {
|
||||
rc = ssh_event_add_session(event,
|
||||
ssh_channel_get_session(connector->in_channel));
|
||||
ssh_session session = ssh_channel_get_session(connector->in_channel);
|
||||
rc = ssh_event_add_session(event, session);
|
||||
if (rc != SSH_OK)
|
||||
goto error;
|
||||
if (ssh_channel_poll_timeout(connector->in_channel, 0, 0) > 0){
|
||||
connector->in_available = 1;
|
||||
}
|
||||
}
|
||||
if(connector->out_channel != NULL) {
|
||||
if (connector->out_channel != NULL) {
|
||||
ssh_session session = ssh_channel_get_session(connector->out_channel);
|
||||
|
||||
rc = ssh_event_add_session(event, session);
|
||||
@@ -627,8 +640,9 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_connector_remove_event(ssh_connector connector) {
|
||||
ssh_session session;
|
||||
int ssh_connector_remove_event(ssh_connector connector)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
|
||||
if (connector->in_poll != NULL) {
|
||||
ssh_event_remove_poll(connector->event, connector->in_poll);
|
||||
|
||||
340
src/curve25519.c
340
src/curve25519.c
@@ -26,119 +26,43 @@
|
||||
#include "libssh/curve25519.h"
|
||||
#ifdef HAVE_CURVE25519
|
||||
|
||||
#ifdef WITH_NACL
|
||||
#include "nacl/crypto_scalarmult_curve25519.h"
|
||||
#endif
|
||||
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/bignum.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/bignum.h"
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/ssh2.h"
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static int ssh_curve25519_init(ssh_session session)
|
||||
int ssh_curve25519_create_k(ssh_session session, ssh_curve25519_pubkey k)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
#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
|
||||
|
||||
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;
|
||||
rc = curve25519_do_create_k(session, k);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
@@ -180,193 +104,120 @@ void ssh_client_curve25519_remove_callbacks(ssh_session session)
|
||||
static int ssh_curve25519_build_k(ssh_session session)
|
||||
{
|
||||
ssh_curve25519_pubkey k;
|
||||
int 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;
|
||||
rc = ssh_curve25519_create_k(session, k);
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
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);
|
||||
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 0;
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @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: %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);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -374,7 +225,8 @@ 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;
|
||||
@@ -393,10 +245,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",
|
||||
@@ -405,7 +257,8 @@ 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 */
|
||||
@@ -447,8 +300,7 @@ 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);
|
||||
@@ -509,7 +361,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;
|
||||
}
|
||||
|
||||
|
||||
164
src/curve25519_crypto.c
Normal file
164
src/curve25519_crypto.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* Free any previously allocated privkey */
|
||||
if (session->next_crypto->curve25519_privkey != NULL) {
|
||||
EVP_PKEY_free(session->next_crypto->curve25519_privkey);
|
||||
session->next_crypto->curve25519_privkey = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
73
src/curve25519_fallback.c
Normal file
73
src/curve25519_fallback.c
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
205
src/curve25519_gcrypt.c
Normal file
205
src/curve25519_gcrypt.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* Free any previously allocated privkey */
|
||||
if (session->next_crypto->curve25519_privkey != NULL) {
|
||||
gcry_sexp_release(session->next_crypto->curve25519_privkey);
|
||||
session->next_crypto->curve25519_privkey = NULL;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
189
src/curve25519_mbedcrypto.c
Normal file
189
src/curve25519_mbedcrypto.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
14
src/dh-gex.c
14
src/dh-gex.c
@@ -416,6 +416,9 @@ 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) {
|
||||
@@ -439,6 +442,9 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli,
|
||||
do {
|
||||
firstbyte = getc(moduli);
|
||||
} while(firstbyte != '\n' && firstbyte != EOF);
|
||||
if (firstbyte == EOF) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -571,12 +577,12 @@ error:
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request);
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_init);
|
||||
|
||||
static ssh_packet_callback dhgex_server_callbacks[]= {
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_REQUEST_OLD */
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_GROUP */
|
||||
static ssh_packet_callback dhgex_server_callbacks[] = {
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_REQUEST_OLD */
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_GROUP */
|
||||
ssh_packet_server_dhgex_init, /* SSH_MSG_KEX_DH_GEX_INIT */
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_REPLY */
|
||||
ssh_packet_server_dhgex_request /* SSH_MSG_GEX_DH_GEX_REQUEST */
|
||||
ssh_packet_server_dhgex_request /* SSH_MSG_KEX_DH_GEX_REQUEST */
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -404,9 +404,14 @@ done:
|
||||
*/
|
||||
int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
struct dh_ctx *ctx;
|
||||
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, klen, NULL);
|
||||
*dest = BN_bin2bn(kstring, (int)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 */
|
||||
@@ -444,7 +456,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init)
|
||||
ssh_string q_c_string = NULL;
|
||||
ssh_string q_s_string = NULL;
|
||||
/* SSH host keys (rsa, ed25519 and ecdsa) */
|
||||
ssh_key privkey;
|
||||
ssh_key privkey = NULL;
|
||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -132,9 +139,9 @@ int ecdh_build_k(ssh_session session)
|
||||
#else
|
||||
size_t k_len = 0;
|
||||
enum ssh_key_exchange_e kex_type = session->next_crypto->kex_type;
|
||||
ssh_string s;
|
||||
ssh_string s = NULL;
|
||||
#endif
|
||||
ssh_string pubkey_raw;
|
||||
ssh_string pubkey_raw = NULL;
|
||||
gcry_sexp_t pubkey = NULL;
|
||||
ssh_string privkey = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
@@ -267,12 +274,12 @@ int ecdh_build_k(ssh_session session)
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
gpg_error_t err;
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
ssh_string q_c_string = NULL;
|
||||
ssh_string q_s_string = NULL;
|
||||
gcry_sexp_t param = NULL;
|
||||
gcry_sexp_t key = NULL;
|
||||
/* SSH host keys (rsa, ed25519 and ecdsa) */
|
||||
ssh_key privkey;
|
||||
ssh_key privkey = NULL;
|
||||
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
|
||||
ssh_string sig_blob = NULL;
|
||||
ssh_string pubkey_blob = 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
Normal file
1060
src/external/sntrup761.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ int ssh_gcry_dec2bn(bignum *bn, const char *data) {
|
||||
|
||||
char *ssh_gcry_bn2dec(bignum bn) {
|
||||
bignum bndup, num, ten;
|
||||
char *ret;
|
||||
char *ret = NULL;
|
||||
int count, count2;
|
||||
int size, rsize;
|
||||
char decnum;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user