mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 20:30:38 +09:00
Compare commits
416 Commits
libssh-0.9
...
libssh-0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52986115b8 | ||
|
|
7a49ee5ffc | ||
|
|
c842bc2e8b | ||
|
|
8892577296 | ||
|
|
ac7c64a769 | ||
|
|
47014eb273 | ||
|
|
2223106113 | ||
|
|
4af77362b0 | ||
|
|
f4a0fcc85e | ||
|
|
fa150ef8d2 | ||
|
|
810dbd3db1 | ||
|
|
fa6aa125a2 | ||
|
|
a4948f6212 | ||
|
|
e05e4ae971 | ||
|
|
b6d275537e | ||
|
|
e69fb89e98 | ||
|
|
f9beb3c690 | ||
|
|
bfc39d578d | ||
|
|
0acfd81f85 | ||
|
|
d028b2495d | ||
|
|
68fc17caac | ||
|
|
d327712739 | ||
|
|
fded1fb9eb | ||
|
|
a6e055c42b | ||
|
|
32221ea9fb | ||
|
|
917ba07478 | ||
|
|
bcdbc11732 | ||
|
|
79289dc506 | ||
|
|
45172a70fa | ||
|
|
7b0c80b475 | ||
|
|
d5bc9a1ace | ||
|
|
80d3e10b47 | ||
|
|
455d495c74 | ||
|
|
b1bae1d90f | ||
|
|
ad4f1dbea0 | ||
|
|
5ffe695c3c | ||
|
|
230a437288 | ||
|
|
1df272c3cc | ||
|
|
c3a57fe2dc | ||
|
|
a238df2436 | ||
|
|
f5e8fa5c5f | ||
|
|
0a07266d9c | ||
|
|
953eae880f | ||
|
|
1d5215a5af | ||
|
|
2d06a83b82 | ||
|
|
fd844cac6d | ||
|
|
a106a00e0d | ||
|
|
d8372c3063 | ||
|
|
946210534e | ||
|
|
fe0331cf40 | ||
|
|
709c48eab6 | ||
|
|
3d56bdae37 | ||
|
|
8b4de1c477 | ||
|
|
906f63ba97 | ||
|
|
26ea4f059a | ||
|
|
3b46198c42 | ||
|
|
3de34944ad | ||
|
|
69cb3c5835 | ||
|
|
5102b16cf1 | ||
|
|
dc071dc6cf | ||
|
|
a8d4fbaccb | ||
|
|
56b7d2da4d | ||
|
|
a4b99eedf2 | ||
|
|
8a8498b586 | ||
|
|
44b32e940e | ||
|
|
059079581a | ||
|
|
f11be32e11 | ||
|
|
a9be4ab73e | ||
|
|
273fb4cfc6 | ||
|
|
56f7c27852 | ||
|
|
1285b37b60 | ||
|
|
b7de358cdc | ||
|
|
bea6393de0 | ||
|
|
9158cc524c | ||
|
|
8ba10ef42b | ||
|
|
2ff8a09ee6 | ||
|
|
d52fa9a02c | ||
|
|
ec3fdb434c | ||
|
|
d877969db3 | ||
|
|
b1a7bd21ad | ||
|
|
0831b85002 | ||
|
|
34d1f5e097 | ||
|
|
fcf2cd0d9e | ||
|
|
4a4ca44b19 | ||
|
|
17a6c3f88f | ||
|
|
e24bb932ed | ||
|
|
5c2d444fa8 | ||
|
|
9763563c02 | ||
|
|
5f9d9f4a53 | ||
|
|
e8f3207a0d | ||
|
|
e5cee205c1 | ||
|
|
63056d1bb1 | ||
|
|
09e4f3d331 | ||
|
|
4b886ac656 | ||
|
|
789df0b7d0 | ||
|
|
66a222a73c | ||
|
|
09a7638575 | ||
|
|
203818608a | ||
|
|
f8c452cbef | ||
|
|
adeaa69cc5 | ||
|
|
72bce5ece7 | ||
|
|
7819621fc2 | ||
|
|
fcfba0d8aa | ||
|
|
b166ac4749 | ||
|
|
160a416ef6 | ||
|
|
59071bc4c5 | ||
|
|
2ae63251d3 | ||
|
|
eefae820b5 | ||
|
|
0792fb37b0 | ||
|
|
e23c28a82b | ||
|
|
7291b50420 | ||
|
|
c1d61617fb | ||
|
|
488fb47c32 | ||
|
|
721132696c | ||
|
|
ee034e0484 | ||
|
|
d56c8fdfc6 | ||
|
|
4269b62153 | ||
|
|
c6c63030c5 | ||
|
|
afa5dbb8b1 | ||
|
|
bd7e8295e2 | ||
|
|
933d9c6b07 | ||
|
|
0f0eb05e03 | ||
|
|
171a950a80 | ||
|
|
b1b1da0f97 | ||
|
|
7453038d74 | ||
|
|
29ef92a95e | ||
|
|
6650685758 | ||
|
|
bdca6b7efa | ||
|
|
97b2a61d74 | ||
|
|
781ce47dea | ||
|
|
277ee932d6 | ||
|
|
c91f530610 | ||
|
|
69740ea841 | ||
|
|
1bb7895cd9 | ||
|
|
a028b88aed | ||
|
|
8a25f6bb07 | ||
|
|
2db453db16 | ||
|
|
03134c2932 | ||
|
|
95d0c143b3 | ||
|
|
3dcdafa6d7 | ||
|
|
75c446c529 | ||
|
|
4a9c32fc81 | ||
|
|
1634c5a91a | ||
|
|
dfa7593c27 | ||
|
|
034af66338 | ||
|
|
55c7b93a0a | ||
|
|
4818cf5606 | ||
|
|
316a3a42a4 | ||
|
|
546d9da185 | ||
|
|
3b7d997b54 | ||
|
|
129744692c | ||
|
|
83f6ce0928 | ||
|
|
b5c7f07064 | ||
|
|
223ba36d54 | ||
|
|
9141e9d4fe | ||
|
|
ead42db7c8 | ||
|
|
d5a68bedfd | ||
|
|
4307489702 | ||
|
|
f0da1f2e03 | ||
|
|
50477cb80b | ||
|
|
ded4a81ffe | ||
|
|
c2bc4e62dd | ||
|
|
f7ab481b22 | ||
|
|
628b529a91 | ||
|
|
7e25963130 | ||
|
|
91d8f1a256 | ||
|
|
61dcc023b0 | ||
|
|
4468a78ee2 | ||
|
|
8f18063b6d | ||
|
|
a167faee3e | ||
|
|
0e8f6aaee5 | ||
|
|
f0a1b94d0d | ||
|
|
5d1ddf5920 | ||
|
|
152ae623c2 | ||
|
|
e7bd9d02bc | ||
|
|
9196639940 | ||
|
|
786d7e39a3 | ||
|
|
c33710d112 | ||
|
|
a14a80f35f | ||
|
|
0389ff6d9d | ||
|
|
8954fccfdb | ||
|
|
332df98fc9 | ||
|
|
d4cc3f69c6 | ||
|
|
534c58c475 | ||
|
|
84fd910423 | ||
|
|
d51f77c2b1 | ||
|
|
47376cbc77 | ||
|
|
85c3db3e89 | ||
|
|
3f8a522c7f | ||
|
|
eb08802b7c | ||
|
|
dc587045bf | ||
|
|
9b495b72c5 | ||
|
|
2ce6c56609 | ||
|
|
9caef95899 | ||
|
|
66c2630aaf | ||
|
|
b8f63ee2df | ||
|
|
68adb49996 | ||
|
|
12e94bfd18 | ||
|
|
4fc3d7a27f | ||
|
|
466bb332c1 | ||
|
|
ff25b45367 | ||
|
|
df83f4fb57 | ||
|
|
5bda3ab9f6 | ||
|
|
9a057159a2 | ||
|
|
9c0875dd5d | ||
|
|
1fa5a2a504 | ||
|
|
a08a2f52fb | ||
|
|
21d37f8605 | ||
|
|
e43586b4de | ||
|
|
dc7e1bdb39 | ||
|
|
03d559b066 | ||
|
|
3191c1f6be | ||
|
|
d46f01cb7c | ||
|
|
04e290a19b | ||
|
|
bad407f5e2 | ||
|
|
2787756efe | ||
|
|
7b35afdf6b | ||
|
|
dba2903e38 | ||
|
|
965014b035 | ||
|
|
c4ec92f375 | ||
|
|
54cf9d1364 | ||
|
|
23ce6d7156 | ||
|
|
07473976e1 | ||
|
|
51063fe07e | ||
|
|
9cc1af1d53 | ||
|
|
8a83bc0569 | ||
|
|
0181f5b5ed | ||
|
|
eaae8ce086 | ||
|
|
0b2072dd30 | ||
|
|
2e77cf6b34 | ||
|
|
ad3c052e1c | ||
|
|
57d9d97866 | ||
|
|
22747c862a | ||
|
|
fed755eee5 | ||
|
|
804410f8ad | ||
|
|
df57a9a81d | ||
|
|
97076780a5 | ||
|
|
899553f9f7 | ||
|
|
2edff5e69e | ||
|
|
37f451171b | ||
|
|
2efc1721d8 | ||
|
|
e9613e6b52 | ||
|
|
73fbe68ccd | ||
|
|
0cb282df99 | ||
|
|
fdb0c0a29b | ||
|
|
2e56db3b2f | ||
|
|
4eb759bf40 | ||
|
|
c3987a9796 | ||
|
|
a070c942e7 | ||
|
|
113b1872cf | ||
|
|
c7dc2937fc | ||
|
|
075895da40 | ||
|
|
7930086a37 | ||
|
|
3f376f848d | ||
|
|
3cee61a65b | ||
|
|
90321f732e | ||
|
|
c6140b1a4c | ||
|
|
9290d89570 | ||
|
|
da9ab71f88 | ||
|
|
53dfee98d2 | ||
|
|
bb14611f86 | ||
|
|
b1aca92268 | ||
|
|
2b524655ae | ||
|
|
b51594c34a | ||
|
|
b409b7d092 | ||
|
|
4256936fed | ||
|
|
fdb6dc7069 | ||
|
|
6291900234 | ||
|
|
216bd2abd8 | ||
|
|
574f279f00 | ||
|
|
d886870bbf | ||
|
|
f56c93cccd | ||
|
|
bbd17bc97a | ||
|
|
26fa923b55 | ||
|
|
177a082974 | ||
|
|
ce3ee332d4 | ||
|
|
eb95f8fa85 | ||
|
|
8d3db75724 | ||
|
|
e1fbc02209 | ||
|
|
766041d956 | ||
|
|
f880a7728f | ||
|
|
013203301f | ||
|
|
bfb60befa7 | ||
|
|
4d34890624 | ||
|
|
6751c0e2c3 | ||
|
|
a641b6ea79 | ||
|
|
fa3c73016d | ||
|
|
ffabd8c6ed | ||
|
|
219a311925 | ||
|
|
8e3af4d859 | ||
|
|
9fa614a36d | ||
|
|
3d207f72a0 | ||
|
|
f53d2f7511 | ||
|
|
b853d99546 | ||
|
|
a09976e3d6 | ||
|
|
1ba0432524 | ||
|
|
7dcd749ee1 | ||
|
|
30368fb06a | ||
|
|
fd6b7db1ce | ||
|
|
53514b2a40 | ||
|
|
0e20418296 | ||
|
|
92b59ace9e | ||
|
|
af7b5b78ee | ||
|
|
2b67e2d54c | ||
|
|
f44994f1e6 | ||
|
|
97d6eb84a4 | ||
|
|
33f2211cae | ||
|
|
03aff19b80 | ||
|
|
cf660fe27c | ||
|
|
f9d60e1360 | ||
|
|
1098280e43 | ||
|
|
62301834f4 | ||
|
|
3e0ac84001 | ||
|
|
4d26e08789 | ||
|
|
3c4403c400 | ||
|
|
8dcde7a74f | ||
|
|
bb7cd8e22b | ||
|
|
7458e95ee5 | ||
|
|
2f69c5f022 | ||
|
|
efdd567a1b | ||
|
|
cff8f7c0b5 | ||
|
|
fe4a4b1b79 | ||
|
|
8caf653e97 | ||
|
|
88c4d532ab | ||
|
|
e69d063252 | ||
|
|
a35218da74 | ||
|
|
4d8e2cdc8b | ||
|
|
3d0f2977bf | ||
|
|
230929a4b2 | ||
|
|
c847216ca4 | ||
|
|
cacd2fa999 | ||
|
|
0b688e4829 | ||
|
|
27cf0ea06b | ||
|
|
e473108e1b | ||
|
|
c74cc9a606 | ||
|
|
619e60cf0e | ||
|
|
37b3657481 | ||
|
|
c1211a4e1a | ||
|
|
95d34b5937 | ||
|
|
6dc3f666c5 | ||
|
|
8e4491a532 | ||
|
|
492095b2a7 | ||
|
|
d516642980 | ||
|
|
193845ecdd | ||
|
|
598d04d5d9 | ||
|
|
06c5dd9c84 | ||
|
|
6632659907 | ||
|
|
86bf835d50 | ||
|
|
c9d0362a6b | ||
|
|
d2989f28db | ||
|
|
0bab6013d0 | ||
|
|
361d93586c | ||
|
|
0db13661b4 | ||
|
|
c866592d7d | ||
|
|
eb90325bed | ||
|
|
c878545977 | ||
|
|
741021513b | ||
|
|
97e8aba080 | ||
|
|
802d46d040 | ||
|
|
96718df15e | ||
|
|
89bd779e78 | ||
|
|
b5af3e74d7 | ||
|
|
2d3932d988 | ||
|
|
d0c1583ad2 | ||
|
|
59ff4064ba | ||
|
|
00a68c985f | ||
|
|
e862ea556c | ||
|
|
a4704cba0b | ||
|
|
455b3a7865 | ||
|
|
fabaab1540 | ||
|
|
8ac49ff181 | ||
|
|
cdf55a18d2 | ||
|
|
d158ca7101 | ||
|
|
664b7ebfa1 | ||
|
|
163c488e30 | ||
|
|
4b5bfa7a9d | ||
|
|
decbadda45 | ||
|
|
f00d780c16 | ||
|
|
1daa2e4609 | ||
|
|
d84bc3ad8e | ||
|
|
a9350e3205 | ||
|
|
95e3a7e7a3 | ||
|
|
e4cecee7d3 | ||
|
|
8b867b41d3 | ||
|
|
c6bd2fe734 | ||
|
|
d7e52b99bd | ||
|
|
a640d9472a | ||
|
|
b15103ef4e | ||
|
|
95071cd1fe | ||
|
|
18a888f9fb | ||
|
|
bbfc41948a | ||
|
|
c29a8cc084 | ||
|
|
54e7af83e6 | ||
|
|
3483d6327d | ||
|
|
5869345899 | ||
|
|
0cad2778b4 | ||
|
|
24de1fbde8 | ||
|
|
131728a680 | ||
|
|
e949e135b6 | ||
|
|
1510b63d20 | ||
|
|
0db4d9bd46 | ||
|
|
1e17e084bf | ||
|
|
a2c14c5ec5 | ||
|
|
b99849c831 | ||
|
|
c7d4286ca1 | ||
|
|
434e2b7212 | ||
|
|
acf0f0fa6e | ||
|
|
220e6b66e8 | ||
|
|
c4d4731ddf | ||
|
|
139ccaa78c | ||
|
|
c42410b560 | ||
|
|
120f11812d | ||
|
|
500486d501 | ||
|
|
6708debd4c | ||
|
|
852a8b4875 | ||
|
|
9c6b4ecb48 |
411
.gitlab-ci.yml
411
.gitlab-ci.yml
@@ -6,16 +6,13 @@ variables:
|
||||
MINGW_BUILD: buildenv-mingw
|
||||
DEBIAN_CROSS_BUILD: buildenv-debian-cross
|
||||
|
||||
# pkd tests fail on CentOS7 docker images, so we don't use -DSERVER_TESTING=ON
|
||||
centos7/openssl_1.0.x/x86_64:
|
||||
# torture_auth fails on centos7 docker images, so we don't use -DCLIENT_TESTING=ON
|
||||
centos7/openssl_1.0.x/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake3
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
- mkdir -p obj && cd obj && cmake3 -DUNIT_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
|
||||
-DWITH_PCAP=ON .. && make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
@@ -26,15 +23,12 @@ centos7/openssl_1.0.x/x86_64:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/openssl_1.1.x/x86_64:
|
||||
fedora/openssl_1.1.x/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_BLOWFISH_CIPHER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
@@ -47,37 +41,13 @@ fedora/openssl_1.1.x/x86_64:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/openssl_1.1.x/x86_64/fips:
|
||||
fedora/openssl_1.1.x/x86-64/release:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- echo 1 > /etc/system-fips
|
||||
- update-crypto-policies --set FIPS
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Release
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-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
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/openssl_1.1.x/x86_64/minimal:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_ZLIB=OFF -DWITH_PCAP=OFF
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DWITH_GEX=OFF .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
@@ -97,8 +67,7 @@ fedora/address-sanitizer:
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=AddressSanitizer
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
@@ -111,35 +80,12 @@ fedora/address-sanitizer:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
# This is disabled as it report OpenSSL issues
|
||||
# It also has ethe same issues with cwrap as AddressSanitizer
|
||||
.fedora/memory-sanitizer:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=MemorySanitizer
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON ..
|
||||
&& make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/undefined-sanitizer:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=UndefinedSanitizer
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
|
||||
&& make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
@@ -152,27 +98,16 @@ fedora/undefined-sanitizer:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/csbuild:
|
||||
fedora/static-analysis:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- |
|
||||
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")
|
||||
|
||||
export CI_COMMIT_RANGE="$CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA"
|
||||
|
||||
- csbuild
|
||||
--build-dir=obj-csbuild
|
||||
--prep-cmd="rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@"
|
||||
--build-cmd "make clean && make -j$(nproc)"
|
||||
--git-commit-range $CI_COMMIT_RANGE
|
||||
--color
|
||||
--print-current --print-fixed
|
||||
- export CCC_CC=clang
|
||||
- export CCC_CXX=clang++
|
||||
- mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. &&
|
||||
scan-build --status-bugs -o scan make -j$(nproc)
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
@@ -181,17 +116,16 @@ fedora/csbuild:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj-csbuild/
|
||||
- obj/scan
|
||||
|
||||
# That is a specific runner that we cannot enable universally.
|
||||
# We restrict it to builds under the $BUILD_IMAGES_PROJECT project.
|
||||
freebsd/x86_64:
|
||||
freebsd/x86-64:
|
||||
image:
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make && ctest --output-on-failure
|
||||
tags:
|
||||
@@ -207,13 +141,11 @@ freebsd/x86_64:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/libgcrypt/x86_64:
|
||||
fedora/libgcrypt/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DWITH_GCRYPT=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
@@ -227,14 +159,13 @@ fedora/libgcrypt/x86_64:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
fedora/mbedtls/x86_64:
|
||||
fedora/mbedtls/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_MBEDTLS=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
@@ -247,89 +178,13 @@ fedora/mbedtls/x86_64:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||
# for MinGW
|
||||
fedora/mingw64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
||||
script:
|
||||
- export WINEPATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
|
||||
- export WINEDEBUG=-all
|
||||
- mkdir -p obj && cd obj && mingw64-cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||
# for MinGW
|
||||
fedora/mingw32:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
||||
script:
|
||||
- export WINEPATH=/usr/i686-w64-mingw32/sys-root/mingw/bin
|
||||
- export WINEDEBUG=-all
|
||||
- mkdir -p obj && cd obj && mingw32-cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
.Debian.cross.template: &Debian_cross_template
|
||||
stage: test
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$DEBIAN_CROSS_BUILD
|
||||
script:
|
||||
- build=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
- host="${CI_JOB_NAME#*.cross.}"
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_C_COMPILER="$(which $host-gcc)"
|
||||
-DCMAKE_CXX_COMPILER="$(which $host-g++)"
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DUNIT_TESTING=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
|
||||
-DWITH_PCAP=ON .. &&
|
||||
make -j$(nproc) &&
|
||||
ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
.Debian.cross.mips-linux-gnu:
|
||||
<<: *Debian_cross_template
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86_64/gcc:
|
||||
tumbleweed/openssl_1.1.x/x86-64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
@@ -342,77 +197,13 @@ tumbleweed/openssl_1.1.x/x86_64/gcc:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86/gcc:
|
||||
tumbleweed/openssl_1.1.x/x86-64/release:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-m32.cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86_64/gcc7:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_BUILD_TYPE=Release
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86/gcc7:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-m32.cmake
|
||||
-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86_64/clang:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
@@ -439,15 +230,32 @@ tumbleweed/docs:
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/openssl_1.1.x/x86:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-m32.cmake
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
tumbleweed/undefined-sanitizer:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
|
||||
script:
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_BUILD_TYPE=UndefinedSanitizer
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
make -j$(nproc) && ctest --output-on-failure
|
||||
-DCMAKE_C_FLAGS="-fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
|
||||
&& make -j$(nproc) && ctest --output-on-failure
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
@@ -463,12 +271,10 @@ tumbleweed/static-analysis:
|
||||
script:
|
||||
- export CCC_CC=clang
|
||||
- export CCC_CXX=clang++
|
||||
- mkdir -p obj && cd obj && scan-build cmake
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
|
||||
- mkdir -p obj && cd obj && scan-build cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
|
||||
-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang .. &&
|
||||
scan-build --status-bugs -o scan make -j$(nproc)
|
||||
tags:
|
||||
- shared
|
||||
@@ -480,57 +286,76 @@ tumbleweed/static-analysis:
|
||||
paths:
|
||||
- obj/scan
|
||||
|
||||
visualstudio/x86_64:
|
||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||
# for MinGW
|
||||
mingw64:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
||||
script:
|
||||
- $env:VCPKG_DEFAULT_TRIPLET="x64-windows"
|
||||
- cd obj
|
||||
- cmake
|
||||
-A x64
|
||||
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_TOOLCHAIN_FILE"
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON ..
|
||||
- cmake --build .
|
||||
- Xvfb :1 -screen 0 1024x768x16 -ac +extension GLX +render -noreset -nolisten tcp &
|
||||
- export DISPLAY=:1
|
||||
- mkdir -p obj && cd obj && mingw64-cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc)
|
||||
- export WINEPATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
|
||||
- ctest --output-on-failure
|
||||
tags:
|
||||
- vs2017
|
||||
- windows
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
only:
|
||||
- branches@libssh/libssh-mirror
|
||||
- branches@ansasaki/libssh-mirror
|
||||
- branches@cryptomilk/libssh-mirror
|
||||
- branches@jjelen/libssh-mirror
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
visualstudio/x86:
|
||||
# Unit testing only, no client and pkd testing, because cwrap is not available
|
||||
# for MinGW
|
||||
mingw32:
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$MINGW_BUILD
|
||||
script:
|
||||
- $env:VCPKG_DEFAULT_TRIPLET="x86-windows"
|
||||
- cd obj
|
||||
- cmake
|
||||
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_TOOLCHAIN_FILE"
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
|
||||
-DUNIT_TESTING=ON ..
|
||||
- cmake --build .
|
||||
- Xvfb :1 -screen 0 1024x768x16 -ac +extension GLX +render -noreset -nolisten tcp &
|
||||
- export DISPLAY=:1
|
||||
- mkdir -p obj && cd obj && mingw32-cmake -DCMAKE_BUILD_TYPE=Debug
|
||||
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON --DWITH_PCAP=ON
|
||||
-DPICKY_DEVELOPER=ON
|
||||
-DUNIT_TESTING=ON .. &&
|
||||
make -j$(nproc)
|
||||
- export WINEPATH=/usr/i686-w64-mingw32/sys-root/mingw/bin
|
||||
- ctest --output-on-failure
|
||||
tags:
|
||||
- vs2017
|
||||
- windows
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
only:
|
||||
- branches@libssh/libssh-mirror
|
||||
- branches@ansasaki/libssh-mirror
|
||||
- branches@cryptomilk/libssh-mirror
|
||||
- branches@jjelen/libssh-mirror
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
.Debian.cross.template: &Debian_cross_template
|
||||
stage: test
|
||||
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$DEBIAN_CROSS_BUILD
|
||||
script:
|
||||
- build=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
- host="${CI_JOB_NAME#*.cross.}"
|
||||
- mkdir -p obj && cd obj && cmake
|
||||
-DCMAKE_C_COMPILER="$(which $host-gcc)"
|
||||
-DCMAKE_CXX_COMPILER="$(which $host-g++)"
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DUNIT_TESTING=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
|
||||
-DWITH_PCAP=ON .. && make -j$(nproc)
|
||||
- ctest --output-on-failure -j$(nproc)
|
||||
tags:
|
||||
- shared
|
||||
except:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
when: on_failure
|
||||
paths:
|
||||
- obj/
|
||||
|
||||
.Debian.cross.mips-linux-gnu:
|
||||
<<: *Debian_cross_template
|
||||
|
||||
@@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
||||
include(DefineCMakeDefaults)
|
||||
include(DefineCompilerFlags)
|
||||
|
||||
project(libssh VERSION 0.9.0 LANGUAGES C)
|
||||
project(libssh VERSION 0.8.7 LANGUAGES C)
|
||||
|
||||
# global needed variable
|
||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
@@ -22,7 +22,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
|
||||
# Increment AGE. Set REVISION to 0
|
||||
# If the source code was changed, but there were no interface changes:
|
||||
# Increment REVISION.
|
||||
set(LIBRARY_VERSION "4.8.1")
|
||||
set(LIBRARY_VERSION "4.7.4")
|
||||
set(LIBRARY_SOVERSION "4")
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
@@ -70,10 +70,6 @@ else (WITH_GCRYPT)
|
||||
endif (NOT OPENSSL_FOUND)
|
||||
endif(WITH_GCRYPT)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
find_package(CMocka REQUIRED)
|
||||
endif ()
|
||||
|
||||
# Find out if we have threading available
|
||||
set(CMAKE_THREAD_PREFER_PTHREADS ON)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
@@ -154,8 +150,9 @@ if (WITH_EXAMPLES)
|
||||
endif (WITH_EXAMPLES)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
include(AddCMockaTest)
|
||||
add_subdirectory(tests)
|
||||
find_package(CMocka REQUIRED)
|
||||
include(AddCMockaTest)
|
||||
add_subdirectory(tests)
|
||||
endif (UNIT_TESTING)
|
||||
|
||||
### SOURCE PACKAGE
|
||||
@@ -223,12 +220,10 @@ message(STATUS "libnacl support: ${WITH_NACL}")
|
||||
message(STATUS "SFTP support: ${WITH_SFTP}")
|
||||
message(STATUS "Server support : ${WITH_SERVER}")
|
||||
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
|
||||
message(STATUS "GEX support : ${WITH_GEX}")
|
||||
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
|
||||
message(STATUS "With static library: ${WITH_STATIC_LIB}")
|
||||
message(STATUS "Unit testing: ${UNIT_TESTING}")
|
||||
message(STATUS "Client code testing: ${CLIENT_TESTING}")
|
||||
message(STATUS "Blowfish cipher support: ${WITH_BLOWFISH_CIPHER}")
|
||||
set(_SERVER_TESTING OFF)
|
||||
if (WITH_SERVER)
|
||||
set(_SERVER_TESTING ${SERVER_TESTING})
|
||||
@@ -243,9 +238,5 @@ message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
|
||||
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
|
||||
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
|
||||
message(STATUS "Release is final: ${WITH_FINAL}")
|
||||
message(STATUS "Global client config: ${GLOBAL_CLIENT_CONFIG}")
|
||||
if (WITH_SERVER)
|
||||
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
|
||||
endif()
|
||||
message(STATUS "********************************************")
|
||||
|
||||
|
||||
15
ChangeLog
15
ChangeLog
@@ -1,21 +1,6 @@
|
||||
ChangeLog
|
||||
==========
|
||||
|
||||
version 0.9.0 (released 2019-06-28)
|
||||
* Added support for AES-GCM
|
||||
* Added improved rekeying support
|
||||
* Added performance improvements
|
||||
* Disabled blowfish support by default
|
||||
* Fixed several ssh config parsing issues
|
||||
* Added support for DH Group Exchange KEX
|
||||
* Added support for Encrypt-then-MAC mode
|
||||
* Added support for parsing server side configuration file
|
||||
* Added support for ECDSA/Ed25519 certificates
|
||||
* Added FIPS 140-2 compatibility
|
||||
* Improved known_hosts parsing
|
||||
* Improved documentation
|
||||
* Improved OpenSSL API usage for KEX, DH, and signatures
|
||||
|
||||
version 0.8.7 (released 2019-02-25)
|
||||
* Fixed handling extension flags in the server implementation
|
||||
* Fixed exporting ed25519 private keys
|
||||
|
||||
@@ -41,7 +41,6 @@ if (UNIX)
|
||||
add_c_compiler_flag("-Werror=strict-overflow" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wstrict-overflow=2" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wno-format-zero-length" SUPPORTED_COMPILER_FLAGS)
|
||||
add_c_compiler_flag("-Wmissing-field-initializers" SUPPORTED_COMPILER_FLAGS)
|
||||
|
||||
check_c_compiler_flag("-Wformat" REQUIRED_FLAGS_WFORMAT)
|
||||
if (REQUIRED_FLAGS_WFORMAT)
|
||||
@@ -52,10 +51,7 @@ if (UNIX)
|
||||
add_c_compiler_flag("-Werror=format-security" SUPPORTED_COMPILER_FLAGS)
|
||||
|
||||
# Allow zero for a variadic macro argument
|
||||
string(TOLOWER "${CMAKE_C_COMPILER_ID}" _C_COMPILER_ID)
|
||||
if ("${_C_COMPILER_ID}" STREQUAL "clang")
|
||||
add_c_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments" SUPPORTED_COMPILER_FLAGS)
|
||||
endif()
|
||||
add_c_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments" SUPPORTED_COMPILER_FLAGS)
|
||||
|
||||
add_c_compiler_flag("-fno-common" SUPPORTED_COMPILER_FLAGS)
|
||||
|
||||
@@ -69,18 +65,10 @@ if (UNIX)
|
||||
check_c_compiler_flag_ssp("-fstack-protector-strong" WITH_STACK_PROTECTOR_STRONG)
|
||||
if (WITH_STACK_PROTECTOR_STRONG)
|
||||
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector-strong")
|
||||
# This is needed as Solaris has a seperate libssp
|
||||
if (SOLARIS)
|
||||
list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector-strong")
|
||||
endif()
|
||||
else (WITH_STACK_PROTECTOR_STRONG)
|
||||
check_c_compiler_flag_ssp("-fstack-protector" WITH_STACK_PROTECTOR)
|
||||
if (WITH_STACK_PROTECTOR)
|
||||
list(APPEND SUPPORTED_COMPILER_FLAGS "-fstack-protector")
|
||||
# This is needed as Solaris has a seperate libssp
|
||||
if (SOLARIS)
|
||||
list(APPEND SUPPORTED_LINKER_FLAGS "-fstack-protector")
|
||||
endif()
|
||||
endif()
|
||||
endif (WITH_STACK_PROTECTOR_STRONG)
|
||||
|
||||
@@ -94,8 +82,6 @@ if (UNIX)
|
||||
add_c_compiler_flag("-Wno-error=tautological-compare" SUPPORTED_COMPILER_FLAGS)
|
||||
endif()
|
||||
|
||||
add_c_compiler_flag("-Wno-deprecated-declarations" DEPRECATION_COMPILER_FLAGS)
|
||||
|
||||
# Unset CMAKE_REQUIRED_FLAGS
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
endif()
|
||||
@@ -114,8 +100,3 @@ if (OSX)
|
||||
endif()
|
||||
|
||||
set(DEFAULT_C_COMPILE_FLAGS ${SUPPORTED_COMPILER_FLAGS} CACHE INTERNAL "Default C Compiler Flags" FORCE)
|
||||
set(DEFAULT_LINK_FLAGS ${SUPPORTED_LINKER_FLAGS} CACHE INTERNAL "Default C Linker Flags" FORCE)
|
||||
|
||||
if (DEPRECATION_COMPILER_FLAGS)
|
||||
set(DEFAULT_C_NO_DEPRECATION_FLAGS ${DEPRECATION_COMPILER_FLAGS} CACHE INTERNAL "Default no deprecation flags" FORCE)
|
||||
endif()
|
||||
|
||||
@@ -64,7 +64,6 @@ check_include_file(sys/param.h HAVE_SYS_PARAM_H)
|
||||
check_include_file(arpa/inet.h HAVE_ARPA_INET_H)
|
||||
check_include_file(byteswap.h HAVE_BYTESWAP_H)
|
||||
check_include_file(glob.h HAVE_GLOB_H)
|
||||
check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H)
|
||||
|
||||
if (WIN32)
|
||||
check_include_file(io.h HAVE_IO_H)
|
||||
@@ -89,10 +88,8 @@ if (OPENSSL_FOUND)
|
||||
message(FATAL_ERROR "Could not detect openssl/aes.h")
|
||||
endif()
|
||||
|
||||
if (WITH_BLOWFISH_CIPHER)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
check_include_file(openssl/ecdh.h HAVE_OPENSSL_ECDH_H)
|
||||
@@ -111,10 +108,6 @@ if (OPENSSL_FOUND)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_aes_128_cbc HAVE_OPENSSL_EVP_AES_CBC)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_aes_128_gcm HAVE_OPENSSL_EVP_AES_GCM)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(CRYPTO_THREADID_set_callback HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK)
|
||||
@@ -127,16 +120,10 @@ if (OPENSSL_FOUND)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_CIPHER_CTX_new HAVE_OPENSSL_EVP_CIPHER_CTX_NEW)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(EVP_KDF_CTX_new_id HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID)
|
||||
|
||||
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
|
||||
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
|
||||
|
||||
check_function_exists(OPENSSL_ia32cap_loc HAVE_OPENSSL_IA32CAP_LOC)
|
||||
|
||||
unset(CMAKE_REQUIRED_INCLUDES)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif()
|
||||
@@ -267,14 +254,6 @@ if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(HAVE_PTHREAD 1)
|
||||
endif (CMAKE_USE_PTHREADS_INIT)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
if (CMOCKA_FOUND)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMOCKA_LIBRARIES})
|
||||
check_function_exists(cmocka_set_test_filter HAVE_CMOCKA_SET_TEST_FILTER)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# OPTIONS
|
||||
check_c_source_compiles("
|
||||
__thread int tls;
|
||||
@@ -293,19 +272,19 @@ int main(void) {
|
||||
###########################################################
|
||||
# For detecting attributes we need to treat warnings as
|
||||
# errors
|
||||
if (UNIX OR MINGW)
|
||||
if (UNIX)
|
||||
# Get warnings for attributs
|
||||
check_c_compiler_flag("-Wattributes" REQUIRED_FLAGS_WERROR)
|
||||
check_c_compiler_flag("-Wattributs" REQUIRED_FLAGS_WERROR)
|
||||
if (REQUIRED_FLAGS_WERROR)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS "-Wattributes ")
|
||||
set(CMAKE_REQUIRED_FLAGS "-Wattributes")
|
||||
endif()
|
||||
|
||||
# Turn warnings into errors
|
||||
check_c_compiler_flag("-Werror" REQUIRED_FLAGS_WERROR)
|
||||
if (REQUIRED_FLAGS_WERROR)
|
||||
string(APPEND CMAKE_REQUIRED_FLAGS "-Werror ")
|
||||
set(CMAKE_REQUIRED_FLAGS "-Werror")
|
||||
endif()
|
||||
endif ()
|
||||
endif (UNIX)
|
||||
|
||||
check_c_source_compiles("
|
||||
void test_constructor_attribute(void) __attribute__ ((constructor));
|
||||
@@ -349,28 +328,6 @@ int main(void) {
|
||||
return 0;
|
||||
}" HAVE_FALLTHROUGH_ATTRIBUTE)
|
||||
|
||||
if (NOT WIN32)
|
||||
check_c_source_compiles("
|
||||
#define __unused __attribute__((unused))
|
||||
|
||||
static int do_nothing(int i __unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = do_nothing(5);
|
||||
if (i > 5) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}" HAVE_UNUSED_ATTRIBUTE)
|
||||
endif()
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <string.h>
|
||||
|
||||
@@ -383,6 +340,18 @@ int main(void)
|
||||
return 0;
|
||||
}" HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <stdio.h>
|
||||
#define __VA_NARG__(...) (__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) - 1)
|
||||
#define __VA_NARG_(...) __VA_ARG_N(__VA_ARGS__)
|
||||
#define __VA_ARG_N( _1, _2, _3, _4, _5, _6, _7, _8, _9,_10,N,...) N
|
||||
#define __RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define myprintf(format, ...) printf((format), __VA_NARG__(__VA_ARGS__), __VA_ARGS__)
|
||||
int main(void) {
|
||||
myprintf(\"%d %d %d %d\",1,2,3);
|
||||
return 0;
|
||||
}" HAVE_GCC_NARG_MACRO)
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <stdio.h>
|
||||
int main(void) {
|
||||
@@ -397,8 +366,6 @@ int main(void) {
|
||||
return 0;
|
||||
}" HAVE_COMPILER__FUNCTION__)
|
||||
|
||||
# This is only available with OpenBSD's gcc implementation */
|
||||
if (OPENBSD)
|
||||
check_c_source_compiles("
|
||||
#define ARRAY_LEN 16
|
||||
void test_attr(const unsigned char *k)
|
||||
@@ -407,7 +374,6 @@ void test_attr(const unsigned char *k)
|
||||
int main(void) {
|
||||
return 0;
|
||||
}" HAVE_GCC_BOUNDED_ATTRIBUTE)
|
||||
endif(OPENBSD)
|
||||
|
||||
# Stop treating warnings as errors
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
|
||||
@@ -8,7 +8,6 @@ option(WITH_DEBUG_PACKET "Build with packet debug output" OFF)
|
||||
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
|
||||
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
|
||||
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
|
||||
option(WITH_BLOWFISH_CIPHER "Compile with blowfish support" OFF)
|
||||
option(WITH_PCAP "Compile with Pcap generation support" ON)
|
||||
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
|
||||
option(UNIT_TESTING "Build with unit tests" OFF)
|
||||
@@ -19,7 +18,6 @@ option(WITH_EXAMPLES "Build examples" ON)
|
||||
option(WITH_NACL "Build with libnacl (curve25519)" ON)
|
||||
option(WITH_SYMBOL_VERSIONING "Build with symbol versioning" ON)
|
||||
option(WITH_ABI_BREAK "Allow ABI break" OFF)
|
||||
option(WITH_GEX "Enable DH Group exchange mechanisms" ON)
|
||||
option(FUZZ_TESTING "Build with fuzzer for the server" OFF)
|
||||
option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
|
||||
|
||||
@@ -49,11 +47,3 @@ endif (WITH_NACL)
|
||||
if (WITH_ABI_BREAK)
|
||||
set(WITH_SYMBOL_VERSIONING ON)
|
||||
endif (WITH_ABI_BREAK)
|
||||
|
||||
if (NOT GLOBAL_BIND_CONFIG)
|
||||
set(GLOBAL_BIND_CONFIG "/etc/ssh/libssh_server_config")
|
||||
endif (NOT GLOBAL_BIND_CONFIG)
|
||||
|
||||
if (NOT GLOBAL_CLIENT_CONFIG)
|
||||
set(GLOBAL_CLIENT_CONFIG "/etc/ssh/ssh_config")
|
||||
endif (NOT GLOBAL_CLIENT_CONFIG)
|
||||
|
||||
11
INSTALL
11
INSTALL
@@ -11,10 +11,9 @@ In order to build libssh, you need to install several components:
|
||||
- [openssl](http://www.openssl.org) >= 0.9.8
|
||||
or
|
||||
- [gcrypt](http://www.gnu.org/directory/Security/libgcrypt.html) >= 1.4
|
||||
- [libz](http://www.zlib.net) >= 1.2
|
||||
|
||||
optional:
|
||||
- [cmocka](https://cmocka.org/) >= 1.1.0
|
||||
- [libz](http://www.zlib.net) >= 1.2
|
||||
- [socket_wrapper](https://cwrap.org/) >= 1.1.5
|
||||
- [nss_wrapper](https://cwrap.org/) >= 1.1.2
|
||||
- [uid_wrapper](https://cwrap.org/) >= 1.2.0
|
||||
@@ -23,12 +22,12 @@ optional:
|
||||
Note that these version numbers are version we know works correctly. If you
|
||||
build and run libssh successfully with an older version, please let us know.
|
||||
|
||||
For Windows use vcpkg:
|
||||
Windows binaries known to be working:
|
||||
|
||||
https://github.com/Microsoft/vcpkg
|
||||
- http://www.slproweb.com/products/Win32OpenSSL.html
|
||||
- http://zlib.net/ -> zlib compiled DLL
|
||||
|
||||
which you can use to install openssl and zlib. libssh itself is also part of
|
||||
vcpkg!
|
||||
We installed them in C:\Program Files
|
||||
|
||||
## Building
|
||||
First, you need to configure the compilation, using CMake. Go inside the
|
||||
|
||||
@@ -1,63 +1,11 @@
|
||||
#
|
||||
# - add_cmocka_test(test_name test_source linklib1 ... linklibN)
|
||||
|
||||
# Copyright (c) 2007 Daniel Gollub <dgollub@suse.de>
|
||||
# Copyright (c) 2007-2018 Andreas Schneider <asn@cryptomilk.org>
|
||||
# Copyright (c) 2018 Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
#.rst:
|
||||
# AddCMockaTest
|
||||
# -------------
|
||||
#
|
||||
# This file provides a function to add a test
|
||||
#
|
||||
# Functions provided
|
||||
# ------------------
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# add_cmocka_test(target_name
|
||||
# SOURCES src1 src2 ... srcN
|
||||
# [COMPILE_OPTIONS opt1 opt2 ... optN]
|
||||
# [LINK_LIBRARIES lib1 lib2 ... libN]
|
||||
# [LINK_OPTIONS lopt1 lop2 .. loptN]
|
||||
# )
|
||||
#
|
||||
# ``target_name``:
|
||||
# Required, expects the name of the test which will be used to define a target
|
||||
#
|
||||
# ``SOURCES``:
|
||||
# Required, expects one or more source files names
|
||||
#
|
||||
# ``COMPILE_OPTIONS``:
|
||||
# Optional, expects one or more options to be passed to the compiler
|
||||
#
|
||||
# ``LINK_LIBRARIES``:
|
||||
# Optional, expects one or more libraries to be linked with the test
|
||||
# executable.
|
||||
#
|
||||
# ``LINK_OPTIONS``:
|
||||
# Optional, expects one or more options to be passed to the linker
|
||||
#
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# .. code-block:: cmake
|
||||
#
|
||||
# add_cmocka_test(my_test
|
||||
# SOURCES my_test.c other_source.c
|
||||
# COMPILE_OPTIONS -g -Wall
|
||||
# LINK_LIBRARIES mylib
|
||||
# LINK_OPTIONS -Wl,--enable-syscall-fixup
|
||||
# )
|
||||
#
|
||||
# Where ``my_test`` is the name of the test, ``my_test.c`` and
|
||||
# ``other_source.c`` are sources for the binary, ``-g -Wall`` are compiler
|
||||
# options to be used, ``mylib`` is a target of a library to be linked, and
|
||||
# ``-Wl,--enable-syscall-fixup`` is an option passed to the linker.
|
||||
#
|
||||
|
||||
enable_testing()
|
||||
include(CTest)
|
||||
|
||||
@@ -69,52 +17,10 @@ if (CMAKE_CROSSCOMPILING)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(ADD_CMOCKA_TEST _TARGET_NAME)
|
||||
function(ADD_CMOCKA_TEST _testName _testSource)
|
||||
add_executable(${_testName} ${_testSource})
|
||||
|
||||
set(one_value_arguments
|
||||
)
|
||||
|
||||
set(multi_value_arguments
|
||||
SOURCES
|
||||
COMPILE_OPTIONS
|
||||
LINK_LIBRARIES
|
||||
LINK_OPTIONS
|
||||
)
|
||||
|
||||
cmake_parse_arguments(_add_cmocka_test
|
||||
""
|
||||
"${one_value_arguments}"
|
||||
"${multi_value_arguments}"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if (NOT DEFINED _add_cmocka_test_SOURCES)
|
||||
message(FATAL_ERROR "No sources provided for target ${_TARGET_NAME}")
|
||||
endif()
|
||||
|
||||
add_executable(${_TARGET_NAME} ${_add_cmocka_test_SOURCES})
|
||||
|
||||
if (DEFINED _add_cmocka_test_COMPILE_OPTIONS)
|
||||
target_compile_options(${_TARGET_NAME}
|
||||
PRIVATE ${_add_cmocka_test_COMPILE_OPTIONS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DEFINED _add_cmocka_test_LINK_LIBRARIES)
|
||||
target_link_libraries(${_TARGET_NAME}
|
||||
PRIVATE ${_add_cmocka_test_LINK_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (DEFINED _add_cmocka_test_LINK_OPTIONS)
|
||||
set_target_properties(${_TARGET_NAME}
|
||||
PROPERTIES LINK_FLAGS
|
||||
${_add_cmocka_test_LINK_OPTIONS}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_test(${_TARGET_NAME}
|
||||
${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME}
|
||||
)
|
||||
target_link_libraries(${_testName} ${ARGN})
|
||||
|
||||
add_test(${_testName} ${TARGET_SYSTEM_EMULATOR} ${CMAKE_CURRENT_BINARY_DIR}/${_testName}${CMAKE_EXECUTABLE_SUFFIX})
|
||||
endfunction (ADD_CMOCKA_TEST)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
if (UNIX AND NOT WIN32)
|
||||
# Activate with: -DCMAKE_BUILD_TYPE=Profiling
|
||||
set(CMAKE_C_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
set(CMAKE_C_FLAGS_PROFILING "-g -O0 -fprofile-arcs -ftest-coverage"
|
||||
CACHE STRING "Flags used by the C compiler during PROFILING builds.")
|
||||
set(CMAKE_CXX_FLAGS_PROFILING "-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
set(CMAKE_CXX_FLAGS_PROFILING "-g -O0 -fprofile-arcs -ftest-coverage"
|
||||
CACHE STRING "Flags used by the CXX compiler during PROFILING builds.")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_PROFILING "-fprofile-arcs -ftest-coverage"
|
||||
CACHE STRING "Flags used by the linker during the creation of shared libraries during PROFILING builds.")
|
||||
@@ -22,28 +22,4 @@ if (UNIX AND NOT WIN32)
|
||||
CACHE STRING "Flags used by the linker during the creation of shared libraries during ADDRESSSANITIZER builds.")
|
||||
set(CMAKE_EXEC_LINKER_FLAGS_ADDRESSSANITIZER "-fsanitize=address"
|
||||
CACHE STRING "Flags used by the linker during ADDRESSSANITIZER builds.")
|
||||
|
||||
# Activate with: -DCMAKE_BUILD_TYPE=MemorySanitizer
|
||||
set(CMAKE_C_FLAGS_MEMORYSANITIZER "-g -O2 -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer"
|
||||
CACHE STRING "Flags used by the C compiler during MEMORYSANITIZER builds.")
|
||||
set(CMAKE_CXX_FLAGS_MEMORYSANITIZER "-g -O2 -fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer"
|
||||
CACHE STRING "Flags used by the CXX compiler during MEMORYSANITIZER builds.")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory"
|
||||
CACHE STRING "Flags used by the linker during the creation of shared libraries during MEMORYSANITIZER builds.")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory"
|
||||
CACHE STRING "Flags used by the linker during the creation of shared libraries during MEMORYSANITIZER builds.")
|
||||
set(CMAKE_EXEC_LINKER_FLAGS_MEMORYSANITIZER "-fsanitize=memory"
|
||||
CACHE STRING "Flags used by the linker during MEMORYSANITIZER builds.")
|
||||
|
||||
# Activate with: -DCMAKE_BUILD_TYPE=UndefinedSanitizer
|
||||
set(CMAKE_C_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
|
||||
CACHE STRING "Flags used by the C compiler during UNDEFINEDSANITIZER builds.")
|
||||
set(CMAKE_CXX_FLAGS_UNDEFINEDSANITIZER "-g -O1 -fsanitize=undefined -fsanitize=null -fsanitize=alignment -fno-sanitize-recover"
|
||||
CACHE STRING "Flags used by the CXX compiler during UNDEFINEDSANITIZER builds.")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined"
|
||||
CACHE STRING "Flags used by the linker during the creation of shared libraries during UNDEFINEDSANITIZER builds.")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined"
|
||||
CACHE STRING "Flags used by the linker during the creation of shared libraries during UNDEFINEDSANITIZER builds.")
|
||||
set(CMAKE_EXEC_LINKER_FLAGS_UNDEFINEDSANITIZER "-fsanitize=undefined"
|
||||
CACHE STRING "Flags used by the linker during UNDEFINEDSANITIZER builds.")
|
||||
endif()
|
||||
|
||||
@@ -49,15 +49,7 @@ find_library(GCRYPT_LIBRARY
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
)
|
||||
find_library(GCRYPT_ERROR_LIBRARY
|
||||
NAMES
|
||||
gpg-error
|
||||
libgpg-error-0
|
||||
libgpg-error6-0
|
||||
HINTS
|
||||
${_GCRYPT_ROOT_HINTS_AND_PATHS}
|
||||
)
|
||||
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY} ${GCRYPT_ERROR_LIBRARY})
|
||||
set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY})
|
||||
|
||||
if (GCRYPT_INCLUDE_DIR)
|
||||
file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" _gcrypt_version_str REGEX "^#define GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]")
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
#cmakedefine BINARYDIR "${BINARYDIR}"
|
||||
#cmakedefine SOURCEDIR "${SOURCEDIR}"
|
||||
|
||||
/* Global bind configuration file path */
|
||||
#cmakedefine GLOBAL_BIND_CONFIG "${GLOBAL_BIND_CONFIG}"
|
||||
|
||||
/* Global client configuration file path */
|
||||
#cmakedefine GLOBAL_CLIENT_CONFIG "${GLOBAL_CLIENT_CONFIG}"
|
||||
|
||||
/************************** HEADER FILES *************************/
|
||||
|
||||
/* Define to 1 if you have the <argp.h> header file. */
|
||||
@@ -29,9 +23,6 @@
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#cmakedefine HAVE_GLOB_H 1
|
||||
|
||||
/* Define to 1 if you have the <valgrind/valgrind.h> header file. */
|
||||
#cmakedefine HAVE_VALGRIND_VALGRIND_H 1
|
||||
|
||||
/* Define to 1 if you have the <pty.h> header file. */
|
||||
#cmakedefine HAVE_PTY_H 1
|
||||
|
||||
@@ -109,9 +100,6 @@
|
||||
/* Define to 1 if you have the `EVP_aes128_cbc' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_AES_CBC 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_aes128_gcm' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_AES_GCM 1
|
||||
|
||||
/* Define to 1 if you have the `CRYPTO_THREADID_set_callback' function. */
|
||||
#cmakedefine HAVE_OPENSSL_CRYPTO_THREADID_SET_CALLBACK 1
|
||||
|
||||
@@ -121,12 +109,6 @@
|
||||
/* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_CIPHER_CTX_NEW 1
|
||||
|
||||
/* Define to 1 if you have the `EVP_KDF_CTX_new_id' function. */
|
||||
#cmakedefine HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID 1
|
||||
|
||||
/* Define to 1 if you have the `OPENSSL_ia32cap_loc' function. */
|
||||
#cmakedefine HAVE_OPENSSL_IA32CAP_LOC 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#cmakedefine HAVE_SNPRINTF 1
|
||||
|
||||
@@ -196,9 +178,6 @@
|
||||
/* Define to 1 if you have the `SecureZeroMemory' function. */
|
||||
#cmakedefine HAVE_SECURE_ZERO_MEMORY 1
|
||||
|
||||
/* Define to 1 if you have the `cmocka_set_test_filter' function. */
|
||||
#cmakedefine HAVE_CMOCKA_SET_TEST_FILTER 1
|
||||
|
||||
/*************************** LIBRARIES ***************************/
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
@@ -213,21 +192,18 @@
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#cmakedefine HAVE_PTHREAD 1
|
||||
|
||||
/* Define to 1 if you have the `cmocka' library (-lcmocka). */
|
||||
#cmakedefine HAVE_CMOCKA 1
|
||||
|
||||
/**************************** OPTIONS ****************************/
|
||||
|
||||
#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1
|
||||
#cmakedefine HAVE_MSC_THREAD_LOCAL_STORAGE 1
|
||||
|
||||
#cmakedefine HAVE_FALLTHROUGH_ATTRIBUTE 1
|
||||
#cmakedefine HAVE_UNUSED_ATTRIBUTE 1
|
||||
|
||||
#cmakedefine HAVE_CONSTRUCTOR_ATTRIBUTE 1
|
||||
#cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 1
|
||||
|
||||
#cmakedefine HAVE_GCC_VOLATILE_MEMORY_PROTECTION 1
|
||||
#cmakedefine HAVE_GCC_NARG_MACRO 1
|
||||
|
||||
#cmakedefine HAVE_COMPILER__FUNC__ 1
|
||||
#cmakedefine HAVE_COMPILER__FUNCTION__ 1
|
||||
@@ -246,12 +222,6 @@
|
||||
/* Define to 1 if you want to enable server support */
|
||||
#cmakedefine WITH_SERVER 1
|
||||
|
||||
/* Define to 1 if you want to enable DH group exchange algorithms */
|
||||
#cmakedefine WITH_GEX 1
|
||||
|
||||
/* Define to 1 if you want to enable blowfish cipher support */
|
||||
#cmakedefine WITH_BLOWFISH_CIPHER 1
|
||||
|
||||
/* Define to 1 if you want to enable debug output for crypto functions */
|
||||
#cmakedefine DEBUG_CRYPTO 1
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ int authenticate_pubkey(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
|
||||
rc = ssh_userauth_publickey_auto(session, NULL);
|
||||
|
||||
if (rc == SSH_AUTH_ERROR)
|
||||
{
|
||||
@@ -281,7 +281,7 @@ pass, ssh_userauth_none() might answer SSH_AUTH_SUCCESS.
|
||||
The following example shows how to perform "none" authentication:
|
||||
|
||||
@code
|
||||
int authenticate_none(ssh_session session)
|
||||
int authenticate_kbdint(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
||||
@@ -431,9 +431,6 @@ int show_remote_processes(ssh_session session)
|
||||
}
|
||||
@endcode
|
||||
|
||||
Each ssh_channel_request_exec() needs to be run on freshly created
|
||||
and connected (with ssh_channel_open_session()) channel.
|
||||
|
||||
@see @ref opening_shell
|
||||
@see @ref remote_command
|
||||
@see @ref sftp_subsystem
|
||||
|
||||
@@ -27,7 +27,4 @@ the dllimport attribute.
|
||||
#include <libssh/libssh.h>
|
||||
@endcode
|
||||
|
||||
If you're are statically linking with OpenSSL, read the "Linking your
|
||||
application" section in the NOTES.<OS> in the OpenSSL source tree!
|
||||
|
||||
*/
|
||||
|
||||
@@ -61,7 +61,7 @@ int sftp_helloworld(ssh_session session)
|
||||
rc = sftp_init(sftp);
|
||||
if (rc != SSH_OK)
|
||||
{
|
||||
fprintf(stderr, "Error initializing SFTP session: code %d.\n",
|
||||
fprintf(stderr, "Error initializing SFTP session: %s.\n",
|
||||
sftp_get_error(sftp));
|
||||
sftp_free(sftp);
|
||||
return rc;
|
||||
|
||||
@@ -53,10 +53,6 @@ if (UNIX AND NOT WIN32)
|
||||
add_executable(proxy proxy.c)
|
||||
target_compile_options(proxy PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(proxy ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
|
||||
|
||||
add_executable(sshd_direct-tcpip sshd_direct-tcpip.c)
|
||||
target_compile_options(sshd_direct-tcpip PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(sshd_direct-tcpip ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
|
||||
endif (WITH_GSSAPI AND GSSAPI_FOUND)
|
||||
|
||||
add_executable(samplesshd-kbdint samplesshd-kbdint.c)
|
||||
@@ -74,10 +70,6 @@ add_executable(senddata senddata.c ${examples_SRCS})
|
||||
target_compile_options(senddata PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(senddata ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
add_executable(keygen keygen.c)
|
||||
target_compile_options(keygen PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
target_link_libraries(keygen ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
add_executable(libsshpp libsshpp.cpp)
|
||||
target_link_libraries(libsshpp ${LIBSSH_SHARED_LIBRARY})
|
||||
|
||||
|
||||
@@ -100,39 +100,6 @@ int authenticate_kbdint(ssh_session session, const char *password)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int auth_keyfile(ssh_session session, char* keyfile)
|
||||
{
|
||||
ssh_key key = NULL;
|
||||
char pubkey[132] = {0}; // +".pub"
|
||||
int rc;
|
||||
|
||||
snprintf(pubkey, sizeof(pubkey), "%s.pub", keyfile);
|
||||
|
||||
rc = ssh_pki_import_pubkey_file( pubkey, &key);
|
||||
|
||||
if (rc != SSH_OK)
|
||||
return SSH_AUTH_DENIED;
|
||||
|
||||
rc = ssh_userauth_try_publickey(session, NULL, key);
|
||||
|
||||
ssh_key_free(key);
|
||||
|
||||
if (rc!=SSH_AUTH_SUCCESS)
|
||||
return SSH_AUTH_DENIED;
|
||||
|
||||
rc = ssh_pki_import_privkey_file(keyfile, NULL, NULL, NULL, &key);
|
||||
|
||||
if (rc != SSH_OK)
|
||||
return SSH_AUTH_DENIED;
|
||||
|
||||
rc = ssh_userauth_publickey(session, NULL, key);
|
||||
|
||||
ssh_key_free(key);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void error(ssh_session session)
|
||||
{
|
||||
fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
|
||||
@@ -173,35 +140,6 @@ int authenticate_console(ssh_session session)
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
char buffer[128] = {0};
|
||||
char *p = NULL;
|
||||
|
||||
printf("Automatic pubkey failed. "
|
||||
"Do you want to try a specific key? (y/n)\n");
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
|
||||
break;
|
||||
}
|
||||
if ((buffer[0]=='Y') || (buffer[0]=='y')) {
|
||||
printf("private key filename: ");
|
||||
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
if ((p = strchr(buffer, '\n'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
rc = auth_keyfile(session, buffer);
|
||||
|
||||
if(rc == SSH_AUTH_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "failed with key\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Try to authenticate with keyboard interactive";
|
||||
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||
|
||||
@@ -14,10 +14,6 @@ clients must be made or how a client should react.
|
||||
#define EXAMPLES_COMMON_H_
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
|
||||
/** Zero a structure */
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
|
||||
int authenticate_console(ssh_session session);
|
||||
int authenticate_kbdint(ssh_session session, const char *password);
|
||||
int verify_knownhost(ssh_session session);
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/* keygen.c
|
||||
* Sample implementation of ssh-keygen using libssh
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2019 Red Hat, Inc.
|
||||
|
||||
Author: Jakub Jelen <jjelen@redhat.com>
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
*/
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ssh_key key = NULL;
|
||||
int rv;
|
||||
|
||||
/* Generate a new ED25519 private key file */
|
||||
rv = ssh_pki_generate(SSH_KEYTYPE_ED25519, 0, &key);
|
||||
if (rv != SSH_OK) {
|
||||
fprintf(stderr, "Failed to generate private key");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write it to a file testkey in the current dirrectory */
|
||||
rv = ssh_pki_export_privkey_file(key, NULL, NULL, NULL, "testkey");
|
||||
if (rv != SSH_OK) {
|
||||
fprintf(stderr, "Failed to write private key file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -32,86 +32,82 @@ clients must be made or how a client should react.
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
int verify_knownhost(ssh_session session)
|
||||
{
|
||||
enum ssh_known_hosts_e state;
|
||||
char buf[10];
|
||||
unsigned char *hash = NULL;
|
||||
size_t hlen;
|
||||
ssh_key srv_pubkey;
|
||||
int rc;
|
||||
int verify_knownhost(ssh_session session){
|
||||
enum ssh_known_hosts_e state;
|
||||
char buf[10];
|
||||
unsigned char *hash = NULL;
|
||||
size_t hlen;
|
||||
ssh_key srv_pubkey;
|
||||
int rc;
|
||||
|
||||
rc = ssh_get_server_publickey(session, &srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
rc = ssh_get_server_publickey(session, &srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ssh_get_publickey_hash(srv_pubkey,
|
||||
SSH_PUBLICKEY_HASH_SHA256,
|
||||
&hash,
|
||||
&hlen);
|
||||
ssh_key_free(srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
rc = ssh_get_publickey_hash(srv_pubkey,
|
||||
SSH_PUBLICKEY_HASH_SHA256,
|
||||
&hash,
|
||||
&hlen);
|
||||
ssh_key_free(srv_pubkey);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
state = ssh_session_is_known_server(session);
|
||||
state = ssh_session_is_known_server(session);
|
||||
|
||||
switch(state) {
|
||||
case SSH_KNOWN_HOSTS_CHANGED:
|
||||
fprintf(stderr,"Host key for server changed : server's one is now :\n");
|
||||
ssh_print_hash(SSH_PUBLICKEY_HASH_SHA256, hash, hlen);
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
fprintf(stderr,"For security reason, connection will be stopped\n");
|
||||
return -1;
|
||||
case SSH_KNOWN_HOSTS_OTHER:
|
||||
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
|
||||
fprintf(stderr,"An attacker might change the default server key to confuse your client"
|
||||
"into thinking the key does not exist\n"
|
||||
"We advise you to rerun the client with -d or -r for more safety.\n");
|
||||
return -1;
|
||||
case SSH_KNOWN_HOSTS_NOT_FOUND:
|
||||
fprintf(stderr,"Could not find known host file. If you accept the host key here,\n");
|
||||
fprintf(stderr,"the file will be automatically created.\n");
|
||||
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
|
||||
FALL_THROUGH;
|
||||
case SSH_SERVER_NOT_KNOWN:
|
||||
fprintf(stderr,
|
||||
"The server is unknown. Do you trust the host key (yes/no)?\n");
|
||||
ssh_print_hash(SSH_PUBLICKEY_HASH_SHA256, hash, hlen);
|
||||
|
||||
if (fgets(buf, sizeof(buf), stdin) == NULL) {
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return -1;
|
||||
}
|
||||
if(strncasecmp(buf,"yes",3)!=0){
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n");
|
||||
if (fgets(buf, sizeof(buf), stdin) == NULL) {
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return -1;
|
||||
}
|
||||
if(strncasecmp(buf,"yes",3)==0){
|
||||
rc = ssh_session_update_known_hosts(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
fprintf(stderr, "error %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case SSH_KNOWN_HOSTS_ERROR:
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
fprintf(stderr,"%s",ssh_get_error(session));
|
||||
return -1;
|
||||
switch(state){
|
||||
case SSH_KNOWN_HOSTS_OK:
|
||||
break; /* ok */
|
||||
}
|
||||
break; /* ok */
|
||||
case SSH_KNOWN_HOSTS_CHANGED:
|
||||
fprintf(stderr,"Host key for server changed : server's one is now :\n");
|
||||
ssh_print_hash(SSH_PUBLICKEY_HASH_SHA256, hash, hlen);
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
fprintf(stderr,"For security reason, connection will be stopped\n");
|
||||
return -1;
|
||||
case SSH_KNOWN_HOSTS_OTHER:
|
||||
fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
|
||||
fprintf(stderr,"An attacker might change the default server key to confuse your client"
|
||||
"into thinking the key does not exist\n"
|
||||
"We advise you to rerun the client with -d or -r for more safety.\n");
|
||||
return -1;
|
||||
case SSH_KNOWN_HOSTS_NOT_FOUND:
|
||||
fprintf(stderr,"Could not find known host file. If you accept the host key here,\n");
|
||||
fprintf(stderr,"the file will be automatically created.\n");
|
||||
/* fallback to SSH_SERVER_NOT_KNOWN behavior */
|
||||
FALL_THROUGH;
|
||||
case SSH_SERVER_NOT_KNOWN:
|
||||
fprintf(stderr,
|
||||
"The server is unknown. Do you trust the host key (yes/no)?\n");
|
||||
ssh_print_hash(SSH_PUBLICKEY_HASH_SHA256, hash, hlen);
|
||||
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
if (fgets(buf, sizeof(buf), stdin) == NULL) {
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return -1;
|
||||
}
|
||||
if(strncasecmp(buf,"yes",3)!=0){
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n");
|
||||
if (fgets(buf, sizeof(buf), stdin) == NULL) {
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return -1;
|
||||
}
|
||||
if(strncasecmp(buf,"yes",3)==0){
|
||||
if (ssh_write_knownhost(session) < 0) {
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
fprintf(stderr, "error %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
break;
|
||||
case SSH_KNOWN_HOSTS_ERROR:
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
fprintf(stderr,"%s",ssh_get_error(session));
|
||||
return -1;
|
||||
}
|
||||
ssh_clean_pubkey_hash(&hash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,6 @@ static void sizechanged(void)
|
||||
static void select_loop(ssh_session session,ssh_channel channel)
|
||||
{
|
||||
ssh_connector connector_in, connector_out, connector_err;
|
||||
int rc;
|
||||
|
||||
ssh_event event = ssh_event_new();
|
||||
|
||||
@@ -223,11 +222,7 @@ static void select_loop(ssh_session session,ssh_channel channel)
|
||||
if (signal_delayed) {
|
||||
sizechanged();
|
||||
}
|
||||
rc = ssh_event_dopoll(event, 60000);
|
||||
if (rc == SSH_ERROR) {
|
||||
fprintf(stderr, "Error in ssh_event_dopoll()\n");
|
||||
break;
|
||||
}
|
||||
ssh_event_dopoll(event, 60000);
|
||||
}
|
||||
ssh_event_remove_connector(event, connector_in);
|
||||
ssh_event_remove_connector(event, connector_out);
|
||||
|
||||
@@ -37,7 +37,6 @@ The goal is to show the API in action.
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef KEYS_FOLDER
|
||||
@@ -71,8 +70,7 @@ static void set_default_keys(ssh_bind sshbind,
|
||||
KEYS_FOLDER "ssh_host_ecdsa_key");
|
||||
}
|
||||
}
|
||||
#define DEF_STR_SIZE 1024
|
||||
char authorizedkeys[DEF_STR_SIZE] = {0};
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
const char *argp_program_version = "libssh server example "
|
||||
SSH_STRINGIFY(LIBSSH_VERSION);
|
||||
@@ -127,14 +125,6 @@ static struct argp_option options[] = {
|
||||
.doc = "Set the ecdsa key.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "authorizedkeys",
|
||||
.key = 'a',
|
||||
.arg = "FILE",
|
||||
.flags = 0,
|
||||
.doc = "Set the authorized keys file.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "no-default-keys",
|
||||
.key = 'n',
|
||||
@@ -188,9 +178,6 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, arg);
|
||||
ecdsa_already_set = 1;
|
||||
break;
|
||||
case 'a':
|
||||
strncpy(authorizedkeys, arg, DEF_STR_SIZE-1);
|
||||
break;
|
||||
case 'v':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||
"3");
|
||||
@@ -447,53 +434,6 @@ static int auth_password(ssh_session session, const char *user,
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
static int auth_publickey(ssh_session session,
|
||||
const char *user,
|
||||
struct ssh_key_struct *pubkey,
|
||||
char signature_state,
|
||||
void *userdata)
|
||||
{
|
||||
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
||||
|
||||
(void) user;
|
||||
(void) session;
|
||||
|
||||
if (signature_state == SSH_PUBLICKEY_STATE_NONE) {
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
|
||||
if (signature_state != SSH_PUBLICKEY_STATE_VALID) {
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
// valid so far. Now look through authorized keys for a match
|
||||
if (authorizedkeys[0]) {
|
||||
ssh_key key = NULL;
|
||||
int result;
|
||||
struct stat buf;
|
||||
|
||||
if (stat(authorizedkeys, &buf) == 0) {
|
||||
result = ssh_pki_import_pubkey_file( authorizedkeys, &key );
|
||||
if ((result != SSH_OK) || (key==NULL)) {
|
||||
fprintf(stderr,
|
||||
"Unable to import public key file %s\n",
|
||||
authorizedkeys);
|
||||
} else {
|
||||
result = ssh_key_cmp( key, pubkey, SSH_KEY_CMP_PUBLIC );
|
||||
ssh_key_free(key);
|
||||
if (result == 0) {
|
||||
sdata->authenticated = 1;
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no matches
|
||||
sdata->authenticated = 0;
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
static ssh_channel channel_open(ssh_session session, void *userdata) {
|
||||
struct session_data_struct *sdata = (struct session_data_struct *) userdata;
|
||||
|
||||
@@ -532,8 +472,7 @@ static int process_stderr(socket_t fd, int revents, void *userdata) {
|
||||
}
|
||||
|
||||
static void handle_session(ssh_event event, ssh_session session) {
|
||||
int n;
|
||||
int rc = 0;
|
||||
int n, rc;
|
||||
|
||||
/* Structure for storing the pty size. */
|
||||
struct winsize wsize = {
|
||||
@@ -578,12 +517,6 @@ static void handle_session(ssh_event event, ssh_session session) {
|
||||
.channel_open_request_session_function = channel_open,
|
||||
};
|
||||
|
||||
if (authorizedkeys[0]) {
|
||||
server_cb.auth_pubkey_function = auth_publickey;
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY);
|
||||
} else
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
|
||||
|
||||
ssh_callbacks_init(&server_cb);
|
||||
ssh_callbacks_init(&channel_cb);
|
||||
|
||||
@@ -594,6 +527,7 @@ static void handle_session(ssh_event event, ssh_session session) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
|
||||
ssh_event_add_session(event, session);
|
||||
|
||||
n = 0;
|
||||
|
||||
@@ -1,654 +0,0 @@
|
||||
/* This is a sample implementation of a libssh based SSH server */
|
||||
/*
|
||||
Copyright 2003-2009 Aris Adamantiadis
|
||||
Copyright 2018 T. Wimmer
|
||||
|
||||
This file is part of the SSH Library
|
||||
|
||||
You are free to copy this file, modify it in any way, consider it being public
|
||||
domain. This does not apply to the rest of the library though, but it is
|
||||
allowed to cut-and-paste working code from this file to any license of
|
||||
program.
|
||||
The goal is to show the API in action. It's not a reference on how terminal
|
||||
clients must be made or how a client should react.
|
||||
*/
|
||||
|
||||
/*
|
||||
Example:
|
||||
./sshd_direct-tcpip -v -p 2022 -d serverkey.dsa -r serverkey.rsa 127.0.0.1
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <libssh/libssh.h>
|
||||
#include <libssh/server.h>
|
||||
#include <libssh/callbacks.h>
|
||||
#include <libssh/channels.h>
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
#include <argp.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <poll.h>
|
||||
|
||||
#ifndef KEYS_FOLDER
|
||||
#ifdef _WIN32
|
||||
#define KEYS_FOLDER
|
||||
#else
|
||||
#define KEYS_FOLDER "/etc/ssh/"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define USER "user"
|
||||
#define PASSWORD "pwd"
|
||||
|
||||
struct event_fd_data_struct {
|
||||
int *p_fd;
|
||||
ssh_channel channel;
|
||||
struct ssh_channel_callbacks_struct *cb_chan;
|
||||
int stacked;
|
||||
};
|
||||
|
||||
struct cleanup_node_struct {
|
||||
struct event_fd_data_struct *data;
|
||||
struct cleanup_node_struct *next;
|
||||
};
|
||||
|
||||
static bool authenticated = false;
|
||||
static int tries = 0;
|
||||
static bool error_set = false;
|
||||
static int sockets_cnt = 0;
|
||||
static ssh_event mainloop = NULL;
|
||||
static struct cleanup_node_struct *cleanup_stack = NULL;
|
||||
|
||||
static void _close_socket(struct event_fd_data_struct event_fd_data);
|
||||
|
||||
static void cleanup_push(struct cleanup_node_struct** head_ref, struct event_fd_data_struct *new_data) {
|
||||
// Allocate memory for node
|
||||
struct cleanup_node_struct *new_node = malloc(sizeof *new_node);
|
||||
|
||||
new_node->next = (*head_ref);
|
||||
|
||||
// Copy new_data
|
||||
new_node->data = new_data;
|
||||
|
||||
// Change head pointer as new node is added at the beginning
|
||||
(*head_ref) = new_node;
|
||||
}
|
||||
|
||||
static void do_cleanup(struct cleanup_node_struct **head_ref) {
|
||||
struct cleanup_node_struct *current = (*head_ref);
|
||||
struct cleanup_node_struct *previous = NULL, *gone = NULL;
|
||||
|
||||
while (current != NULL) {
|
||||
if (ssh_channel_is_closed(current->data->channel)) {
|
||||
if (current == (*head_ref)) {
|
||||
(*head_ref) = current->next;
|
||||
}
|
||||
if (previous != NULL) {
|
||||
previous->next = current->next;
|
||||
}
|
||||
gone = current;
|
||||
current = current->next;
|
||||
|
||||
if (gone->data->channel) {
|
||||
_close_socket(*gone->data);
|
||||
ssh_remove_channel_callbacks(gone->data->channel, gone->data->cb_chan);
|
||||
ssh_channel_free(gone->data->channel);
|
||||
gone->data->channel = NULL;
|
||||
|
||||
SAFE_FREE(gone->data->p_fd);
|
||||
SAFE_FREE(gone->data->cb_chan);
|
||||
SAFE_FREE(gone->data);
|
||||
SAFE_FREE(gone);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "channel already freed!\n");
|
||||
}
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== do_cleanup", "Freed.");
|
||||
}
|
||||
else {
|
||||
ssh_channel_close(current->data->channel);
|
||||
previous = current;
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int auth_password(ssh_session session, const char *user,
|
||||
const char *password, void *userdata) {
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== auth_password", "Authenticating user %s pwd %s",user, password);
|
||||
if (strcmp(user,USER) == 0 && strcmp(password, PASSWORD) == 0){
|
||||
authenticated = true;
|
||||
printf("Authenticated\n");
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
if (tries >= 3){
|
||||
printf("Too many authentication tries\n");
|
||||
ssh_disconnect(session);
|
||||
error_set = true;
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
tries++;
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
|
||||
static int auth_gssapi_mic(ssh_session session, const char *user, const char *principal, void *userdata) {
|
||||
ssh_gssapi_creds creds = ssh_gssapi_get_creds(session);
|
||||
(void)userdata;
|
||||
printf("Authenticating user %s with gssapi principal %s\n", user, principal);
|
||||
if (creds != NULL)
|
||||
printf("Received some gssapi credentials\n");
|
||||
else
|
||||
printf("Not received any forwardable creds\n");
|
||||
printf("authenticated\n");
|
||||
authenticated = true;
|
||||
return SSH_AUTH_SUCCESS;
|
||||
}
|
||||
|
||||
static int subsystem_request(ssh_session session, ssh_channel channel, const char *subsystem, void *userdata) {
|
||||
(void)session;
|
||||
(void)channel;
|
||||
//(void)subsystem;
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== subsystem_request", "Channel subsystem reqeuest: %s", subsystem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ssh_channel_callbacks_struct channel_cb = {
|
||||
.channel_subsystem_request_function = subsystem_request
|
||||
};
|
||||
|
||||
static ssh_channel new_session_channel(ssh_session session, void *userdata) {
|
||||
(void)session;
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== subsystem_request", "Session channel request");
|
||||
/* For TCP forward only there seems to be no need for a session channel */
|
||||
/*if(chan != NULL)
|
||||
return NULL;
|
||||
printf("Session channel request\n");
|
||||
chan = ssh_channel_new(session);
|
||||
ssh_callbacks_init(&channel_cb);
|
||||
ssh_set_channel_callbacks(chan, &channel_cb);
|
||||
return chan;*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void stack_socket_close(UNUSED_PARAM(ssh_session session),
|
||||
struct event_fd_data_struct *event_fd_data)
|
||||
{
|
||||
if (event_fd_data->stacked != 1) {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== stack_socket_close", "Closing fd = %d sockets_cnt = %d", *event_fd_data->p_fd, sockets_cnt);
|
||||
event_fd_data->stacked = 1;
|
||||
cleanup_push(&cleanup_stack, event_fd_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void _close_socket(struct event_fd_data_struct event_fd_data) {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== close_socket", "Closing fd = %d sockets_cnt = %d", *event_fd_data.p_fd, sockets_cnt);
|
||||
ssh_event_remove_fd(mainloop, *event_fd_data.p_fd);
|
||||
sockets_cnt--;
|
||||
#ifdef _WIN32
|
||||
closesocket(*event_fd_data.p_fd);
|
||||
#else
|
||||
close(*event_fd_data.p_fd);
|
||||
#endif // _WIN32
|
||||
(*event_fd_data.p_fd) = SSH_INVALID_SOCKET;
|
||||
}
|
||||
|
||||
static int service_request(ssh_session session, const char *service, void *userdata) {
|
||||
(void)session;
|
||||
//(void)service;
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== service_request", "Service request: %s", service);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void global_request(ssh_session session, ssh_message message, void *userdata) {
|
||||
(void)session;
|
||||
(void)userdata;
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== global_request", "Global request, message type: %d", ssh_message_type(message));
|
||||
}
|
||||
|
||||
static void my_channel_close_function(ssh_session session, ssh_channel channel, void *userdata) {
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
(void)session;
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_close_function", "Channel %d:%d closed by remote. State=%d", channel->local_channel, channel->remote_channel, channel->state);
|
||||
|
||||
stack_socket_close(session, event_fd_data);
|
||||
}
|
||||
|
||||
static void my_channel_eof_function(ssh_session session, ssh_channel channel, void *userdata) {
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
(void)session;
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_eof_function", "Got EOF on channel %d:%d. Shuting down write on socket (fd = %d).", channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
|
||||
|
||||
stack_socket_close(session, event_fd_data);
|
||||
}
|
||||
|
||||
static void my_channel_exit_status_function(ssh_session session, ssh_channel channel, int exit_status, void *userdata) {
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
(void)session;
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_exit_status_function", "Got exit status %d on channel %d:%d fd = %d.", exit_status, channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
|
||||
}
|
||||
|
||||
static int my_channel_data_function(ssh_session session,
|
||||
ssh_channel channel,
|
||||
void *data,
|
||||
uint32_t len,
|
||||
UNUSED_PARAM(int is_stderr),
|
||||
void *userdata)
|
||||
{
|
||||
int i = 0;
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
|
||||
if (event_fd_data->channel == NULL) {
|
||||
fprintf(stderr, "Why we're here? Stacked = %d\n", event_fd_data->stacked);
|
||||
}
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_channel_data_function", "%d bytes waiting on channel %d:%d for reading. Fd = %d",len, channel->local_channel, channel->remote_channel, *event_fd_data->p_fd);
|
||||
if (len > 0) {
|
||||
i = send(*event_fd_data->p_fd, data, len, 0);
|
||||
}
|
||||
if (i < 0) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== my_channel_data_function", "Writing to tcp socket %d: %s", *event_fd_data->p_fd, strerror(errno));
|
||||
stack_socket_close(session, event_fd_data);
|
||||
}
|
||||
else {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_channel_data_function", "Sent %d bytes", i);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int my_fd_data_function(UNUSED_PARAM(socket_t fd),
|
||||
int revents,
|
||||
void *userdata)
|
||||
{
|
||||
struct event_fd_data_struct *event_fd_data = (struct event_fd_data_struct *)userdata;
|
||||
ssh_channel channel = event_fd_data->channel;
|
||||
ssh_session session;
|
||||
int len, i, wr;
|
||||
char buf[16384];
|
||||
int blocking;
|
||||
|
||||
if (channel == NULL) {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel == NULL!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
session = ssh_channel_get_session(channel);
|
||||
|
||||
if (ssh_channel_is_closed(channel)) {
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel is closed!");
|
||||
stack_socket_close(session, event_fd_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(revents & POLLIN)) {
|
||||
if (revents & POLLPRI) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLPRI");
|
||||
}
|
||||
if (revents & POLLOUT) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLOUT");
|
||||
}
|
||||
if (revents & POLLHUP) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLHUP");
|
||||
}
|
||||
if (revents & POLLNVAL) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLNVAL");
|
||||
}
|
||||
if (revents & POLLERR) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "poll revents & POLLERR");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
blocking = ssh_is_blocking(session);
|
||||
ssh_set_blocking(session, 0);
|
||||
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "Trying to read from tcp socket fd = %d... (Channel %d:%d state=%d)",
|
||||
*event_fd_data->p_fd, channel->local_channel, channel->remote_channel, channel->state);
|
||||
#ifdef _WIN32
|
||||
struct sockaddr from;
|
||||
int fromlen = sizeof(from);
|
||||
len = recvfrom(*event_fd_data->p_fd, buf, sizeof(buf), 0, &from, &fromlen);
|
||||
#else
|
||||
len = recv(*event_fd_data->p_fd, buf, sizeof(buf), 0);
|
||||
#endif // _WIN32
|
||||
if (len < 0) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Reading from tcp socket: %s", strerror(errno));
|
||||
|
||||
ssh_channel_send_eof(channel);
|
||||
}
|
||||
else if (len > 0) {
|
||||
if (ssh_channel_is_open(channel)) {
|
||||
wr = 0;
|
||||
do {
|
||||
i = ssh_channel_write(channel, buf, len);
|
||||
if (i < 0) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Error writing on the direct-tcpip channel: %d", i);
|
||||
len = wr;
|
||||
break;
|
||||
}
|
||||
wr += i;
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== my_fd_data_function", "channel_write (%d from %d)", wr, len);
|
||||
} while (i > 0 && wr < len);
|
||||
}
|
||||
else {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== my_fd_data_function", "Can't write on closed channel!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== my_fd_data_function", "The destination host has disconnected!");
|
||||
|
||||
ssh_channel_close(channel);
|
||||
#ifdef _WIN32
|
||||
shutdown(*event_fd_data->p_fd, SD_RECEIVE);
|
||||
#else
|
||||
shutdown(*event_fd_data->p_fd, SHUT_RD);
|
||||
#endif // _WIN32
|
||||
}
|
||||
ssh_set_blocking(session, blocking);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int open_tcp_socket(ssh_message msg) {
|
||||
struct sockaddr_in sin;
|
||||
int forwardsock = -1;
|
||||
struct hostent *host;
|
||||
const char *dest_hostname;
|
||||
int dest_port;
|
||||
|
||||
forwardsock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (forwardsock < 0) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR opening socket: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
dest_hostname = ssh_message_channel_request_open_destination(msg);
|
||||
dest_port = ssh_message_channel_request_open_destination_port(msg);
|
||||
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== open_tcp_socket", "Connecting to %s on port %d", dest_hostname, dest_port);
|
||||
|
||||
host = gethostbyname(dest_hostname);
|
||||
if (host == NULL) {
|
||||
close(forwardsock);
|
||||
_ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR, no such host: %s", dest_hostname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((char *)&sin, '\0', sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
memcpy((char *)&sin.sin_addr.s_addr, (char *)host->h_addr, host->h_length);
|
||||
sin.sin_port = htons(dest_port);
|
||||
|
||||
if (connect(forwardsock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
|
||||
close(forwardsock);
|
||||
_ssh_log(SSH_LOG_WARNING, "=== open_tcp_socket", "ERROR connecting: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockets_cnt++;
|
||||
_ssh_log(SSH_LOG_FUNCTIONS, "=== open_tcp_socket", "Connected. sockets_cnt = %d", sockets_cnt);
|
||||
return forwardsock;
|
||||
}
|
||||
|
||||
static int message_callback(ssh_session session, ssh_message message, void *userdata) {
|
||||
ssh_channel channel;
|
||||
int socket_fd, *pFd;
|
||||
struct ssh_channel_callbacks_struct *cb_chan;
|
||||
struct event_fd_data_struct *event_fd_data;
|
||||
(void)session;
|
||||
(void)message;
|
||||
(void)userdata;
|
||||
|
||||
_ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message type: %d", ssh_message_type(message));
|
||||
_ssh_log(SSH_LOG_PACKET, "=== message_callback", "Message Subtype: %d", ssh_message_subtype(message));
|
||||
if (ssh_message_type(message) == SSH_REQUEST_CHANNEL_OPEN) {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "channel_request_open");
|
||||
|
||||
if (ssh_message_subtype(message) == SSH_CHANNEL_DIRECT_TCPIP) {
|
||||
channel = ssh_message_channel_request_open_reply_accept(message);
|
||||
|
||||
if (channel == NULL) {
|
||||
_ssh_log(SSH_LOG_WARNING, "=== message_callback", "Accepting direct-tcpip channel failed!");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
_ssh_log(SSH_LOG_PROTOCOL, "=== message_callback", "Connected to channel!");
|
||||
|
||||
socket_fd = open_tcp_socket(message);
|
||||
if (-1 == socket_fd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
pFd = malloc(sizeof *pFd);
|
||||
cb_chan = malloc(sizeof *cb_chan);
|
||||
event_fd_data = malloc(sizeof *event_fd_data);
|
||||
|
||||
(*pFd) = socket_fd;
|
||||
event_fd_data->channel = channel;
|
||||
event_fd_data->p_fd = pFd;
|
||||
event_fd_data->stacked = 0;
|
||||
event_fd_data->cb_chan = cb_chan;
|
||||
|
||||
cb_chan->userdata = event_fd_data;
|
||||
cb_chan->channel_eof_function = my_channel_eof_function;
|
||||
cb_chan->channel_close_function = my_channel_close_function;
|
||||
cb_chan->channel_data_function = my_channel_data_function;
|
||||
cb_chan->channel_exit_status_function = my_channel_exit_status_function;
|
||||
|
||||
ssh_callbacks_init(cb_chan);
|
||||
ssh_set_channel_callbacks(channel, cb_chan);
|
||||
|
||||
ssh_event_add_fd(mainloop, (socket_t)*pFd, POLLIN, my_fd_data_function, event_fd_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
const char *argp_program_version = "libssh server example "
|
||||
SSH_STRINGIFY(LIBSSH_VERSION);
|
||||
const char *argp_program_bug_address = "<libssh@libssh.org>";
|
||||
|
||||
/* Program documentation. */
|
||||
static char doc[] = "libssh -- a Secure Shell protocol implementation";
|
||||
|
||||
/* A description of the arguments we accept. */
|
||||
static char args_doc[] = "BINDADDR";
|
||||
|
||||
/* The options we understand. */
|
||||
static struct argp_option options[] = {
|
||||
{
|
||||
.name = "port",
|
||||
.key = 'p',
|
||||
.arg = "PORT",
|
||||
.flags = 0,
|
||||
.doc = "Set the port to bind.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "hostkey",
|
||||
.key = 'k',
|
||||
.arg = "FILE",
|
||||
.flags = 0,
|
||||
.doc = "Set the host key.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "dsakey",
|
||||
.key = 'd',
|
||||
.arg = "FILE",
|
||||
.flags = 0,
|
||||
.doc = "Set the dsa key.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "rsakey",
|
||||
.key = 'r',
|
||||
.arg = "FILE",
|
||||
.flags = 0,
|
||||
.doc = "Set the rsa key.",
|
||||
.group = 0
|
||||
},
|
||||
{
|
||||
.name = "verbose",
|
||||
.key = 'v',
|
||||
.arg = NULL,
|
||||
.flags = 0,
|
||||
.doc = "Get verbose output.",
|
||||
.group = 0
|
||||
},
|
||||
{NULL, 0, NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* Parse a single option. */
|
||||
static error_t parse_opt (int key, char *arg, struct argp_state *state) {
|
||||
/* Get the input argument from argp_parse, which we
|
||||
* know is a pointer to our arguments structure.
|
||||
*/
|
||||
ssh_bind sshbind = state->input;
|
||||
|
||||
switch (key) {
|
||||
case 'p':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, arg);
|
||||
break;
|
||||
case 'd':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, arg);
|
||||
break;
|
||||
case 'k':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, arg);
|
||||
break;
|
||||
case 'r':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, arg);
|
||||
break;
|
||||
case 'v':
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "1");
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num >= 1) {
|
||||
/* Too many arguments. */
|
||||
argp_usage (state);
|
||||
}
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, arg);
|
||||
break;
|
||||
case ARGP_KEY_END:
|
||||
if (state->arg_num < 1) {
|
||||
/* Not enough arguments. */
|
||||
argp_usage (state);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Our argp parser. */
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
|
||||
#endif /* HAVE_ARGP_H */
|
||||
|
||||
int main(int argc, char **argv){
|
||||
ssh_session session;
|
||||
ssh_bind sshbind;
|
||||
struct ssh_server_callbacks_struct cb = {
|
||||
.userdata = NULL,
|
||||
.auth_password_function = auth_password,
|
||||
.auth_gssapi_mic_function = auth_gssapi_mic,
|
||||
.channel_open_request_session_function = new_session_channel,
|
||||
.service_request_function = service_request
|
||||
};
|
||||
struct ssh_callbacks_struct cb_gen = {
|
||||
.userdata = NULL,
|
||||
.global_request_function = global_request
|
||||
};
|
||||
|
||||
int ret = 1;
|
||||
|
||||
sshbind = ssh_bind_new();
|
||||
session = ssh_new();
|
||||
mainloop = ssh_event_new();
|
||||
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, KEYS_FOLDER "ssh_host_dsa_key");
|
||||
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, KEYS_FOLDER "ssh_host_rsa_key");
|
||||
|
||||
#ifdef HAVE_ARGP_H
|
||||
/*
|
||||
* Parse our arguments; every option seen by parse_opt will
|
||||
* be reflected in arguments.
|
||||
*/
|
||||
argp_parse (&argp, argc, argv, 0, 0, sshbind);
|
||||
#else
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
#endif
|
||||
|
||||
if (ssh_bind_listen(sshbind) < 0) {
|
||||
printf("Error listening to socket: %s\n", ssh_get_error(sshbind));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ssh_bind_accept(sshbind, session) == SSH_ERROR) {
|
||||
printf("error accepting a connection : %s\n", ssh_get_error(sshbind));
|
||||
ret = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
ssh_callbacks_init(&cb);
|
||||
ssh_callbacks_init(&cb_gen);
|
||||
ssh_set_server_callbacks(session, &cb);
|
||||
ssh_set_callbacks(session, &cb_gen);
|
||||
ssh_set_message_callback(session, message_callback, (void *)NULL);
|
||||
|
||||
if (ssh_handle_key_exchange(session)) {
|
||||
printf("ssh_handle_key_exchange: %s\n", ssh_get_error(session));
|
||||
ret = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_GSSAPI_MIC);
|
||||
ssh_event_add_session(mainloop, session);
|
||||
|
||||
while (!authenticated) {
|
||||
if (error_set) {
|
||||
break;
|
||||
}
|
||||
if (ssh_event_dopoll(mainloop, -1) == SSH_ERROR) {
|
||||
printf("Error : %s\n", ssh_get_error(session));
|
||||
ret = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
if (error_set) {
|
||||
printf("Error, exiting loop\n");
|
||||
} else {
|
||||
printf("Authenticated and got a channel\n");
|
||||
|
||||
while (!error_set) {
|
||||
if (ssh_event_dopoll(mainloop, 100) == SSH_ERROR) {
|
||||
printf("Error : %s\n", ssh_get_error(session));
|
||||
ret = 1;
|
||||
goto shutdown;
|
||||
}
|
||||
do_cleanup(&cleanup_stack);
|
||||
}
|
||||
}
|
||||
|
||||
shutdown:
|
||||
ssh_disconnect(session);
|
||||
ssh_bind_free(sshbind);
|
||||
ssh_finalize();
|
||||
return ret;
|
||||
}
|
||||
@@ -90,7 +90,6 @@ static void select_loop(ssh_session session,ssh_channel channel){
|
||||
do{
|
||||
int fd;
|
||||
|
||||
ZERO_STRUCT(fds);
|
||||
FD_ZERO(&fds);
|
||||
if(!eof)
|
||||
FD_SET(0,&fds);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "libssh/libmbedcrypto.h"
|
||||
|
||||
bignum ssh_make_string_bn(ssh_string string);
|
||||
void ssh_make_string_bn_inplace(ssh_string string, bignum bnout);
|
||||
ssh_string ssh_make_bignum_string(bignum num);
|
||||
void ssh_print_bignum(const char *which, const bignum num);
|
||||
|
||||
|
||||
@@ -46,9 +46,6 @@ struct ssh_bind_struct {
|
||||
unsigned int bindport;
|
||||
int blocking;
|
||||
int toaccept;
|
||||
bool config_processed;
|
||||
char *config_dir;
|
||||
char *pubkey_accepted_key_types;
|
||||
};
|
||||
|
||||
struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* bind_config.h - Parse the SSH server configuration file
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.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; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef BIND_CONFIG_H_
|
||||
#define BIND_CONFIG_H_
|
||||
|
||||
#include "libssh/server.h"
|
||||
|
||||
enum ssh_bind_config_opcode_e {
|
||||
/* Known but not allowed in Match block */
|
||||
BIND_CFG_NOT_ALLOWED_IN_MATCH = -4,
|
||||
/* Unknown opcode */
|
||||
BIND_CFG_UNKNOWN = -3,
|
||||
/* Known and not applicable to libssh */
|
||||
BIND_CFG_NA = -2,
|
||||
/* Known but not supported by current libssh version */
|
||||
BIND_CFG_UNSUPPORTED = -1,
|
||||
BIND_CFG_INCLUDE,
|
||||
BIND_CFG_HOSTKEY,
|
||||
BIND_CFG_LISTENADDRESS,
|
||||
BIND_CFG_PORT,
|
||||
BIND_CFG_LOGLEVEL,
|
||||
BIND_CFG_CIPHERS,
|
||||
BIND_CFG_MACS,
|
||||
BIND_CFG_KEXALGORITHMS,
|
||||
BIND_CFG_MATCH,
|
||||
BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
BIND_CFG_HOSTKEY_ALGORITHMS,
|
||||
|
||||
BIND_CFG_MAX /* Keep this one last in the list */
|
||||
};
|
||||
|
||||
/* @brief Parse configuration file and set the options to the given ssh_bind
|
||||
*
|
||||
* @params[in] sshbind The ssh_bind context to be configured
|
||||
* @params[in] filename The path to the configuration file
|
||||
*
|
||||
* @returns 0 on successful parsing the configuration file, -1 on error
|
||||
*/
|
||||
int ssh_bind_config_parse_file(ssh_bind sshbind, const char *filename);
|
||||
|
||||
#endif /* BIND_CONFIG_H_ */
|
||||
@@ -40,21 +40,21 @@ void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len);
|
||||
int ssh_buffer_allocate_size(struct ssh_buffer_struct *buffer, uint32_t len);
|
||||
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
va_list ap);
|
||||
int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
...);
|
||||
#define ssh_buffer_pack(buffer, format, ...) \
|
||||
_ssh_buffer_pack((buffer), (format), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, SSH_BUFFER_PACK_END)
|
||||
|
||||
int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format, size_t argc,
|
||||
const char *format, int argc,
|
||||
va_list ap);
|
||||
int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
...);
|
||||
#define ssh_buffer_unpack(buffer, format, ...) \
|
||||
_ssh_buffer_unpack((buffer), (format), __VA_NARG__(__VA_ARGS__), __VA_ARGS__, SSH_BUFFER_PACK_END)
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2018 Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* 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 _BYTEARRAY_H
|
||||
#define _BYTEARRAY_H
|
||||
|
||||
#define _DATA_BYTE_CONST(data, pos) \
|
||||
((uint8_t)(((const uint8_t *)(data))[(pos)]))
|
||||
|
||||
#define _DATA_BYTE(data, pos) \
|
||||
(((uint8_t *)(data))[(pos)])
|
||||
|
||||
/*
|
||||
* These macros pull or push integer values from byte arrays stored in
|
||||
* little-endian byte order.
|
||||
*/
|
||||
#define PULL_LE_U8(data, pos) \
|
||||
(_DATA_BYTE_CONST(data, pos))
|
||||
|
||||
#define PULL_LE_U16(data, pos) \
|
||||
((uint16_t)PULL_LE_U8(data, pos) | ((uint16_t)(PULL_LE_U8(data, (pos) + 1))) << 8)
|
||||
|
||||
#define PULL_LE_U32(data, pos) \
|
||||
((uint32_t)(PULL_LE_U16(data, pos) | ((uint32_t)PULL_LE_U16(data, (pos) + 2)) << 16))
|
||||
|
||||
#define PULL_LE_U64(data, pos) \
|
||||
((uint64_t)(PULL_LE_U32(data, pos) | ((uint64_t)PULL_LE_U32(data, (pos) + 4)) << 32))
|
||||
|
||||
|
||||
#define PUSH_LE_U8(data, pos, val) \
|
||||
(_DATA_BYTE(data, pos) = ((uint8_t)(val)))
|
||||
|
||||
#define PUSH_LE_U16(data, pos, val) \
|
||||
(PUSH_LE_U8((data), (pos), (uint8_t)((uint16_t)(val) & 0xff)), PUSH_LE_U8((data), (pos) + 1, (uint8_t)((uint16_t)(val) >> 8)))
|
||||
|
||||
#define PUSH_LE_U32(data, pos, val) \
|
||||
(PUSH_LE_U16((data), (pos), (uint16_t)((uint32_t)(val) & 0xffff)), PUSH_LE_U16((data), (pos) + 2, (uint16_t)((uint32_t)(val) >> 16)))
|
||||
|
||||
#define PUSH_LE_U64(data, pos, val) \
|
||||
(PUSH_LE_U32((data), (pos), (uint32_t)((uint64_t)(val) & 0xffffffff)), PUSH_LE_U32((data), (pos) + 4, (uint32_t)((uint64_t)(val) >> 32)))
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* These macros pull or push integer values from byte arrays stored in
|
||||
* big-endian byte order (network byte order).
|
||||
*/
|
||||
#define PULL_BE_U8(data, pos) \
|
||||
(_DATA_BYTE_CONST(data, pos))
|
||||
|
||||
#define PULL_BE_U16(data, pos) \
|
||||
((((uint16_t)(PULL_BE_U8(data, pos))) << 8) | (uint16_t)PULL_BE_U8(data, (pos) + 1))
|
||||
|
||||
#define PULL_BE_U32(data, pos) \
|
||||
((((uint32_t)PULL_BE_U16(data, pos)) << 16) | (uint32_t)(PULL_BE_U16(data, (pos) + 2)))
|
||||
|
||||
#define PULL_BE_U64(data, pos) \
|
||||
((((uint64_t)PULL_BE_U32(data, pos)) << 32) | (uint64_t)(PULL_BE_U32(data, (pos) + 4)))
|
||||
|
||||
|
||||
|
||||
#define PUSH_BE_U8(data, pos, val) \
|
||||
(_DATA_BYTE(data, pos) = ((uint8_t)(val)))
|
||||
|
||||
#define PUSH_BE_U16(data, pos, val) \
|
||||
(PUSH_BE_U8((data), (pos), (uint8_t)(((uint16_t)(val)) >> 8)), PUSH_BE_U8((data), (pos) + 1, (uint8_t)((val) & 0xff)))
|
||||
|
||||
#define PUSH_BE_U32(data, pos, val) \
|
||||
(PUSH_BE_U16((data), (pos), (uint16_t)(((uint32_t)(val)) >> 16)), PUSH_BE_U16((data), (pos) + 2, (uint16_t)((val) & 0xffff)))
|
||||
|
||||
#define PUSH_BE_U64(data, pos, val) \
|
||||
(PUSH_BE_U32((data), (pos), (uint32_t)(((uint64_t)(val)) >> 32)), PUSH_BE_U32((data), (pos) + 4, (uint32_t)((val) & 0xffffffff)))
|
||||
|
||||
#endif /* _BYTEARRAY_H */
|
||||
@@ -854,7 +854,7 @@ typedef struct ssh_channel_callbacks_struct *ssh_channel_callbacks;
|
||||
* @code
|
||||
* struct ssh_channel_callbacks_struct cb = {
|
||||
* .userdata = data,
|
||||
* .channel_data_function = my_channel_data_function
|
||||
* .channel_data = my_channel_data_function
|
||||
* };
|
||||
* ssh_callbacks_init(&cb);
|
||||
* ssh_set_channel_callbacks(channel, &cb);
|
||||
@@ -944,20 +944,9 @@ LIBSSH_API int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct
|
||||
*cb);
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the appropriate callbacks structure for the
|
||||
* environment, to be used with ssh_threads_set_callbacks.
|
||||
*
|
||||
* @returns A pointer to a ssh_threads_callbacks_struct to be used with
|
||||
* @brief returns a pointer on the pthread threads callbacks, to be used with
|
||||
* ssh_threads_set_callbacks.
|
||||
*
|
||||
* @see ssh_threads_set_callbacks
|
||||
*/
|
||||
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_default(void);
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer on the pthread threads callbacks, to be used with
|
||||
* ssh_threads_set_callbacks.
|
||||
*
|
||||
* @warning you have to link with the library ssh_threads.
|
||||
* @see ssh_threads_set_callbacks
|
||||
*/
|
||||
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void);
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* config.h - parse the ssh config file
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009-2018 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef LIBSSH_CONFIG_H_
|
||||
#define LIBSSH_CONFIG_H_
|
||||
|
||||
|
||||
enum ssh_config_opcode_e {
|
||||
/* Unknown opcode */
|
||||
SOC_UNKNOWN = -3,
|
||||
/* Known and not applicable to libssh */
|
||||
SOC_NA = -2,
|
||||
/* Known but not supported by current libssh version */
|
||||
SOC_UNSUPPORTED = -1,
|
||||
SOC_HOST,
|
||||
SOC_MATCH,
|
||||
SOC_HOSTNAME,
|
||||
SOC_PORT,
|
||||
SOC_USERNAME,
|
||||
SOC_IDENTITY,
|
||||
SOC_CIPHERS,
|
||||
SOC_MACS,
|
||||
SOC_COMPRESSION,
|
||||
SOC_TIMEOUT,
|
||||
SOC_PROTOCOL,
|
||||
SOC_STRICTHOSTKEYCHECK,
|
||||
SOC_KNOWNHOSTS,
|
||||
SOC_PROXYCOMMAND,
|
||||
SOC_PROXYJUMP,
|
||||
SOC_GSSAPISERVERIDENTITY,
|
||||
SOC_GSSAPICLIENTIDENTITY,
|
||||
SOC_GSSAPIDELEGATECREDENTIALS,
|
||||
SOC_INCLUDE,
|
||||
SOC_BINDADDRESS,
|
||||
SOC_GLOBALKNOWNHOSTSFILE,
|
||||
SOC_LOGLEVEL,
|
||||
SOC_HOSTKEYALGORITHMS,
|
||||
SOC_KEXALGORITHMS,
|
||||
SOC_GSSAPIAUTHENTICATION,
|
||||
SOC_KBDINTERACTIVEAUTHENTICATION,
|
||||
SOC_PASSWORDAUTHENTICATION,
|
||||
SOC_PUBKEYAUTHENTICATION,
|
||||
SOC_PUBKEYACCEPTEDTYPES,
|
||||
SOC_REKEYLIMIT,
|
||||
|
||||
SOC_MAX /* Keep this one last in the list */
|
||||
};
|
||||
#endif /* LIBSSH_CONFIG_H_ */
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* config_parser.h - Common configuration file parser functions
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.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; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_PARSER_H_
|
||||
#define CONFIG_PARSER_H_
|
||||
|
||||
char *ssh_config_get_cmd(char **str);
|
||||
|
||||
char *ssh_config_get_token(char **str);
|
||||
|
||||
long ssh_config_get_long(char **str, long notfound);
|
||||
|
||||
const char *ssh_config_get_str_tok(char **str, const char *def);
|
||||
|
||||
int ssh_config_get_yesno(char **str, int notfound);
|
||||
|
||||
/* @brief Parse SSH URI in format [user@]host[:port] from the given string
|
||||
*
|
||||
* @param[in] tok String to parse
|
||||
* @param[out] username Pointer to the location, where the new username will
|
||||
* be stored or NULL if we do not care about the result.
|
||||
* @param[out] hostname Pointer to the location, where the new hostname will
|
||||
* be stored or NULL if we do not care about the result.
|
||||
* @param[out] port Pointer to the location, where the new port will
|
||||
* be stored or NULL if we do not care about the result.
|
||||
*
|
||||
* @returns SSH_OK if the provided string is in format of SSH URI,
|
||||
* SSH_ERROR on failure
|
||||
*/
|
||||
int ssh_config_parse_uri(const char *tok,
|
||||
char **username,
|
||||
char **hostname,
|
||||
char **port);
|
||||
|
||||
#endif /* LIBSSH_CONFIG_H_ */
|
||||
28
include/libssh/crc32.h
Normal file
28
include/libssh/crc32.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* crc32.c - simple CRC32 code
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2005 by Aris Adamantiadis
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _CRC32_H
|
||||
#define _CRC32_H
|
||||
|
||||
uint32_t ssh_crc32(const char *buf, uint32_t len);
|
||||
|
||||
#endif /* _CRC32_H */
|
||||
@@ -25,13 +25,10 @@
|
||||
#ifndef _CRYPTO_H_
|
||||
#define _CRYPTO_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||
#include <mbedtls/gcm.h>
|
||||
#endif
|
||||
#include "libssh/wrapper.h"
|
||||
|
||||
@@ -45,27 +42,17 @@
|
||||
#ifdef HAVE_OPENSSL_ECDH_H
|
||||
#include <openssl/ecdh.h>
|
||||
#endif
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/kex.h"
|
||||
#include "libssh/curve25519.h"
|
||||
|
||||
#define DIGEST_MAX_LEN 64
|
||||
|
||||
#define AES_GCM_TAGLEN 16
|
||||
#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,
|
||||
#ifdef WITH_GEX
|
||||
/* 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 */
|
||||
@@ -84,29 +71,18 @@ enum ssh_key_exchange_e {
|
||||
|
||||
enum ssh_cipher_e {
|
||||
SSH_NO_CIPHER=0,
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
SSH_BLOWFISH_CBC,
|
||||
#endif /* WITH_BLOWFISH_CIPHER */
|
||||
SSH_3DES_CBC,
|
||||
SSH_AES128_CBC,
|
||||
SSH_AES192_CBC,
|
||||
SSH_AES256_CBC,
|
||||
SSH_AES128_CTR,
|
||||
SSH_AES192_CTR,
|
||||
SSH_AES256_CTR,
|
||||
SSH_AEAD_AES128_GCM,
|
||||
SSH_AEAD_AES256_GCM,
|
||||
SSH_AEAD_CHACHA20_POLY1305
|
||||
SSH_AES256_CTR
|
||||
};
|
||||
|
||||
struct dh_ctx;
|
||||
|
||||
struct ssh_crypto_struct {
|
||||
bignum shared_secret;
|
||||
struct dh_ctx *dh_ctx;
|
||||
#ifdef WITH_GEX
|
||||
size_t dh_pmin; int dh_pn; int dh_pmax; /* preferred group parameters */
|
||||
#endif /* WITH_GEX */
|
||||
bignum e,f,x,k,y;
|
||||
#ifdef HAVE_ECDH
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
EC_KEY *ecdh_privkey;
|
||||
@@ -124,7 +100,7 @@ struct ssh_crypto_struct {
|
||||
ssh_curve25519_pubkey curve25519_server_pubkey;
|
||||
#endif
|
||||
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
||||
size_t digest_len; /* len of the two fields below */
|
||||
size_t digest_len; /* len of all the fields below */
|
||||
unsigned char *session_id;
|
||||
unsigned char *secret_hash; /* Secret hash is same as session id until re-kex */
|
||||
unsigned char *encryptIV;
|
||||
@@ -136,7 +112,6 @@ struct ssh_crypto_struct {
|
||||
unsigned char hmacbuf[DIGEST_MAX_LEN];
|
||||
struct ssh_cipher_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
|
||||
enum ssh_hmac_e in_hmac, out_hmac; /* the MAC algorithms used */
|
||||
bool in_hmac_etm, out_hmac_etm; /* Whether EtM mode is used or not */
|
||||
|
||||
ssh_key server_pubkey;
|
||||
int do_compress_out; /* idem */
|
||||
@@ -150,8 +125,7 @@ struct ssh_crypto_struct {
|
||||
struct ssh_kex_struct client_kex;
|
||||
char *kex_methods[SSH_KEX_METHODS];
|
||||
enum ssh_key_exchange_e kex_type;
|
||||
enum ssh_kdf_digest digest_type; /* Digest type for session keys derivation */
|
||||
enum ssh_crypto_direction_e used; /* Is this crypto still used for either of directions? */
|
||||
enum ssh_mac_e mac_type; /* Mac operations to use for key gen */
|
||||
};
|
||||
|
||||
struct ssh_cipher_struct {
|
||||
@@ -162,7 +136,6 @@ struct ssh_cipher_struct {
|
||||
size_t keylen; /* length of the key structure */
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_cipher_hd_t *key;
|
||||
unsigned char last_iv[AES_GCM_IVLEN];
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
struct ssh_3des_key_schedule *des3_key;
|
||||
struct ssh_aes_key_schedule *aes_key;
|
||||
@@ -172,30 +145,17 @@ struct ssh_cipher_struct {
|
||||
mbedtls_cipher_context_t encrypt_ctx;
|
||||
mbedtls_cipher_context_t decrypt_ctx;
|
||||
mbedtls_cipher_type_t type;
|
||||
#ifdef MBEDTLS_GCM_C
|
||||
mbedtls_gcm_context gcm_ctx;
|
||||
unsigned char last_iv[AES_GCM_IVLEN];
|
||||
#endif /* MBEDTLS_GCM_C */
|
||||
#endif
|
||||
struct chacha20_poly1305_keysched *chacha20_schedule;
|
||||
unsigned int keysize; /* bytes of key used. != keylen */
|
||||
size_t tag_size; /* overhead required for tag */
|
||||
/* Counters for rekeying initialization */
|
||||
uint32_t packets;
|
||||
uint64_t blocks;
|
||||
/* Rekeying limit for the cipher or manually enforced */
|
||||
uint64_t max_blocks;
|
||||
/* sets the new key for immediate use */
|
||||
int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
||||
int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
||||
void (*encrypt)(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len);
|
||||
void (*decrypt)(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len);
|
||||
void (*encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len);
|
||||
void (*decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len);
|
||||
void (*aead_encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
size_t len, uint8_t *mac, uint64_t seq);
|
||||
int (*aead_decrypt_length)(struct ssh_cipher_struct *cipher, void *in,
|
||||
@@ -206,9 +166,5 @@ struct ssh_cipher_struct {
|
||||
};
|
||||
|
||||
const struct ssh_cipher_struct *ssh_get_chacha20poly1305_cipher(void);
|
||||
int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len);
|
||||
|
||||
#endif /* _CRYPTO_H_ */
|
||||
|
||||
@@ -48,9 +48,10 @@ typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
|
||||
|
||||
|
||||
int ssh_client_curve25519_init(ssh_session session);
|
||||
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
void ssh_server_curve25519_init(ssh_session session);
|
||||
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* CURVE25519_H_ */
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2016 by Aris Adamantiadis <aris@0xbadc0de.be>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SRC_DH_GEX_H_
|
||||
#define SRC_DH_GEX_H_
|
||||
|
||||
int ssh_client_dhgex_init(ssh_session session);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
void ssh_server_dhgex_init(ssh_session session);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* SRC_DH_GEX_H_ */
|
||||
@@ -25,35 +25,25 @@
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
struct dh_ctx;
|
||||
int ssh_dh_generate_e(ssh_session session);
|
||||
int ssh_dh_generate_f(ssh_session session);
|
||||
int ssh_dh_generate_x(ssh_session session);
|
||||
int ssh_dh_generate_y(ssh_session session);
|
||||
|
||||
#define DH_CLIENT_KEYPAIR 0
|
||||
#define DH_SERVER_KEYPAIR 1
|
||||
|
||||
/* functions implemented by crypto backends */
|
||||
int ssh_dh_init_common(struct ssh_crypto_struct *crypto);
|
||||
void ssh_dh_cleanup(struct ssh_crypto_struct *crypto);
|
||||
|
||||
int ssh_dh_get_parameters(struct dh_ctx *ctx,
|
||||
const_bignum *modulus, const_bignum *generator);
|
||||
int ssh_dh_set_parameters(struct dh_ctx *ctx,
|
||||
const bignum modulus, const bignum generator);
|
||||
|
||||
int ssh_dh_keypair_gen_keys(struct dh_ctx *ctx, int peer);
|
||||
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
|
||||
const_bignum *priv, const_bignum *pub);
|
||||
int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
|
||||
const bignum priv, const bignum pub);
|
||||
|
||||
int ssh_dh_compute_shared_secret(struct dh_ctx *ctx, int local, int remote,
|
||||
bignum *dest);
|
||||
|
||||
/* common functions */
|
||||
int ssh_dh_init(void);
|
||||
void ssh_dh_finalize(void);
|
||||
|
||||
int ssh_dh_import_next_pubkey_blob(ssh_session session,
|
||||
ssh_string pubkey_blob);
|
||||
ssh_string ssh_dh_get_e(ssh_session session);
|
||||
ssh_string ssh_dh_get_f(ssh_session session);
|
||||
int ssh_dh_import_f(ssh_session session,ssh_string f_string);
|
||||
int ssh_dh_import_e(ssh_session session, ssh_string e_string);
|
||||
|
||||
int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
|
||||
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
|
||||
|
||||
int ssh_dh_build_k(ssh_session session);
|
||||
int ssh_client_dh_init(ssh_session session);
|
||||
int ssh_client_dh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
ssh_key ssh_dh_get_current_server_publickey(ssh_session session);
|
||||
int ssh_dh_get_current_server_publickey_blob(ssh_session session,
|
||||
@@ -62,12 +52,10 @@ ssh_key ssh_dh_get_next_server_publickey(ssh_session session);
|
||||
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
|
||||
ssh_string *pubkey_blob);
|
||||
|
||||
int ssh_client_dh_init(ssh_session session);
|
||||
#ifdef WITH_SERVER
|
||||
void ssh_server_dh_init(ssh_session session);
|
||||
#endif /* WITH_SERVER */
|
||||
int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet);
|
||||
int ssh_fallback_group(uint32_t pmax, bignum *p, bignum *g);
|
||||
bool ssh_dh_is_known_group(bignum modulus, bignum generator);
|
||||
int ssh_make_sessionid(ssh_session session);
|
||||
/* add data for the final cookie */
|
||||
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
int ssh_hashbufout_add_cookie(ssh_session session);
|
||||
int ssh_generate_session_keys(ssh_session session);
|
||||
|
||||
#endif /* DH_H_ */
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define ECDH_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/callbacks.h"
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#ifdef HAVE_OPENSSL_ECDH_H
|
||||
@@ -42,15 +41,15 @@
|
||||
#define HAVE_ECDH 1
|
||||
#endif
|
||||
|
||||
extern struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks;
|
||||
/* Common functions. */
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet);
|
||||
|
||||
/* Backend-specific functions. */
|
||||
int ssh_client_ecdh_init(ssh_session session);
|
||||
int ecdh_build_k(ssh_session session);
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
extern struct ssh_packet_callbacks_struct ssh_ecdh_server_callbacks;
|
||||
void ssh_server_ecdh_init(ssh_session session);
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init);
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
#endif /* ECDH_H_ */
|
||||
|
||||
@@ -56,8 +56,8 @@ int crypto_sign_ed25519_keypair(ed25519_pubkey pk, ed25519_privkey sk);
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int crypto_sign_ed25519(
|
||||
unsigned char *sm, uint64_t *smlen,
|
||||
const unsigned char *m, uint64_t mlen,
|
||||
unsigned char *sm,unsigned long long *smlen,
|
||||
const unsigned char *m,unsigned long long mlen,
|
||||
const ed25519_privkey sk);
|
||||
|
||||
/** @internal
|
||||
@@ -71,8 +71,8 @@ int crypto_sign_ed25519(
|
||||
* @returns 0 on success (supposedly).
|
||||
*/
|
||||
int crypto_sign_ed25519_open(
|
||||
unsigned char *m, uint64_t *mlen,
|
||||
const unsigned char *sm, uint64_t smlen,
|
||||
unsigned char *m,unsigned long long *mlen,
|
||||
const unsigned char *sm,unsigned long long smlen,
|
||||
const ed25519_pubkey pk);
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -39,21 +39,12 @@ int ssh_set_client_kex(ssh_session session);
|
||||
int ssh_kex_select_methods(ssh_session session);
|
||||
int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name);
|
||||
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list);
|
||||
char *ssh_keep_fips_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);
|
||||
char *ssh_client_select_hostkeys(ssh_session session);
|
||||
int ssh_send_rekex(ssh_session session);
|
||||
int server_set_kex(ssh_session session);
|
||||
int ssh_make_sessionid(ssh_session session);
|
||||
/* add data for the final cookie */
|
||||
int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
|
||||
int ssh_hashbufout_add_cookie(ssh_session session);
|
||||
int ssh_generate_session_keys(ssh_session session);
|
||||
|
||||
#endif /* KEX_H_ */
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
typedef EVP_MD_CTX* SHACTX;
|
||||
typedef EVP_MD_CTX* SHA256CTX;
|
||||
@@ -65,7 +64,6 @@ typedef void *EVPCTX;
|
||||
#define BROKEN_AES_CTR
|
||||
#endif
|
||||
typedef BIGNUM* bignum;
|
||||
typedef const BIGNUM* const_bignum;
|
||||
typedef BN_CTX* bignum_CTX;
|
||||
|
||||
#define bignum_new() BN_new()
|
||||
@@ -76,43 +74,19 @@ typedef BN_CTX* bignum_CTX;
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_set_word(bn,n) BN_set_word(bn,n)
|
||||
#define bignum_bin2bn(data, datalen, dest) \
|
||||
do { \
|
||||
(*dest) = BN_new(); \
|
||||
if ((*dest) != NULL) { \
|
||||
BN_bin2bn(data,datalen,(*dest)); \
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
|
||||
#define bignum_bn2dec(num) BN_bn2dec(num)
|
||||
#define bignum_dec2bn(data, bn) BN_dec2bn(bn, data)
|
||||
#define bignum_hex2bn(data, bn) BN_hex2bn(bn, data)
|
||||
#define bignum_bn2hex(num, dest) (*dest)=(unsigned char *)BN_bn2hex(num)
|
||||
#define bignum_dec2bn(bn,data) BN_dec2bn(data,bn)
|
||||
#define bignum_bn2hex(num) BN_bn2hex(num)
|
||||
#define bignum_rand(rnd, bits) BN_rand(rnd, bits, 0, 1)
|
||||
#define bignum_rand_range(rnd, max) BN_rand_range(rnd, max)
|
||||
#define bignum_ctx_new() BN_CTX_new()
|
||||
#define bignum_ctx_free(num) BN_CTX_free(num)
|
||||
#define bignum_ctx_invalid(ctx) ((ctx) == NULL)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
|
||||
#define bignum_add(dest, a, b) BN_add(dest, a, b)
|
||||
#define bignum_sub(dest, a, b) BN_sub(dest, a, b)
|
||||
#define bignum_mod(dest, a, b, ctx) BN_mod(dest, a, b, ctx)
|
||||
#define bignum_num_bytes(num) BN_num_bytes(num)
|
||||
#define bignum_num_bits(num) BN_num_bits(num)
|
||||
#define bignum_is_bit_set(num,bit) BN_is_bit_set(num,bit)
|
||||
#define bignum_bn2bin(num,len, ptr) BN_bn2bin(num, ptr)
|
||||
#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
|
||||
#define bignum_cmp(num1,num2) BN_cmp(num1,num2)
|
||||
#define bignum_rshift1(dest, src) BN_rshift1(dest, src)
|
||||
#define bignum_dup(orig, dest) do { \
|
||||
if (*(dest) == NULL) { \
|
||||
*(dest) = BN_dup(orig); \
|
||||
} else { \
|
||||
BN_copy(*(dest), orig); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* Returns true if the OpenSSL is operating in FIPS mode */
|
||||
#define ssh_fips_mode() (FIPS_mode() != 0)
|
||||
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
|
||||
@@ -50,8 +50,6 @@ typedef gcry_md_hd_t EVPCTX;
|
||||
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
||||
|
||||
typedef gcry_mpi_t bignum;
|
||||
typedef const struct gcry_mpi *const_bignum;
|
||||
typedef void* bignum_CTX;
|
||||
|
||||
/* Constants for curves. */
|
||||
#define NID_gcrypt_nistp256 0
|
||||
@@ -61,7 +59,6 @@ typedef void* bignum_CTX;
|
||||
/* missing gcrypt functions */
|
||||
int ssh_gcry_dec2bn(bignum *bn, const char *data);
|
||||
char *ssh_gcry_bn2dec(bignum bn);
|
||||
int ssh_gcry_rand_range(bignum rnd, bignum max);
|
||||
|
||||
#define bignum_new() gcry_mpi_new(0)
|
||||
#define bignum_safe_free(num) do { \
|
||||
@@ -70,35 +67,20 @@ int ssh_gcry_rand_range(bignum rnd, bignum max);
|
||||
(num)=NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
#define bignum_free(num) gcry_mpi_release(num)
|
||||
#define bignum_ctx_new() NULL
|
||||
#define bignum_ctx_free(ctx) do {(ctx) = NULL;} while(0)
|
||||
#define bignum_ctx_invalid(ctx) (ctx != NULL)
|
||||
#define bignum_set_word(bn,n) (gcry_mpi_set_ui(bn,n)!=NULL ? 1 : 0)
|
||||
#define bignum_bin2bn(data,datalen,dest) gcry_mpi_scan(dest,GCRYMPI_FMT_USG,data,datalen,NULL)
|
||||
#define bignum_set_word(bn,n) gcry_mpi_set_ui(bn,n)
|
||||
#define bignum_bin2bn(bn,datalen,data) gcry_mpi_scan(data,GCRYMPI_FMT_USG,bn,datalen,NULL)
|
||||
#define bignum_bn2dec(num) ssh_gcry_bn2dec(num)
|
||||
#define bignum_dec2bn(num, data) ssh_gcry_dec2bn(data, num)
|
||||
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
|
||||
#define bignum_hex2bn(data, num) (gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,0,NULL)==0?1:0)
|
||||
#define bignum_rand(num,bits) 1,gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo, ctx) 1,gcry_mpi_powm(dest,generator,exp,modulo)
|
||||
#define bignum_hex2bn(num,datalen,data) gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,datalen,NULL)
|
||||
#define bignum_rand(num,bits) gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
|
||||
#define bignum_mod_exp(dest,generator,exp,modulo) gcry_mpi_powm(dest,generator,exp,modulo)
|
||||
#define bignum_num_bits(num) gcry_mpi_get_nbits(num)
|
||||
#define bignum_num_bytes(num) ((gcry_mpi_get_nbits(num)+7)/8)
|
||||
#define bignum_is_bit_set(num,bit) gcry_mpi_test_bit(num,bit)
|
||||
#define bignum_bn2bin(num,datalen,data) gcry_mpi_print(GCRYMPI_FMT_USG,data,datalen,NULL,num)
|
||||
#define bignum_cmp(num1,num2) gcry_mpi_cmp(num1,num2)
|
||||
#define bignum_rshift1(dest, src) gcry_mpi_rshift (dest, src, 1)
|
||||
#define bignum_add(dst, a, b) gcry_mpi_add(dst, a, b)
|
||||
#define bignum_sub(dst, a, b) gcry_mpi_sub(dst, a, b)
|
||||
#define bignum_mod(dst, a, b, ctx) 1,gcry_mpi_mod(dst, a, b)
|
||||
#define bignum_rand_range(rnd, max) ssh_gcry_rand_range(rnd, max);
|
||||
#define bignum_dup(orig, dest) do { \
|
||||
if (*(dest) == NULL) { \
|
||||
*(dest) = gcry_mpi_copy(orig); \
|
||||
} else { \
|
||||
gcry_mpi_set(*(dest), orig); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Helper functions for data conversions. */
|
||||
|
||||
/* Extract an MPI from the given s-expression SEXP named NAME which is
|
||||
@@ -109,8 +91,6 @@ ssh_string ssh_sexp_extract_mpi(const gcry_sexp_t sexp,
|
||||
enum gcry_mpi_format informat,
|
||||
enum gcry_mpi_format outformat);
|
||||
|
||||
#define ssh_fips_mode() false
|
||||
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
|
||||
#endif /* LIBGCRYPT_H_ */
|
||||
|
||||
@@ -60,8 +60,6 @@ typedef mbedtls_md_context_t *EVPCTX;
|
||||
#define EVP_DIGEST_LEN EVP_MAX_MD_SIZE
|
||||
|
||||
typedef mbedtls_mpi *bignum;
|
||||
typedef const mbedtls_mpi *const_bignum;
|
||||
typedef void* bignum_CTX;
|
||||
|
||||
/* Constants for curves */
|
||||
#define NID_mbedtls_nistp256 0
|
||||
@@ -75,11 +73,9 @@ struct mbedtls_ecdsa_sig {
|
||||
|
||||
bignum ssh_mbedcry_bn_new(void);
|
||||
void ssh_mbedcry_bn_free(bignum num);
|
||||
unsigned char *ssh_mbedcry_bn2num(bignum num, int radix);
|
||||
char *ssh_mbedcry_bn2num(bignum num, int radix);
|
||||
int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
|
||||
int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
|
||||
int ssh_mbedcry_rand_range(bignum dest, bignum max);
|
||||
int ssh_mbedcry_hex2bn(bignum *dest, char *data);
|
||||
|
||||
#define bignum_new() ssh_mbedcry_bn_new()
|
||||
#define bignum_safe_free(num) do { \
|
||||
@@ -88,44 +84,22 @@ int ssh_mbedcry_hex2bn(bignum *dest, char *data);
|
||||
(num)=NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_ctx_new() NULL
|
||||
#define bignum_ctx_free(num) do {(num) = NULL;} while(0)
|
||||
#define bignum_ctx_invalid(ctx) (ctx == NULL?0:1)
|
||||
#define bignum_set_word(bn, n) (mbedtls_mpi_lset(bn, n)==0?1:0) /* TODO fix
|
||||
#define bignum_set_word(bn, n) mbedtls_mpi_lset(bn, n) /* TODO fix
|
||||
overflow/underflow */
|
||||
#define bignum_bin2bn(data, datalen, bn) do { \
|
||||
*(bn) = bignum_new(); \
|
||||
if (*(bn) != NULL) { \
|
||||
mbedtls_mpi_read_binary(*(bn), data, datalen); \
|
||||
} \
|
||||
} while(0)
|
||||
#define bignum_bin2bn(data, datalen, bn) mbedtls_mpi_read_binary(bn, data, \
|
||||
datalen)
|
||||
#define bignum_bn2dec(num) ssh_mbedcry_bn2num(num, 10)
|
||||
#define bignum_dec2bn(data, bn) mbedtls_mpi_read_string(bn, 10, data)
|
||||
#define bignum_bn2hex(num, dest) (*dest)=ssh_mbedcry_bn2num(num, 16)
|
||||
#define bignum_hex2bn(data, dest) ssh_mbedcry_hex2bn(dest, data)
|
||||
#define bignum_bn2hex(num) ssh_mbedcry_bn2num(num, 16)
|
||||
#define bignum_rand(rnd, bits) ssh_mbedcry_rand((rnd), (bits), 0, 1)
|
||||
#define bignum_rand_range(rnd, max) ssh_mbedcry_rand_range(rnd, max)
|
||||
#define bignum_mod_exp(dest, generator, exp, modulo, ctx) \
|
||||
(mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL)==0?1:0)
|
||||
#define bignum_add(dest, a, b) mbedtls_mpi_add_mpi(dest, a, b)
|
||||
#define bignum_sub(dest, a, b) mbedtls_mpi_sub_mpi(dest, a, b)
|
||||
#define bignum_mod(dest, a, b, ctx) \
|
||||
(mbedtls_mpi_mod_mpi(dest, a, b) == 0 ? 1 : 0)
|
||||
mbedtls_mpi_exp_mod(dest, generator, exp, modulo, NULL)
|
||||
#define bignum_num_bytes(num) mbedtls_mpi_size(num)
|
||||
#define bignum_num_bits(num) mbedtls_mpi_bitlen(num)
|
||||
#define bignum_is_bit_set(num, bit) ssh_mbedcry_is_bit_set(num, bit)
|
||||
#define bignum_bn2bin(num, len, ptr) mbedtls_mpi_write_binary(num, ptr, \
|
||||
#define bignum_bn2bin(num, ptr) mbedtls_mpi_write_binary(num, ptr, \
|
||||
mbedtls_mpi_size(num))
|
||||
#define bignum_cmp(num1, num2) mbedtls_mpi_cmp_mpi(num1, num2)
|
||||
#define bignum_rshift1(dest, src) mbedtls_mpi_copy(dest, src), mbedtls_mpi_shift_r(dest, 1)
|
||||
#define bignum_dup(orig, dest) do { \
|
||||
if (*(dest) == NULL) { \
|
||||
*(dest) = bignum_new(); \
|
||||
} \
|
||||
if (*(dest) != NULL) { \
|
||||
mbedtls_mpi_copy(orig, *(dest)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
mbedtls_ctr_drbg_context *ssh_get_mbedtls_ctr_drbg_context(void);
|
||||
|
||||
@@ -134,7 +108,5 @@ int ssh_mbedtls_random(void *where, int len, int strong);
|
||||
ssh_string make_ecpoint_string(const mbedtls_ecp_group *g, const
|
||||
mbedtls_ecp_point *p);
|
||||
|
||||
#define ssh_fips_mode() false
|
||||
|
||||
#endif /* HAVE_LIBMBEDCRYPTO */
|
||||
#endif /* LIBMBEDCRYPTO_H_ */
|
||||
|
||||
@@ -78,8 +78,8 @@
|
||||
|
||||
/* libssh version */
|
||||
#define LIBSSH_VERSION_MAJOR 0
|
||||
#define LIBSSH_VERSION_MINOR 9
|
||||
#define LIBSSH_VERSION_MICRO 0
|
||||
#define LIBSSH_VERSION_MINOR 8
|
||||
#define LIBSSH_VERSION_MICRO 7
|
||||
|
||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||
LIBSSH_VERSION_MINOR, \
|
||||
@@ -293,17 +293,10 @@ enum ssh_keytypes_e{
|
||||
SSH_KEYTYPE_DSS=1,
|
||||
SSH_KEYTYPE_RSA,
|
||||
SSH_KEYTYPE_RSA1,
|
||||
SSH_KEYTYPE_ECDSA, /* deprecated */
|
||||
SSH_KEYTYPE_ECDSA,
|
||||
SSH_KEYTYPE_ED25519,
|
||||
SSH_KEYTYPE_DSS_CERT01,
|
||||
SSH_KEYTYPE_RSA_CERT01,
|
||||
SSH_KEYTYPE_ECDSA_P256,
|
||||
SSH_KEYTYPE_ECDSA_P384,
|
||||
SSH_KEYTYPE_ECDSA_P521,
|
||||
SSH_KEYTYPE_ECDSA_P256_CERT01,
|
||||
SSH_KEYTYPE_ECDSA_P384_CERT01,
|
||||
SSH_KEYTYPE_ECDSA_P521_CERT01,
|
||||
SSH_KEYTYPE_ED25519_CERT01,
|
||||
SSH_KEYTYPE_RSA_CERT01
|
||||
};
|
||||
|
||||
enum ssh_keycmp_e {
|
||||
@@ -412,9 +405,6 @@ enum ssh_options_e {
|
||||
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
|
||||
SSH_OPTIONS_NODELAY,
|
||||
SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
|
||||
SSH_OPTIONS_PROCESS_CONFIG,
|
||||
SSH_OPTIONS_REKEY_DATA,
|
||||
SSH_OPTIONS_REKEY_TIME,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -461,8 +451,6 @@ LIBSSH_API ssh_channel ssh_channel_new(ssh_session session);
|
||||
LIBSSH_API int ssh_channel_open_auth_agent(ssh_channel channel);
|
||||
LIBSSH_API int ssh_channel_open_forward(ssh_channel channel, const char *remotehost,
|
||||
int remoteport, const char *sourcehost, int localport);
|
||||
LIBSSH_API int ssh_channel_open_forward_unix(ssh_channel channel, const char *remotepath,
|
||||
const char *sourcehost, int localport);
|
||||
LIBSSH_API int ssh_channel_open_session(ssh_channel channel);
|
||||
LIBSSH_API int ssh_channel_open_x11(ssh_channel channel, const char *orig_addr, int orig_port);
|
||||
LIBSSH_API int ssh_channel_poll(ssh_channel channel, int is_stderr);
|
||||
@@ -555,11 +543,6 @@ SSH_DEPRECATED LIBSSH_API ssh_channel ssh_forward_accept(ssh_session session, in
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_forward_cancel(ssh_session session, const char *address, int port);
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port);
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key);
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_write_knownhost(ssh_session session);
|
||||
SSH_DEPRECATED LIBSSH_API char *ssh_dump_knownhost(ssh_session session);
|
||||
SSH_DEPRECATED LIBSSH_API int ssh_is_server_known(ssh_session session);
|
||||
SSH_DEPRECATED LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
|
||||
|
||||
|
||||
|
||||
LIBSSH_API int ssh_get_random(void *where,int len,int strong);
|
||||
@@ -569,6 +552,7 @@ LIBSSH_API int ssh_get_poll_flags(ssh_session session);
|
||||
LIBSSH_API int ssh_init(void);
|
||||
LIBSSH_API int ssh_is_blocking(ssh_session session);
|
||||
LIBSSH_API int ssh_is_connected(ssh_session session);
|
||||
LIBSSH_API int ssh_is_server_known(ssh_session session);
|
||||
|
||||
/* KNOWN HOSTS */
|
||||
LIBSSH_API void ssh_knownhosts_entry_free(struct ssh_knownhosts_entry *entry);
|
||||
@@ -588,8 +572,9 @@ LIBSSH_API int ssh_session_export_known_hosts_entry(ssh_session session,
|
||||
char **pentry_string);
|
||||
LIBSSH_API int ssh_session_update_known_hosts(ssh_session session);
|
||||
|
||||
LIBSSH_API enum ssh_known_hosts_e ssh_session_get_known_hosts_entry(ssh_session session,
|
||||
struct ssh_knownhosts_entry **pentry);
|
||||
LIBSSH_API enum ssh_known_hosts_e
|
||||
ssh_session_get_known_hosts_entry(ssh_session session,
|
||||
struct ssh_knownhosts_entry **pentry);
|
||||
LIBSSH_API enum ssh_known_hosts_e ssh_session_is_known_server(ssh_session session);
|
||||
|
||||
/* LOGGING */
|
||||
@@ -607,10 +592,7 @@ SSH_DEPRECATED LIBSSH_API void ssh_log(ssh_session session,
|
||||
const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
|
||||
|
||||
LIBSSH_API ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg);
|
||||
LIBSSH_API int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_channel chan);
|
||||
LIBSSH_API int ssh_message_channel_request_reply_success(ssh_message msg);
|
||||
#define SSH_MESSAGE_FREE(x) \
|
||||
do { if ((x) != NULL) { ssh_message_free(x); (x) = NULL; } } while(0)
|
||||
LIBSSH_API void ssh_message_free(ssh_message msg);
|
||||
LIBSSH_API ssh_message ssh_message_get(ssh_session session);
|
||||
LIBSSH_API int ssh_message_subtype(ssh_message msg);
|
||||
@@ -711,6 +693,7 @@ LIBSSH_API char *ssh_get_fingerprint_hash(enum ssh_publickey_hash_type type,
|
||||
unsigned char *hash,
|
||||
size_t len);
|
||||
LIBSSH_API void ssh_print_hash(enum ssh_publickey_hash_type type, unsigned char *hash, size_t len);
|
||||
LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
|
||||
LIBSSH_API int ssh_send_ignore (ssh_session session, const char *data);
|
||||
LIBSSH_API int ssh_send_debug (ssh_session session, const char *message, int always_display);
|
||||
LIBSSH_API void ssh_gssapi_set_creds(ssh_session session, const ssh_gssapi_creds creds);
|
||||
@@ -777,6 +760,8 @@ LIBSSH_API int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i
|
||||
const char *answer);
|
||||
LIBSSH_API int ssh_userauth_gssapi(ssh_session session);
|
||||
LIBSSH_API const char *ssh_version(int req_version);
|
||||
LIBSSH_API int ssh_write_knownhost(ssh_session session);
|
||||
LIBSSH_API char *ssh_dump_knownhost(ssh_session session);
|
||||
|
||||
LIBSSH_API void ssh_string_burn(ssh_string str);
|
||||
LIBSSH_API ssh_string ssh_string_copy(ssh_string str);
|
||||
|
||||
@@ -212,7 +212,7 @@ public:
|
||||
* @see ssh_userauth_kbdint
|
||||
*/
|
||||
int userauthKbdint(const char* username, const char* submethods){
|
||||
int ret = ssh_userauth_kbdint(c_session, username, submethods);
|
||||
int ret=ssh_userauth_kbdint(c_session,NULL,NULL);
|
||||
ssh_throw(ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -407,7 +407,7 @@ public:
|
||||
* @see ssh_write_knownhost
|
||||
*/
|
||||
int writeKnownhost(){
|
||||
int ret = ssh_session_update_known_hosts(c_session);
|
||||
int ret = ssh_write_knownhost(c_session);
|
||||
ssh_throw(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request);
|
||||
|
||||
int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel, ssh_buffer packet,
|
||||
const char *request, uint8_t want_reply);
|
||||
void ssh_message_queue(ssh_session session, ssh_message message);
|
||||
ssh_message ssh_message_pop_head(ssh_session session);
|
||||
int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_channel chan);
|
||||
|
||||
#endif /* MESSAGES_H_ */
|
||||
|
||||
@@ -81,6 +81,4 @@ int ssh_timeout_update(struct ssh_timestamp *ts, int timeout);
|
||||
|
||||
int ssh_match_group(const char *group, const char *object);
|
||||
|
||||
void uint64_inc(unsigned char *counter);
|
||||
|
||||
#endif /* MISC_H_ */
|
||||
|
||||
@@ -70,7 +70,6 @@ int ssh_packet_parse_type(ssh_session session);
|
||||
int ssh_packet_socket_callback(const void *data, size_t len, void *user);
|
||||
void ssh_packet_register_socket_callback(ssh_session session, struct ssh_socket_struct *s);
|
||||
void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks);
|
||||
void ssh_packet_remove_callbacks(ssh_session session, ssh_packet_callbacks callbacks);
|
||||
void ssh_packet_set_default_callbacks(ssh_session session);
|
||||
void ssh_packet_process(ssh_session session, uint8_t type);
|
||||
|
||||
@@ -81,11 +80,7 @@ int ssh_packet_decrypt(ssh_session session, uint8_t *destination, uint8_t *sourc
|
||||
unsigned char *ssh_packet_encrypt(ssh_session session,
|
||||
void *packet,
|
||||
unsigned int len);
|
||||
int ssh_packet_hmac_verify(ssh_session session, const void *data, size_t len,
|
||||
int ssh_packet_hmac_verify(ssh_session session,ssh_buffer buffer,
|
||||
unsigned char *mac, enum ssh_hmac_e type);
|
||||
int ssh_packet_set_newkeys(ssh_session session,
|
||||
enum ssh_crypto_direction_e direction);
|
||||
struct ssh_crypto_struct *ssh_packet_get_current_crypto(ssh_session session,
|
||||
enum ssh_crypto_direction_e direction);
|
||||
|
||||
#endif /* PACKET_H_ */
|
||||
|
||||
@@ -44,23 +44,23 @@ struct ssh_key_struct {
|
||||
int flags;
|
||||
const char *type_c; /* Don't free it ! it is static */
|
||||
int ecdsa_nid;
|
||||
#if defined(HAVE_LIBGCRYPT)
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa;
|
||||
gcry_sexp_t rsa;
|
||||
gcry_sexp_t ecdsa;
|
||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
mbedtls_pk_context *rsa;
|
||||
mbedtls_ecdsa_context *ecdsa;
|
||||
void *dsa;
|
||||
#elif defined(HAVE_LIBCRYPTO)
|
||||
#elif HAVE_LIBCRYPTO
|
||||
DSA *dsa;
|
||||
RSA *rsa;
|
||||
# if defined(HAVE_OPENSSL_ECC)
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
EC_KEY *ecdsa;
|
||||
# else
|
||||
#else
|
||||
void *ecdsa;
|
||||
# endif /* HAVE_OPENSSL_EC_H */
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
#endif /* HAVE_OPENSSL_EC_H */
|
||||
#endif
|
||||
ed25519_pubkey *ed25519_pubkey;
|
||||
ed25519_privkey *ed25519_privkey;
|
||||
void *cert;
|
||||
@@ -71,16 +71,23 @@ struct ssh_signature_struct {
|
||||
enum ssh_keytypes_e type;
|
||||
enum ssh_digest_e hash_type;
|
||||
const char *type_c;
|
||||
#if defined(HAVE_LIBGCRYPT)
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
gcry_sexp_t dsa_sig;
|
||||
gcry_sexp_t rsa_sig;
|
||||
gcry_sexp_t ecdsa_sig;
|
||||
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
DSA_SIG *dsa_sig;
|
||||
ssh_string rsa_sig;
|
||||
# ifdef HAVE_OPENSSL_ECC
|
||||
ECDSA_SIG *ecdsa_sig;
|
||||
# else
|
||||
void *ecdsa_sig;
|
||||
# endif
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
ssh_string rsa_sig;
|
||||
struct mbedtls_ecdsa_sig ecdsa_sig;
|
||||
#endif /* HAVE_LIBGCRYPT */
|
||||
#endif
|
||||
ed25519_signature *ed25519_sig;
|
||||
ssh_string raw_sig;
|
||||
};
|
||||
|
||||
typedef struct ssh_signature_struct *ssh_signature;
|
||||
@@ -93,18 +100,6 @@ const char *
|
||||
ssh_key_get_signature_algorithm(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name);
|
||||
enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type);
|
||||
enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
|
||||
enum ssh_keytypes_e type);
|
||||
|
||||
#define is_ecdsa_key_type(t) \
|
||||
((t) >= SSH_KEYTYPE_ECDSA_P256 && (t) <= SSH_KEYTYPE_ECDSA_P521)
|
||||
|
||||
#define is_cert_type(kt)\
|
||||
((kt) == SSH_KEYTYPE_DSS_CERT01 ||\
|
||||
(kt) == SSH_KEYTYPE_RSA_CERT01 ||\
|
||||
((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\
|
||||
(kt) <= SSH_KEYTYPE_ED25519_CERT01))
|
||||
|
||||
/* SSH Signature Functions */
|
||||
ssh_signature ssh_signature_new(void);
|
||||
@@ -133,7 +128,7 @@ int ssh_pki_import_cert_blob(const ssh_string cert_blob,
|
||||
|
||||
/* SSH Signing Functions */
|
||||
ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf,
|
||||
const ssh_key privatekey, enum ssh_digest_e hash_type);
|
||||
const ssh_key privatekey);
|
||||
ssh_string ssh_pki_do_sign_agent(ssh_session session,
|
||||
struct ssh_buffer_struct *buf,
|
||||
const ssh_key pubkey);
|
||||
|
||||
@@ -61,8 +61,6 @@ int pki_key_compare(const ssh_key k1,
|
||||
const ssh_key k2,
|
||||
enum ssh_keycmp_e what);
|
||||
|
||||
int pki_key_check_hash_compatible(ssh_key key,
|
||||
enum ssh_digest_e hash_type);
|
||||
/* SSH Private Key Functions */
|
||||
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey);
|
||||
ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
@@ -111,14 +109,6 @@ int pki_privkey_build_ecdsa(ssh_key key,
|
||||
ssh_string pki_publickey_to_blob(const ssh_key key);
|
||||
|
||||
/* SSH Signature Functions */
|
||||
ssh_signature pki_sign_data(const ssh_key privkey,
|
||||
enum ssh_digest_e hash_type,
|
||||
const unsigned char *input,
|
||||
size_t input_len);
|
||||
int pki_verify_data_signature(ssh_signature signature,
|
||||
const ssh_key pubkey,
|
||||
const unsigned char *input,
|
||||
size_t input_len);
|
||||
ssh_string pki_signature_to_blob(const ssh_signature sign);
|
||||
ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
const ssh_string sig_blob,
|
||||
@@ -127,18 +117,22 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
int pki_signature_verify(ssh_session session,
|
||||
const ssh_signature sig,
|
||||
const ssh_key key,
|
||||
const unsigned char *input,
|
||||
size_t input_len);
|
||||
const unsigned char *hash,
|
||||
size_t hlen);
|
||||
|
||||
/* SSH Signing Functions */
|
||||
ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
const unsigned char *input,
|
||||
size_t input_len,
|
||||
enum ssh_digest_e hash_type);
|
||||
#define pki_do_sign(key, hash, hlen) \
|
||||
pki_do_sign_hash(key, hash, hlen, SSH_DIGEST_AUTO)
|
||||
ssh_signature pki_do_sign_hash(const ssh_key privkey,
|
||||
const unsigned char *hash,
|
||||
size_t hlen,
|
||||
enum ssh_digest_e hash_type);
|
||||
#define pki_do_sign_sessionid(key, hash, hlen) \
|
||||
pki_do_sign_sessionid_hash(key, hash, hlen, SSH_DIGEST_AUTO)
|
||||
ssh_signature pki_do_sign_sessionid_hash(const ssh_key key,
|
||||
const unsigned char *hash,
|
||||
size_t hlen,
|
||||
enum ssh_digest_e hash_type);
|
||||
int pki_ed25519_sign(const ssh_key privkey, ssh_signature sig,
|
||||
const unsigned char *hash, size_t hlen);
|
||||
int pki_ed25519_verify(const ssh_key pubkey, ssh_signature sig,
|
||||
|
||||
@@ -78,22 +78,6 @@ char *strndup(const char *s, size_t n);
|
||||
# endif /* __WORDSIZE */
|
||||
# endif /* PRIu64 */
|
||||
|
||||
# ifndef PRIu32
|
||||
# define PRIu32 "u"
|
||||
# endif /* PRIu32 */
|
||||
|
||||
# ifndef PRIx64
|
||||
# if __WORDSIZE == 64
|
||||
# define PRIx64 "lx"
|
||||
# else
|
||||
# define PRIx64 "llx"
|
||||
# endif /* __WORDSIZE */
|
||||
# endif /* PRIx64 */
|
||||
|
||||
# ifndef PRIx32
|
||||
# define PRIx32 "x"
|
||||
# endif /* PRIx32 */
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# include <stdio.h>
|
||||
# include <stdarg.h> /* va_copy define check */
|
||||
@@ -272,6 +256,8 @@ int ssh_auth_reply_success(ssh_session session, int partial);
|
||||
int ssh_send_banner(ssh_session session, int is_server);
|
||||
|
||||
/* connect.c */
|
||||
socket_t ssh_connect_host(ssh_session session, const char *host,const char
|
||||
*bind_addr, int port, long timeout, long usec);
|
||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port);
|
||||
|
||||
@@ -338,6 +324,7 @@ void explicit_bzero(void *s, size_t n);
|
||||
/**
|
||||
* Get the argument cound of variadic arguments
|
||||
*/
|
||||
#ifdef HAVE_GCC_NARG_MACRO
|
||||
/*
|
||||
* Since MSVC 2010 there is a bug in passing __VA_ARGS__ to subsequent
|
||||
* macros as a single token, which results in:
|
||||
@@ -347,7 +334,7 @@ void explicit_bzero(void *s, size_t n);
|
||||
#define VA_APPLY_VARIADIC_MACRO(macro, tuple) macro tuple
|
||||
|
||||
#define __VA_NARG__(...) \
|
||||
(__VA_NARG_(__VA_ARGS__, __RSEQ_N()))
|
||||
(__VA_NARG_(_0, ## __VA_ARGS__, __RSEQ_N()) - 1)
|
||||
#define __VA_NARG_(...) \
|
||||
VA_APPLY_VARIADIC_MACRO(__VA_ARG_N, (__VA_ARGS__))
|
||||
#define __VA_ARG_N( \
|
||||
@@ -366,6 +353,10 @@ 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
|
||||
#else
|
||||
/* clang does not support the above construction */
|
||||
#define __VA_NARG__(...) (-1)
|
||||
#endif
|
||||
|
||||
#define CLOSE_SOCKET(s) do { if ((s) != SSH_INVALID_SOCKET) { _XCLOSESOCKET(s); (s) = SSH_INVALID_SOCKET;} } while(0)
|
||||
|
||||
@@ -395,22 +386,6 @@ void explicit_bzero(void *s, size_t n);
|
||||
# endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
|
||||
#endif /* FALL_THROUGH */
|
||||
|
||||
#ifndef __unused__
|
||||
# ifdef HAVE_UNUSED_ATTRIBUTE
|
||||
# define __unused__ __attribute__((unused))
|
||||
# else /* HAVE_UNUSED_ATTRIBUTE */
|
||||
# define __unused__
|
||||
# endif /* HAVE_UNUSED_ATTRIBUTE */
|
||||
#endif /* __unused__ */
|
||||
|
||||
#ifndef UNUSED_PARAM
|
||||
#define UNUSED_PARAM(param) param __unused__
|
||||
#endif /* UNUSED_PARAM */
|
||||
|
||||
#ifndef UNUSED_VAR
|
||||
#define UNUSED_VAR(var) __unused__ var
|
||||
#endif /* UNUSED_VAR */
|
||||
|
||||
void ssh_agent_state_free(void *data);
|
||||
|
||||
#endif /* _LIBSSH_PRIV_H */
|
||||
|
||||
@@ -46,16 +46,7 @@ enum ssh_bind_options_e {
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
|
||||
SSH_BIND_OPTIONS_ECDSAKEY,
|
||||
SSH_BIND_OPTIONS_IMPORT_KEY,
|
||||
SSH_BIND_OPTIONS_KEY_EXCHANGE,
|
||||
SSH_BIND_OPTIONS_CIPHERS_C_S,
|
||||
SSH_BIND_OPTIONS_CIPHERS_S_C,
|
||||
SSH_BIND_OPTIONS_HMAC_C_S,
|
||||
SSH_BIND_OPTIONS_HMAC_S_C,
|
||||
SSH_BIND_OPTIONS_CONFIG_DIR,
|
||||
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
|
||||
SSH_BIND_OPTIONS_PROCESS_CONFIG,
|
||||
SSH_BIND_OPTIONS_IMPORT_KEY
|
||||
};
|
||||
|
||||
typedef struct ssh_bind_struct* ssh_bind;
|
||||
@@ -94,9 +85,6 @@ LIBSSH_API ssh_bind ssh_bind_new(void);
|
||||
LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
|
||||
enum ssh_bind_options_e type, const void *value);
|
||||
|
||||
LIBSSH_API int ssh_bind_options_parse_config(ssh_bind sshbind,
|
||||
const char *filename);
|
||||
|
||||
/**
|
||||
* @brief Start listening to the socket.
|
||||
*
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
|
||||
#ifndef SESSION_H_
|
||||
#define SESSION_H_
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/kex.h"
|
||||
#include "libssh/packet.h"
|
||||
@@ -29,8 +27,6 @@
|
||||
#include "libssh/auth.h"
|
||||
#include "libssh/channels.h"
|
||||
#include "libssh/poll.h"
|
||||
#include "libssh/config.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
/* These are the different states a SSH session can be into its life */
|
||||
enum ssh_session_state_e {
|
||||
@@ -49,8 +45,6 @@ enum ssh_session_state_e {
|
||||
|
||||
enum ssh_dh_state_e {
|
||||
DH_STATE_INIT=0,
|
||||
DH_STATE_GROUP_SENT,
|
||||
DH_STATE_REQUEST_SENT,
|
||||
DH_STATE_INIT_SENT,
|
||||
DH_STATE_NEWKEYS_SENT,
|
||||
DH_STATE_FINISHED
|
||||
@@ -117,7 +111,6 @@ struct ssh_session_struct {
|
||||
int openssh;
|
||||
uint32_t send_seq;
|
||||
uint32_t recv_seq;
|
||||
struct ssh_timestamp last_rekey_time;
|
||||
|
||||
int connected;
|
||||
/* !=0 when the user got a session handle */
|
||||
@@ -138,8 +131,6 @@ struct ssh_session_struct {
|
||||
ssh_buffer in_buffer;
|
||||
PACKET in_packet;
|
||||
ssh_buffer out_buffer;
|
||||
struct ssh_list *out_queue; /* This list is used for delaying packets
|
||||
when rekeying is required */
|
||||
|
||||
/* the states are used by the nonblocking stuff to remember */
|
||||
/* where it was before being interrupted */
|
||||
@@ -227,10 +218,6 @@ struct ssh_session_struct {
|
||||
int gss_delegate_creds;
|
||||
int flags;
|
||||
int nodelay;
|
||||
bool config_processed;
|
||||
uint8_t options_seen[SOC_MAX];
|
||||
uint64_t rekey_data;
|
||||
uint32_t rekey_time;
|
||||
} opts;
|
||||
/* counters */
|
||||
ssh_counter socket_counter;
|
||||
@@ -244,10 +231,8 @@ struct ssh_session_struct {
|
||||
*/
|
||||
typedef int (*ssh_termination_function)(void *user);
|
||||
int ssh_handle_packets(ssh_session session, int timeout);
|
||||
int ssh_handle_packets_termination(ssh_session session,
|
||||
long timeout,
|
||||
ssh_termination_function fct,
|
||||
void *user);
|
||||
int ssh_handle_packets_termination(ssh_session session, int timeout,
|
||||
ssh_termination_function fct, void *user);
|
||||
void ssh_socket_exception_callback(int code, int errno_code, void *user);
|
||||
|
||||
#endif /* SESSION_H_ */
|
||||
|
||||
@@ -818,9 +818,7 @@ LIBSSH_API int sftp_fsync(sftp_file file);
|
||||
*
|
||||
* @param path The path to be canonicalized.
|
||||
*
|
||||
* @return A pointer to the newly allocated canonicalized path,
|
||||
* NULL on error. The caller needs to free the memory
|
||||
* using ssh_string_free_char().
|
||||
* @return The canonicalize path, NULL on error.
|
||||
*/
|
||||
LIBSSH_API char *sftp_canonicalize_path(sftp_session sftp, const char *path);
|
||||
|
||||
@@ -853,13 +851,6 @@ LIBSSH_API sftp_session sftp_server_new(ssh_session session, ssh_channel chan);
|
||||
* @return 0 on success, < 0 on error.
|
||||
*/
|
||||
LIBSSH_API int sftp_server_init(sftp_session sftp);
|
||||
|
||||
/**
|
||||
* @brief Close and deallocate a sftp server session.
|
||||
*
|
||||
* @param sftp The sftp session handle to free.
|
||||
*/
|
||||
LIBSSH_API void sftp_server_free(sftp_session sftp);
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
/* this is not a public interface */
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* token.h - Tokens list handling
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.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; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef TOKEN_H_
|
||||
#define TOKEN_H_
|
||||
|
||||
struct ssh_tokens_st {
|
||||
char *buffer;
|
||||
char **tokens;
|
||||
};
|
||||
|
||||
struct ssh_tokens_st *ssh_tokenize(const char *chain, char separator);
|
||||
|
||||
void ssh_tokens_free(struct ssh_tokens_st *tokens);
|
||||
|
||||
char *ssh_find_matching(const char *available_d,
|
||||
const char *preferred_d);
|
||||
|
||||
|
||||
char *ssh_find_all_matching(const char *available_d,
|
||||
const char *preferred_d);
|
||||
#endif /* TOKEN_H_ */
|
||||
@@ -21,8 +21,6 @@
|
||||
#ifndef WRAPPER_H_
|
||||
#define WRAPPER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/libcrypto.h"
|
||||
@@ -33,15 +31,14 @@ enum ssh_digest_e {
|
||||
SSH_DIGEST_AUTO=0,
|
||||
SSH_DIGEST_SHA1=1,
|
||||
SSH_DIGEST_SHA256,
|
||||
SSH_DIGEST_SHA384,
|
||||
SSH_DIGEST_SHA512,
|
||||
SSH_DIGEST_SHA512
|
||||
};
|
||||
|
||||
enum ssh_kdf_digest {
|
||||
SSH_KDF_SHA1=1,
|
||||
SSH_KDF_SHA256,
|
||||
SSH_KDF_SHA384,
|
||||
SSH_KDF_SHA512
|
||||
enum ssh_mac_e {
|
||||
SSH_MAC_SHA1=1,
|
||||
SSH_MAC_SHA256,
|
||||
SSH_MAC_SHA384,
|
||||
SSH_MAC_SHA512
|
||||
};
|
||||
|
||||
enum ssh_hmac_e {
|
||||
@@ -49,8 +46,7 @@ enum ssh_hmac_e {
|
||||
SSH_HMAC_SHA256,
|
||||
SSH_HMAC_SHA512,
|
||||
SSH_HMAC_MD5,
|
||||
SSH_HMAC_AEAD_POLY1305,
|
||||
SSH_HMAC_AEAD_GCM
|
||||
SSH_HMAC_AEAD_POLY1305
|
||||
};
|
||||
|
||||
enum ssh_des_e {
|
||||
@@ -61,17 +57,9 @@ enum ssh_des_e {
|
||||
struct ssh_hmac_struct {
|
||||
const char* name;
|
||||
enum ssh_hmac_e hmac_type;
|
||||
bool etm;
|
||||
};
|
||||
|
||||
enum ssh_crypto_direction_e {
|
||||
SSH_DIRECTION_IN = 1,
|
||||
SSH_DIRECTION_OUT = 2,
|
||||
SSH_DIRECTION_BOTH = 3,
|
||||
};
|
||||
|
||||
struct ssh_cipher_struct;
|
||||
struct ssh_crypto_struct;
|
||||
|
||||
typedef struct ssh_mac_ctx_struct *ssh_mac_ctx;
|
||||
MD5CTX md5_init(void);
|
||||
@@ -81,38 +69,37 @@ void md5_final(unsigned char *md,MD5CTX c);
|
||||
SHACTX sha1_init(void);
|
||||
void sha1_update(SHACTX c, const void *data, unsigned long len);
|
||||
void sha1_final(unsigned char *md,SHACTX c);
|
||||
void sha1(const unsigned char *digest,int len,unsigned char *hash);
|
||||
void sha1(unsigned char *digest,int len,unsigned char *hash);
|
||||
|
||||
SHA256CTX sha256_init(void);
|
||||
void sha256_update(SHA256CTX c, const void *data, unsigned long len);
|
||||
void sha256_final(unsigned char *md,SHA256CTX c);
|
||||
void sha256(const unsigned char *digest, int len, unsigned char *hash);
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash);
|
||||
|
||||
SHA384CTX sha384_init(void);
|
||||
void sha384_update(SHA384CTX c, const void *data, unsigned long len);
|
||||
void sha384_final(unsigned char *md,SHA384CTX c);
|
||||
void sha384(const unsigned char *digest, int len, unsigned char *hash);
|
||||
void sha384(unsigned char *digest, int len, unsigned char *hash);
|
||||
|
||||
SHA512CTX sha512_init(void);
|
||||
void sha512_update(SHA512CTX c, const void *data, unsigned long len);
|
||||
void sha512_final(unsigned char *md,SHA512CTX c);
|
||||
void sha512(const unsigned char *digest, int len, unsigned char *hash);
|
||||
void sha512(unsigned char *digest, int len, unsigned char *hash);
|
||||
|
||||
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen);
|
||||
EVPCTX evp_init(int nid);
|
||||
void evp_update(EVPCTX ctx, const void *data, unsigned long len);
|
||||
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen);
|
||||
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type);
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len);
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx);
|
||||
|
||||
HMACCTX hmac_init(const void *key,int len, enum ssh_hmac_e type);
|
||||
void hmac_update(HMACCTX c, const void *data, unsigned long len);
|
||||
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
|
||||
size_t hmac_digest_len(enum ssh_hmac_e type);
|
||||
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len);
|
||||
|
||||
int crypt_set_algorithms_client(ssh_session session);
|
||||
int crypt_set_algorithms_server(ssh_session session);
|
||||
struct ssh_crypto_struct *crypto_new(void);
|
||||
@@ -125,6 +112,6 @@ void ssh_crypto_finalize(void);
|
||||
void ssh_cipher_clear(struct ssh_cipher_struct *cipher);
|
||||
struct ssh_hmac_struct *ssh_get_hmactab(void);
|
||||
struct ssh_cipher_struct *ssh_get_ciphertab(void);
|
||||
const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type, bool etm);
|
||||
const char *ssh_hmac_type_to_string(enum ssh_hmac_e hmac_type);
|
||||
|
||||
#endif /* WRAPPER_H_ */
|
||||
|
||||
@@ -1 +1 @@
|
||||
4.8.1
|
||||
4.7.4
|
||||
@@ -1,419 +0,0 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_init
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -1,421 +0,0 @@
|
||||
_ssh_log
|
||||
buffer_free
|
||||
buffer_get
|
||||
buffer_get_len
|
||||
buffer_new
|
||||
channel_accept_x11
|
||||
channel_change_pty_size
|
||||
channel_close
|
||||
channel_forward_accept
|
||||
channel_forward_cancel
|
||||
channel_forward_listen
|
||||
channel_free
|
||||
channel_get_exit_status
|
||||
channel_get_session
|
||||
channel_is_closed
|
||||
channel_is_eof
|
||||
channel_is_open
|
||||
channel_new
|
||||
channel_open_forward
|
||||
channel_open_session
|
||||
channel_poll
|
||||
channel_read
|
||||
channel_read_buffer
|
||||
channel_read_nonblocking
|
||||
channel_request_env
|
||||
channel_request_exec
|
||||
channel_request_pty
|
||||
channel_request_pty_size
|
||||
channel_request_send_signal
|
||||
channel_request_sftp
|
||||
channel_request_shell
|
||||
channel_request_subsystem
|
||||
channel_request_x11
|
||||
channel_select
|
||||
channel_send_eof
|
||||
channel_set_blocking
|
||||
channel_write
|
||||
channel_write_stderr
|
||||
privatekey_free
|
||||
privatekey_from_file
|
||||
publickey_free
|
||||
publickey_from_file
|
||||
publickey_from_privatekey
|
||||
publickey_to_string
|
||||
sftp_async_read
|
||||
sftp_async_read_begin
|
||||
sftp_attributes_free
|
||||
sftp_canonicalize_path
|
||||
sftp_chmod
|
||||
sftp_chown
|
||||
sftp_client_message_free
|
||||
sftp_client_message_get_data
|
||||
sftp_client_message_get_filename
|
||||
sftp_client_message_get_flags
|
||||
sftp_client_message_get_submessage
|
||||
sftp_client_message_get_type
|
||||
sftp_client_message_set_filename
|
||||
sftp_close
|
||||
sftp_closedir
|
||||
sftp_dir_eof
|
||||
sftp_extension_supported
|
||||
sftp_extensions_get_count
|
||||
sftp_extensions_get_data
|
||||
sftp_extensions_get_name
|
||||
sftp_file_set_blocking
|
||||
sftp_file_set_nonblocking
|
||||
sftp_free
|
||||
sftp_fstat
|
||||
sftp_fstatvfs
|
||||
sftp_fsync
|
||||
sftp_get_client_message
|
||||
sftp_get_error
|
||||
sftp_handle
|
||||
sftp_handle_alloc
|
||||
sftp_handle_remove
|
||||
sftp_init
|
||||
sftp_lstat
|
||||
sftp_mkdir
|
||||
sftp_new
|
||||
sftp_new_channel
|
||||
sftp_open
|
||||
sftp_opendir
|
||||
sftp_read
|
||||
sftp_readdir
|
||||
sftp_readlink
|
||||
sftp_rename
|
||||
sftp_reply_attr
|
||||
sftp_reply_data
|
||||
sftp_reply_handle
|
||||
sftp_reply_name
|
||||
sftp_reply_names
|
||||
sftp_reply_names_add
|
||||
sftp_reply_status
|
||||
sftp_rewind
|
||||
sftp_rmdir
|
||||
sftp_seek
|
||||
sftp_seek64
|
||||
sftp_send_client_message
|
||||
sftp_server_free
|
||||
sftp_server_init
|
||||
sftp_server_new
|
||||
sftp_server_version
|
||||
sftp_setstat
|
||||
sftp_stat
|
||||
sftp_statvfs
|
||||
sftp_statvfs_free
|
||||
sftp_symlink
|
||||
sftp_tell
|
||||
sftp_tell64
|
||||
sftp_unlink
|
||||
sftp_utimes
|
||||
sftp_write
|
||||
ssh_accept
|
||||
ssh_add_channel_callbacks
|
||||
ssh_auth_list
|
||||
ssh_basename
|
||||
ssh_bind_accept
|
||||
ssh_bind_accept_fd
|
||||
ssh_bind_fd_toaccept
|
||||
ssh_bind_free
|
||||
ssh_bind_get_fd
|
||||
ssh_bind_listen
|
||||
ssh_bind_new
|
||||
ssh_bind_options_parse_config
|
||||
ssh_bind_options_set
|
||||
ssh_bind_set_blocking
|
||||
ssh_bind_set_callbacks
|
||||
ssh_bind_set_fd
|
||||
ssh_blocking_flush
|
||||
ssh_buffer_add_data
|
||||
ssh_buffer_free
|
||||
ssh_buffer_get
|
||||
ssh_buffer_get_data
|
||||
ssh_buffer_get_len
|
||||
ssh_buffer_new
|
||||
ssh_buffer_reinit
|
||||
ssh_channel_accept_forward
|
||||
ssh_channel_accept_x11
|
||||
ssh_channel_cancel_forward
|
||||
ssh_channel_change_pty_size
|
||||
ssh_channel_close
|
||||
ssh_channel_free
|
||||
ssh_channel_get_exit_status
|
||||
ssh_channel_get_session
|
||||
ssh_channel_is_closed
|
||||
ssh_channel_is_eof
|
||||
ssh_channel_is_open
|
||||
ssh_channel_listen_forward
|
||||
ssh_channel_new
|
||||
ssh_channel_open_auth_agent
|
||||
ssh_channel_open_forward
|
||||
ssh_channel_open_forward_unix
|
||||
ssh_channel_open_reverse_forward
|
||||
ssh_channel_open_session
|
||||
ssh_channel_open_x11
|
||||
ssh_channel_poll
|
||||
ssh_channel_poll_timeout
|
||||
ssh_channel_read
|
||||
ssh_channel_read_nonblocking
|
||||
ssh_channel_read_timeout
|
||||
ssh_channel_request_auth_agent
|
||||
ssh_channel_request_env
|
||||
ssh_channel_request_exec
|
||||
ssh_channel_request_pty
|
||||
ssh_channel_request_pty_size
|
||||
ssh_channel_request_send_break
|
||||
ssh_channel_request_send_exit_signal
|
||||
ssh_channel_request_send_exit_status
|
||||
ssh_channel_request_send_signal
|
||||
ssh_channel_request_sftp
|
||||
ssh_channel_request_shell
|
||||
ssh_channel_request_subsystem
|
||||
ssh_channel_request_x11
|
||||
ssh_channel_select
|
||||
ssh_channel_send_eof
|
||||
ssh_channel_set_blocking
|
||||
ssh_channel_set_counter
|
||||
ssh_channel_window_size
|
||||
ssh_channel_write
|
||||
ssh_channel_write_stderr
|
||||
ssh_clean_pubkey_hash
|
||||
ssh_connect
|
||||
ssh_connector_free
|
||||
ssh_connector_new
|
||||
ssh_connector_set_in_channel
|
||||
ssh_connector_set_in_fd
|
||||
ssh_connector_set_out_channel
|
||||
ssh_connector_set_out_fd
|
||||
ssh_copyright
|
||||
ssh_dirname
|
||||
ssh_disconnect
|
||||
ssh_dump_knownhost
|
||||
ssh_event_add_connector
|
||||
ssh_event_add_fd
|
||||
ssh_event_add_session
|
||||
ssh_event_dopoll
|
||||
ssh_event_free
|
||||
ssh_event_new
|
||||
ssh_event_remove_connector
|
||||
ssh_event_remove_fd
|
||||
ssh_event_remove_session
|
||||
ssh_execute_message_callbacks
|
||||
ssh_finalize
|
||||
ssh_forward_accept
|
||||
ssh_forward_cancel
|
||||
ssh_forward_listen
|
||||
ssh_free
|
||||
ssh_get_cipher_in
|
||||
ssh_get_cipher_out
|
||||
ssh_get_clientbanner
|
||||
ssh_get_disconnect_message
|
||||
ssh_get_error
|
||||
ssh_get_error_code
|
||||
ssh_get_fd
|
||||
ssh_get_fingerprint_hash
|
||||
ssh_get_hexa
|
||||
ssh_get_hmac_in
|
||||
ssh_get_hmac_out
|
||||
ssh_get_issue_banner
|
||||
ssh_get_kex_algo
|
||||
ssh_get_log_callback
|
||||
ssh_get_log_level
|
||||
ssh_get_log_userdata
|
||||
ssh_get_openssh_version
|
||||
ssh_get_poll_flags
|
||||
ssh_get_pubkey
|
||||
ssh_get_pubkey_hash
|
||||
ssh_get_publickey
|
||||
ssh_get_publickey_hash
|
||||
ssh_get_random
|
||||
ssh_get_server_publickey
|
||||
ssh_get_serverbanner
|
||||
ssh_get_status
|
||||
ssh_get_version
|
||||
ssh_getpass
|
||||
ssh_gssapi_get_creds
|
||||
ssh_gssapi_set_creds
|
||||
ssh_handle_key_exchange
|
||||
ssh_init
|
||||
ssh_is_blocking
|
||||
ssh_is_connected
|
||||
ssh_is_server_known
|
||||
ssh_key_cmp
|
||||
ssh_key_free
|
||||
ssh_key_is_private
|
||||
ssh_key_is_public
|
||||
ssh_key_new
|
||||
ssh_key_type
|
||||
ssh_key_type_from_name
|
||||
ssh_key_type_to_char
|
||||
ssh_known_hosts_parse_line
|
||||
ssh_knownhosts_entry_free
|
||||
ssh_log
|
||||
ssh_message_auth_interactive_request
|
||||
ssh_message_auth_kbdint_is_response
|
||||
ssh_message_auth_password
|
||||
ssh_message_auth_pubkey
|
||||
ssh_message_auth_publickey
|
||||
ssh_message_auth_publickey_state
|
||||
ssh_message_auth_reply_pk_ok
|
||||
ssh_message_auth_reply_pk_ok_simple
|
||||
ssh_message_auth_reply_success
|
||||
ssh_message_auth_set_methods
|
||||
ssh_message_auth_user
|
||||
ssh_message_channel_request_channel
|
||||
ssh_message_channel_request_command
|
||||
ssh_message_channel_request_env_name
|
||||
ssh_message_channel_request_env_value
|
||||
ssh_message_channel_request_open_destination
|
||||
ssh_message_channel_request_open_destination_port
|
||||
ssh_message_channel_request_open_originator
|
||||
ssh_message_channel_request_open_originator_port
|
||||
ssh_message_channel_request_open_reply_accept
|
||||
ssh_message_channel_request_open_reply_accept_channel
|
||||
ssh_message_channel_request_pty_height
|
||||
ssh_message_channel_request_pty_pxheight
|
||||
ssh_message_channel_request_pty_pxwidth
|
||||
ssh_message_channel_request_pty_term
|
||||
ssh_message_channel_request_pty_width
|
||||
ssh_message_channel_request_reply_success
|
||||
ssh_message_channel_request_subsystem
|
||||
ssh_message_channel_request_x11_auth_cookie
|
||||
ssh_message_channel_request_x11_auth_protocol
|
||||
ssh_message_channel_request_x11_screen_number
|
||||
ssh_message_channel_request_x11_single_connection
|
||||
ssh_message_free
|
||||
ssh_message_get
|
||||
ssh_message_global_request_address
|
||||
ssh_message_global_request_port
|
||||
ssh_message_global_request_reply_success
|
||||
ssh_message_reply_default
|
||||
ssh_message_retrieve
|
||||
ssh_message_service_reply_success
|
||||
ssh_message_service_service
|
||||
ssh_message_subtype
|
||||
ssh_message_type
|
||||
ssh_mkdir
|
||||
ssh_new
|
||||
ssh_options_copy
|
||||
ssh_options_get
|
||||
ssh_options_get_port
|
||||
ssh_options_getopt
|
||||
ssh_options_parse_config
|
||||
ssh_options_set
|
||||
ssh_pcap_file_close
|
||||
ssh_pcap_file_free
|
||||
ssh_pcap_file_new
|
||||
ssh_pcap_file_open
|
||||
ssh_pki_copy_cert_to_privkey
|
||||
ssh_pki_export_privkey_base64
|
||||
ssh_pki_export_privkey_file
|
||||
ssh_pki_export_privkey_to_pubkey
|
||||
ssh_pki_export_pubkey_base64
|
||||
ssh_pki_export_pubkey_file
|
||||
ssh_pki_generate
|
||||
ssh_pki_import_cert_base64
|
||||
ssh_pki_import_cert_file
|
||||
ssh_pki_import_privkey_base64
|
||||
ssh_pki_import_privkey_file
|
||||
ssh_pki_import_pubkey_base64
|
||||
ssh_pki_import_pubkey_file
|
||||
ssh_pki_key_ecdsa_name
|
||||
ssh_print_hash
|
||||
ssh_print_hexa
|
||||
ssh_privatekey_type
|
||||
ssh_publickey_to_file
|
||||
ssh_remove_channel_callbacks
|
||||
ssh_scp_accept_request
|
||||
ssh_scp_close
|
||||
ssh_scp_deny_request
|
||||
ssh_scp_free
|
||||
ssh_scp_init
|
||||
ssh_scp_leave_directory
|
||||
ssh_scp_new
|
||||
ssh_scp_pull_request
|
||||
ssh_scp_push_directory
|
||||
ssh_scp_push_file
|
||||
ssh_scp_push_file64
|
||||
ssh_scp_read
|
||||
ssh_scp_request_get_filename
|
||||
ssh_scp_request_get_permissions
|
||||
ssh_scp_request_get_size
|
||||
ssh_scp_request_get_size64
|
||||
ssh_scp_request_get_warning
|
||||
ssh_scp_write
|
||||
ssh_select
|
||||
ssh_send_debug
|
||||
ssh_send_ignore
|
||||
ssh_send_keepalive
|
||||
ssh_server_init_kex
|
||||
ssh_service_request
|
||||
ssh_session_export_known_hosts_entry
|
||||
ssh_session_get_known_hosts_entry
|
||||
ssh_session_has_known_hosts_entry
|
||||
ssh_session_is_known_server
|
||||
ssh_session_update_known_hosts
|
||||
ssh_set_agent_channel
|
||||
ssh_set_agent_socket
|
||||
ssh_set_auth_methods
|
||||
ssh_set_blocking
|
||||
ssh_set_callbacks
|
||||
ssh_set_channel_callbacks
|
||||
ssh_set_counters
|
||||
ssh_set_fd_except
|
||||
ssh_set_fd_toread
|
||||
ssh_set_fd_towrite
|
||||
ssh_set_log_callback
|
||||
ssh_set_log_level
|
||||
ssh_set_log_userdata
|
||||
ssh_set_message_callback
|
||||
ssh_set_pcap_file
|
||||
ssh_set_server_callbacks
|
||||
ssh_silent_disconnect
|
||||
ssh_string_burn
|
||||
ssh_string_copy
|
||||
ssh_string_data
|
||||
ssh_string_fill
|
||||
ssh_string_free
|
||||
ssh_string_free_char
|
||||
ssh_string_from_char
|
||||
ssh_string_get_char
|
||||
ssh_string_len
|
||||
ssh_string_new
|
||||
ssh_string_to_char
|
||||
ssh_threads_get_default
|
||||
ssh_threads_get_noop
|
||||
ssh_threads_get_pthread
|
||||
ssh_threads_set_callbacks
|
||||
ssh_try_publickey_from_file
|
||||
ssh_userauth_agent
|
||||
ssh_userauth_agent_pubkey
|
||||
ssh_userauth_autopubkey
|
||||
ssh_userauth_gssapi
|
||||
ssh_userauth_kbdint
|
||||
ssh_userauth_kbdint_getanswer
|
||||
ssh_userauth_kbdint_getinstruction
|
||||
ssh_userauth_kbdint_getname
|
||||
ssh_userauth_kbdint_getnanswers
|
||||
ssh_userauth_kbdint_getnprompts
|
||||
ssh_userauth_kbdint_getprompt
|
||||
ssh_userauth_kbdint_setanswer
|
||||
ssh_userauth_list
|
||||
ssh_userauth_none
|
||||
ssh_userauth_offer_pubkey
|
||||
ssh_userauth_password
|
||||
ssh_userauth_privatekey_file
|
||||
ssh_userauth_pubkey
|
||||
ssh_userauth_publickey
|
||||
ssh_userauth_publickey_auto
|
||||
ssh_userauth_try_publickey
|
||||
ssh_version
|
||||
ssh_write_knownhost
|
||||
string_burn
|
||||
string_copy
|
||||
string_data
|
||||
string_fill
|
||||
string_free
|
||||
string_from_char
|
||||
string_len
|
||||
string_new
|
||||
string_to_char
|
||||
@@ -48,7 +48,7 @@ if (MBEDTLS_CRYPTO_LIBRARY)
|
||||
)
|
||||
endif (MBEDTLS_CRYPTO_LIBRARY)
|
||||
|
||||
if (GCRYPT_LIBRARIES)
|
||||
if (GCRYPT_LIBRARY)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
${LIBSSH_PRIVATE_INCLUDE_DIRS}
|
||||
${GCRYPT_INCLUDE_DIR}
|
||||
@@ -56,8 +56,9 @@ if (GCRYPT_LIBRARIES)
|
||||
|
||||
set(LIBSSH_LINK_LIBRARIES
|
||||
${LIBSSH_LINK_LIBRARIES}
|
||||
${GCRYPT_LIBRARIES})
|
||||
endif()
|
||||
${GCRYPT_LIBRARY}
|
||||
)
|
||||
endif (GCRYPT_LIBRARY)
|
||||
|
||||
if (WITH_ZLIB)
|
||||
set(LIBSSH_PRIVATE_INCLUDE_DIRS
|
||||
@@ -130,7 +131,6 @@ set(libssh_SRCS
|
||||
error.c
|
||||
getpass.c
|
||||
init.c
|
||||
kdf.c
|
||||
kex.c
|
||||
known_hosts.c
|
||||
knownhosts.c
|
||||
@@ -163,16 +163,8 @@ set(libssh_SRCS
|
||||
external/poly1305.c
|
||||
external/sc25519.c
|
||||
chachapoly.c
|
||||
config_parser.c
|
||||
token.c
|
||||
)
|
||||
|
||||
if (DEFAULT_C_NO_DEPRECATION_FLAGS)
|
||||
set_source_files_properties(known_hosts.c
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS ${DEFAULT_C_NO_DEPRECATION_FLAGS})
|
||||
endif()
|
||||
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
@@ -200,7 +192,6 @@ if (WITH_GCRYPT)
|
||||
gcrypt_missing.c
|
||||
pki_gcrypt.c
|
||||
ecdh_gcrypt.c
|
||||
dh_key.c
|
||||
)
|
||||
elseif (WITH_MBEDTLS)
|
||||
set(libssh_SRCS
|
||||
@@ -210,7 +201,6 @@ elseif (WITH_MBEDTLS)
|
||||
mbedcrypto_missing.c
|
||||
pki_mbedcrypto.c
|
||||
ecdh_mbedcrypto.c
|
||||
dh_key.c
|
||||
)
|
||||
else (WITH_GCRYPT)
|
||||
set(libssh_SRCS
|
||||
@@ -219,7 +209,6 @@ else (WITH_GCRYPT)
|
||||
pki_crypto.c
|
||||
ecdh_crypto.c
|
||||
libcrypto.c
|
||||
dh_crypto.c
|
||||
)
|
||||
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
|
||||
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
|
||||
@@ -245,17 +234,9 @@ if (WITH_SERVER)
|
||||
${libssh_SRCS}
|
||||
server.c
|
||||
bind.c
|
||||
bind_config.c
|
||||
)
|
||||
endif (WITH_SERVER)
|
||||
|
||||
if (WITH_GEX)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
dh-gex.c
|
||||
)
|
||||
endif (WITH_GEX)
|
||||
|
||||
if (WITH_ZLIB)
|
||||
set(libssh_SRCS
|
||||
${libssh_SRCS}
|
||||
@@ -314,10 +295,7 @@ if (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT AND ABIMAP_FOUND)
|
||||
endif (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT AND ABIMAP_FOUND)
|
||||
|
||||
add_library(${LIBSSH_SHARED_LIBRARY} SHARED ${libssh_SRCS})
|
||||
target_compile_options(${LIBSSH_SHARED_LIBRARY}
|
||||
PRIVATE
|
||||
${DEFAULT_C_COMPILE_FLAGS}
|
||||
-D_GNU_SOURCE)
|
||||
target_compile_options(${LIBSSH_SHARED_LIBRARY} PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
|
||||
target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
|
||||
|
||||
@@ -365,10 +343,7 @@ install(
|
||||
|
||||
if (BUILD_STATIC_LIB)
|
||||
add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS})
|
||||
target_compile_options(${LIBSSH_STATIC_LIBRARY}
|
||||
PRIVATE
|
||||
${DEFAULT_C_COMPILE_FLAGS}
|
||||
-D_GNU_SOURCE)
|
||||
target_compile_options(${LIBSSH_STATIC_LIBRARY} PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
|
||||
|
||||
if (MSVC)
|
||||
set(OUTPUT_SUFFIX static)
|
||||
|
||||
41
src/agent.c
41
src/agent.c
@@ -56,13 +56,33 @@
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/poll.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bytearray.h"
|
||||
|
||||
/* macro to check for "agent failure" message */
|
||||
#define agent_failed(x) \
|
||||
(((x) == SSH_AGENT_FAILURE) || ((x) == SSH_COM_AGENT2_FAILURE) || \
|
||||
((x) == SSH2_AGENT_FAILURE))
|
||||
|
||||
static uint32_t agent_get_u32(const void *vp) {
|
||||
const uint8_t *p = (const uint8_t *)vp;
|
||||
uint32_t v;
|
||||
|
||||
v = (uint32_t)p[0] << 24;
|
||||
v |= (uint32_t)p[1] << 16;
|
||||
v |= (uint32_t)p[2] << 8;
|
||||
v |= (uint32_t)p[3];
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void agent_put_u32(void *vp, uint32_t v) {
|
||||
uint8_t *p = (uint8_t *)vp;
|
||||
|
||||
p[0] = (uint8_t)(v >> 24) & 0xff;
|
||||
p[1] = (uint8_t)(v >> 16) & 0xff;
|
||||
p[2] = (uint8_t)(v >> 8) & 0xff;
|
||||
p[3] = (uint8_t)v & 0xff;
|
||||
}
|
||||
|
||||
static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int do_read) {
|
||||
char *b = buf;
|
||||
size_t pos = 0;
|
||||
@@ -255,7 +275,7 @@ static int agent_talk(struct ssh_session_struct *session,
|
||||
|
||||
len = ssh_buffer_get_len(request);
|
||||
SSH_LOG(SSH_LOG_TRACE, "Request length: %u", len);
|
||||
PUSH_BE_U32(payload, 0, len);
|
||||
agent_put_u32(payload, len);
|
||||
|
||||
/* send length and then the request packet */
|
||||
if (atomicio(session->agent, payload, 4, 0) == 4) {
|
||||
@@ -279,7 +299,7 @@ static int agent_talk(struct ssh_session_struct *session,
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = PULL_BE_U32(payload, 0);
|
||||
len = agent_get_u32(payload);
|
||||
if (len > 256 * 1024) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Authentication response too long: %u", len);
|
||||
@@ -311,7 +331,7 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
|
||||
ssh_buffer request = NULL;
|
||||
ssh_buffer reply = NULL;
|
||||
unsigned int type = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t buf[1] = {0};
|
||||
int rc;
|
||||
|
||||
/* send message to the agent requesting the list of identities */
|
||||
@@ -366,15 +386,8 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_get_u32(reply, &count);
|
||||
if (rc != 4) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to read count");
|
||||
ssh_buffer_free(reply);
|
||||
return -1;
|
||||
}
|
||||
session->agent->count = ntohl(count);
|
||||
ssh_buffer_get_u32(reply, (uint32_t *) buf);
|
||||
session->agent->count = agent_get_u32(buf);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Agent count: %d",
|
||||
session->agent->count);
|
||||
if (session->agent->count > 1024) {
|
||||
@@ -536,7 +549,7 @@ ssh_string ssh_agent_sign_data(ssh_session session,
|
||||
}
|
||||
|
||||
/* Add Flags: SHA2 extension (RFC 8332) if negotiated */
|
||||
if (ssh_key_type_plain(pubkey->type) == SSH_KEYTYPE_RSA) {
|
||||
if (pubkey->type == SSH_KEYTYPE_RSA) {
|
||||
if (session->extensions & SSH_EXT_SIG_RSA_SHA512) {
|
||||
flags |= SSH_AGENT_RSA_SHA2_512;
|
||||
} else if (session->extensions & SSH_EXT_SIG_RSA_SHA256) {
|
||||
|
||||
77
src/auth.c
77
src/auth.c
@@ -69,7 +69,7 @@ static int ssh_userauth_request_service(ssh_session session) {
|
||||
int rc;
|
||||
|
||||
rc = ssh_service_request(session, "ssh-userauth");
|
||||
if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Failed to request \"ssh-userauth\" service");
|
||||
}
|
||||
@@ -282,10 +282,7 @@ end:
|
||||
*
|
||||
* It is also used to communicate the new to the upper levels.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_success)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_userauth_success) {
|
||||
(void)packet;
|
||||
(void)type;
|
||||
(void)user;
|
||||
@@ -297,16 +294,13 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success)
|
||||
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
|
||||
session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
|
||||
if (crypto != NULL && crypto->delayed_compress_out) {
|
||||
if (session->current_crypto && session->current_crypto->delayed_compress_out) {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT");
|
||||
crypto->do_compress_out = 1;
|
||||
session->current_crypto->do_compress_out = 1;
|
||||
}
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
|
||||
if (crypto != NULL && crypto->delayed_compress_in) {
|
||||
if (session->current_crypto && session->current_crypto->delayed_compress_in) {
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN");
|
||||
crypto->do_compress_in = 1;
|
||||
session->current_crypto->do_compress_in = 1;
|
||||
}
|
||||
|
||||
/* Reset errors by previous authentication methods. */
|
||||
@@ -515,13 +509,26 @@ int ssh_userauth_try_publickey(ssh_session session,
|
||||
return SSH_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,
|
||||
switch (pubkey->type) {
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Invalid key type (unknown)");
|
||||
return SSH_AUTH_DENIED;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
sig_type_c = ssh_pki_key_ecdsa_name(pubkey);
|
||||
break;
|
||||
case SSH_KEYTYPE_DSS:
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
@@ -613,7 +620,6 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
int rc;
|
||||
const char *sig_type_c = NULL;
|
||||
enum ssh_keytypes_e key_type;
|
||||
enum ssh_digest_e hash_type;
|
||||
|
||||
if (session == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
@@ -639,13 +645,26 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
/* Cert auth requires presenting the cert type name (*-cert@openssh.com) */
|
||||
key_type = privkey->cert != NULL ? privkey->cert_type : privkey->type;
|
||||
|
||||
/* 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,
|
||||
switch (key_type) {
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Invalid key type (unknown)");
|
||||
return SSH_AUTH_DENIED;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
sig_type_c = ssh_pki_key_ecdsa_name(privkey);
|
||||
break;
|
||||
case SSH_KEYTYPE_DSS:
|
||||
case SSH_KEYTYPE_RSA:
|
||||
case SSH_KEYTYPE_RSA1:
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_DSS_CERT01:
|
||||
case SSH_KEYTYPE_RSA_CERT01:
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, key_type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if the given public key algorithm is allowed */
|
||||
if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
@@ -682,11 +701,8 @@ int ssh_userauth_publickey(ssh_session session,
|
||||
}
|
||||
ssh_string_free(str);
|
||||
|
||||
/* Get the hash type to be used in the signature based on the key type */
|
||||
hash_type = ssh_key_type_to_hash(session, privkey->type);
|
||||
|
||||
/* sign the buffer with the private key */
|
||||
str = ssh_pki_do_sign(session, session->out_buffer, privkey, hash_type);
|
||||
str = ssh_pki_do_sign(session, session->out_buffer, privkey);
|
||||
if (str == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -755,15 +771,9 @@ static int ssh_userauth_agent_publickey(ssh_session session,
|
||||
if (rc < 0) {
|
||||
goto fail;
|
||||
}
|
||||
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
|
||||
|
||||
/* 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,
|
||||
"Invalid key type (unknown)");
|
||||
SSH_STRING_FREE(pubkey_s);
|
||||
return SSH_AUTH_DENIED;
|
||||
}
|
||||
if (!ssh_key_algorithm_allowed(session, sig_type_c)) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"The key algorithm '%s' is not allowed to be used by"
|
||||
@@ -1261,9 +1271,6 @@ int ssh_userauth_password(ssh_session session,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set the buffer as secure to be explicitly zeroed when freed */
|
||||
ssh_buffer_set_secure(session->out_buffer);
|
||||
|
||||
session->auth.current_method = SSH_AUTH_METHOD_PASSWORD;
|
||||
session->auth.state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
|
||||
session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
|
||||
|
||||
67
src/bignum.c
67
src/bignum.c
@@ -56,39 +56,70 @@ ssh_string ssh_make_bignum_string(bignum num) {
|
||||
ptr->data[0] = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_bn2bin(num, len, ptr->data + pad);
|
||||
#elif HAVE_LIBCRYPTO
|
||||
bignum_bn2bin(num, ptr->data + pad);
|
||||
#elif HAVE_LIBMBEDCRYPTO
|
||||
bignum_bn2bin(num, ptr->data + pad);
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bignum ssh_make_string_bn(ssh_string string)
|
||||
{
|
||||
bignum bn = NULL;
|
||||
size_t len = ssh_string_len(string);
|
||||
bignum ssh_make_string_bn(ssh_string string){
|
||||
bignum bn = NULL;
|
||||
unsigned int len = ssh_string_len(string);
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
fprintf(stderr, "Importing a %zu bits, %zu bytes object ...\n",
|
||||
len * 8, len);
|
||||
fprintf(stderr, "Importing a %d bits, %d bytes object ...\n",
|
||||
len * 8, len);
|
||||
#endif /* DEBUG_CRYPTO */
|
||||
|
||||
bignum_bin2bn(string->data, len, &bn);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_bin2bn(string->data, len, &bn);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bn = bignum_bin2bn(string->data, len, NULL);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bn = bignum_new();
|
||||
bignum_bin2bn(string->data, len, bn);
|
||||
#endif
|
||||
|
||||
return bn;
|
||||
return bn;
|
||||
}
|
||||
|
||||
void ssh_make_string_bn_inplace(ssh_string string, bignum bnout) {
|
||||
unsigned int len = ssh_string_len(string);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
/* XXX: FIXME as needed for LIBGCRYPT ECDSA codepaths. */
|
||||
(void) len;
|
||||
(void) bnout;
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_bin2bn(string->data, len, bnout);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bignum_bin2bn(string->data, len, bnout);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* prints the bignum on stderr */
|
||||
void ssh_print_bignum(const char *name, const bignum num)
|
||||
{
|
||||
unsigned char *hex = NULL;
|
||||
if (num != NULL) {
|
||||
bignum_bn2hex(num, &hex);
|
||||
}
|
||||
fprintf(stderr, "%s value: %s\n", name, (hex == NULL) ? "(null)" : (char *) hex);
|
||||
void ssh_print_bignum(const char *which, const bignum num) {
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
SAFE_FREE(hex);
|
||||
unsigned char *hex = NULL;
|
||||
bignum_bn2hex(num, &hex);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
OPENSSL_free(hex);
|
||||
char *hex = NULL;
|
||||
hex = bignum_bn2hex(num);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
SAFE_FREE(hex);
|
||||
char *hex = NULL;
|
||||
hex = bignum_bn2hex(num);
|
||||
#endif
|
||||
fprintf(stderr, "%s value: ", which);
|
||||
fprintf(stderr, "%s\n", (hex == NULL) ? "(null)" : (char *) hex);
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
SAFE_FREE(hex);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
OPENSSL_free(hex);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
SAFE_FREE(hex);
|
||||
#endif
|
||||
}
|
||||
|
||||
82
src/bind.c
82
src/bind.c
@@ -38,7 +38,6 @@
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/token.h"
|
||||
|
||||
/**
|
||||
* @addtogroup libssh_server
|
||||
@@ -131,17 +130,18 @@ static socket_t bind_socket(ssh_bind sshbind, const char *hostname,
|
||||
}
|
||||
|
||||
ssh_bind ssh_bind_new(void) {
|
||||
ssh_bind ptr;
|
||||
ssh_bind ptr;
|
||||
|
||||
ptr = calloc(1, sizeof(struct ssh_bind_struct));
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ptr->bindfd = SSH_INVALID_SOCKET;
|
||||
ptr->bindport = 22;
|
||||
ptr->common.log_verbosity = 0;
|
||||
ptr = malloc(sizeof(struct ssh_bind_struct));
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(ptr);
|
||||
ptr->bindfd = SSH_INVALID_SOCKET;
|
||||
ptr->bindport= 22;
|
||||
ptr->common.log_verbosity = 0;
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
@@ -169,7 +169,7 @@ static int ssh_bind_import_keys(ssh_bind sshbind) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (!is_ecdsa_key_type(ssh_key_type(sshbind->ecdsa))) {
|
||||
if (ssh_key_type(sshbind->ecdsa) != SSH_KEYTYPE_ECDSA) {
|
||||
ssh_set_error(sshbind, SSH_FATAL,
|
||||
"The ECDSA host key has the wrong type");
|
||||
ssh_key_free(sshbind->ecdsa);
|
||||
@@ -343,24 +343,12 @@ static int ssh_bind_poll_callback(ssh_poll_handle sshpoll,
|
||||
* @param sshbind the ssh_bind object
|
||||
* @returns a ssh_poll handle suitable for operation
|
||||
*/
|
||||
ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind)
|
||||
{
|
||||
short events = POLLIN;
|
||||
|
||||
if (sshbind->poll) {
|
||||
return sshbind->poll;
|
||||
}
|
||||
|
||||
#ifdef POLLRDHUP
|
||||
events |= POLLRDHUP;
|
||||
#endif /* POLLRDHUP */
|
||||
|
||||
sshbind->poll = ssh_poll_new(sshbind->bindfd,
|
||||
events,
|
||||
ssh_bind_poll_callback,
|
||||
sshbind);
|
||||
|
||||
ssh_poll_handle ssh_bind_get_poll(ssh_bind sshbind){
|
||||
if(sshbind->poll)
|
||||
return sshbind->poll;
|
||||
sshbind->poll=ssh_poll_new(sshbind->bindfd,POLLIN,
|
||||
ssh_bind_poll_callback,sshbind);
|
||||
return sshbind->poll;
|
||||
}
|
||||
|
||||
void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) {
|
||||
@@ -394,8 +382,6 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
/* options */
|
||||
SAFE_FREE(sshbind->banner);
|
||||
SAFE_FREE(sshbind->bindaddr);
|
||||
SAFE_FREE(sshbind->config_dir);
|
||||
SAFE_FREE(sshbind->pubkey_accepted_key_types);
|
||||
|
||||
SAFE_FREE(sshbind->dsakey);
|
||||
SAFE_FREE(sshbind->rsakey);
|
||||
@@ -423,25 +409,14 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
int i, rc;
|
||||
|
||||
if (sshbind == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (session == NULL){
|
||||
ssh_set_error(sshbind, SSH_FATAL,"session is null");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
session->server = 1;
|
||||
|
||||
/* Copy options from bind to session */
|
||||
/* copy options */
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (sshbind->wanted_methods[i]) {
|
||||
session->opts.wanted_methods[i] = strdup(sshbind->wanted_methods[i]);
|
||||
@@ -461,29 +436,6 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
}
|
||||
}
|
||||
|
||||
if (sshbind->pubkey_accepted_key_types != NULL) {
|
||||
if (session->opts.pubkey_accepted_types == NULL) {
|
||||
session->opts.pubkey_accepted_types = strdup(sshbind->pubkey_accepted_key_types);
|
||||
if (session->opts.pubkey_accepted_types == NULL) {
|
||||
ssh_set_error_oom(sshbind);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
} else {
|
||||
char *p;
|
||||
/* If something was set to the session prior to calling this
|
||||
* function, keep only what is allowed by the options set in
|
||||
* sshbind */
|
||||
p = ssh_find_all_matching(sshbind->pubkey_accepted_key_types,
|
||||
session->opts.pubkey_accepted_types);
|
||||
if (p == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SAFE_FREE(session->opts.pubkey_accepted_types);
|
||||
session->opts.pubkey_accepted_types = p;
|
||||
}
|
||||
}
|
||||
|
||||
session->common.log_verbosity = sshbind->common.log_verbosity;
|
||||
if(sshbind->banner != NULL)
|
||||
session->opts.custombanner = strdup(sshbind->banner);
|
||||
|
||||
@@ -1,638 +0,0 @@
|
||||
/*
|
||||
* bind_config.c - Parse the SSH server configuration file
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Red Hat, Inc.
|
||||
*
|
||||
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.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; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_GLOB_H
|
||||
# include <glob.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/bind.h"
|
||||
#include "libssh/bind_config.h"
|
||||
#include "libssh/config_parser.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/server.h"
|
||||
#include "libssh/options.h"
|
||||
|
||||
#define MAX_LINE_SIZE 1024
|
||||
|
||||
/* Flags used for the parser state */
|
||||
#define PARSING 1
|
||||
#define IN_MATCH (1<<1)
|
||||
|
||||
struct ssh_bind_config_keyword_table_s {
|
||||
const char *name;
|
||||
enum ssh_bind_config_opcode_e opcode;
|
||||
bool allowed_in_match;
|
||||
};
|
||||
|
||||
static struct ssh_bind_config_keyword_table_s
|
||||
ssh_bind_config_keyword_table[] = {
|
||||
{
|
||||
.name = "include",
|
||||
.opcode = BIND_CFG_INCLUDE
|
||||
},
|
||||
{
|
||||
.name = "hostkey",
|
||||
.opcode = BIND_CFG_HOSTKEY
|
||||
},
|
||||
{
|
||||
.name = "listenaddress",
|
||||
.opcode = BIND_CFG_LISTENADDRESS
|
||||
},
|
||||
{
|
||||
.name = "port",
|
||||
.opcode = BIND_CFG_PORT
|
||||
},
|
||||
{
|
||||
.name = "loglevel",
|
||||
.opcode = BIND_CFG_LOGLEVEL,
|
||||
.allowed_in_match = true,
|
||||
},
|
||||
{
|
||||
.name = "ciphers",
|
||||
.opcode = BIND_CFG_CIPHERS
|
||||
},
|
||||
{
|
||||
.name = "macs",
|
||||
.opcode = BIND_CFG_MACS
|
||||
},
|
||||
{
|
||||
.name = "kexalgorithms",
|
||||
.opcode = BIND_CFG_KEXALGORITHMS
|
||||
},
|
||||
{
|
||||
.name = "match",
|
||||
.opcode = BIND_CFG_MATCH,
|
||||
.allowed_in_match = true
|
||||
},
|
||||
{
|
||||
.name = "pubkeyacceptedkeytypes",
|
||||
.opcode = BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
.allowed_in_match = true
|
||||
},
|
||||
{
|
||||
.name = "hostkeyalgorithms",
|
||||
.opcode = BIND_CFG_HOSTKEY_ALGORITHMS,
|
||||
.allowed_in_match = true
|
||||
},
|
||||
{
|
||||
.opcode = BIND_CFG_UNKNOWN,
|
||||
}
|
||||
};
|
||||
|
||||
enum ssh_bind_config_match_e {
|
||||
BIND_MATCH_UNKNOWN = -1,
|
||||
BIND_MATCH_ALL,
|
||||
BIND_MATCH_USER,
|
||||
BIND_MATCH_GROUP,
|
||||
BIND_MATCH_HOST,
|
||||
BIND_MATCH_LOCALADDRESS,
|
||||
BIND_MATCH_LOCALPORT,
|
||||
BIND_MATCH_RDOMAIN,
|
||||
BIND_MATCH_ADDRESS,
|
||||
};
|
||||
|
||||
struct ssh_bind_config_match_keyword_table_s {
|
||||
const char *name;
|
||||
enum ssh_bind_config_match_e opcode;
|
||||
};
|
||||
|
||||
static struct ssh_bind_config_match_keyword_table_s
|
||||
ssh_bind_config_match_keyword_table[] = {
|
||||
{
|
||||
.name = "all",
|
||||
.opcode = BIND_MATCH_ALL
|
||||
},
|
||||
{
|
||||
.name = "user",
|
||||
.opcode = BIND_MATCH_USER
|
||||
},
|
||||
{
|
||||
.name = "group",
|
||||
.opcode = BIND_MATCH_GROUP
|
||||
},
|
||||
{
|
||||
.name = "host",
|
||||
.opcode = BIND_MATCH_HOST
|
||||
},
|
||||
{
|
||||
.name = "localaddress",
|
||||
.opcode = BIND_MATCH_LOCALADDRESS
|
||||
},
|
||||
{
|
||||
.name = "localport",
|
||||
.opcode = BIND_MATCH_LOCALPORT
|
||||
},
|
||||
{
|
||||
.name = "rdomain",
|
||||
.opcode = BIND_MATCH_RDOMAIN
|
||||
},
|
||||
{
|
||||
.name = "address",
|
||||
.opcode = BIND_MATCH_ADDRESS
|
||||
},
|
||||
{
|
||||
.opcode = BIND_MATCH_UNKNOWN
|
||||
},
|
||||
};
|
||||
|
||||
static enum ssh_bind_config_opcode_e
|
||||
ssh_bind_config_get_opcode(char *keyword, uint32_t *parser_flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ssh_bind_config_keyword_table[i].name != NULL; i++) {
|
||||
if (strcasecmp(keyword, ssh_bind_config_keyword_table[i].name) == 0) {
|
||||
if ((*parser_flags & IN_MATCH) &&
|
||||
!(ssh_bind_config_keyword_table[i].allowed_in_match))
|
||||
{
|
||||
return BIND_CFG_NOT_ALLOWED_IN_MATCH;
|
||||
}
|
||||
return ssh_bind_config_keyword_table[i].opcode;
|
||||
}
|
||||
}
|
||||
|
||||
return BIND_CFG_UNKNOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_bind_config_parse_line(ssh_bind bind,
|
||||
const char *line,
|
||||
unsigned int count,
|
||||
uint32_t *parser_flags,
|
||||
uint8_t *seen);
|
||||
|
||||
static void local_parse_file(ssh_bind bind,
|
||||
const char *filename,
|
||||
uint32_t *parser_flags,
|
||||
uint8_t *seen)
|
||||
{
|
||||
FILE *f;
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
int rv;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
|
||||
filename);
|
||||
return;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s",
|
||||
filename);
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
rv = ssh_bind_config_parse_line(bind, line, count, parser_flags, seen);
|
||||
if (rv < 0) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
|
||||
static void local_parse_glob(ssh_bind bind,
|
||||
const char *fileglob,
|
||||
uint32_t *parser_flags,
|
||||
uint8_t *seen)
|
||||
{
|
||||
glob_t globbuf = {
|
||||
.gl_flags = 0,
|
||||
};
|
||||
int rt;
|
||||
u_int i;
|
||||
|
||||
rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
|
||||
if (rt == GLOB_NOMATCH) {
|
||||
globfree(&globbuf);
|
||||
return;
|
||||
} else if (rt != 0) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Glob error: %s",
|
||||
fileglob);
|
||||
globfree(&globbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < globbuf.gl_pathc; i++) {
|
||||
local_parse_file(bind, globbuf.gl_pathv[i], parser_flags, seen);
|
||||
}
|
||||
|
||||
globfree(&globbuf);
|
||||
}
|
||||
#endif /* HAVE_GLOB HAVE_GLOB_GL_FLAGS_MEMBER */
|
||||
|
||||
static enum ssh_bind_config_match_e
|
||||
ssh_bind_config_get_match_opcode(const char *keyword)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; ssh_bind_config_match_keyword_table[i].name != NULL; i++) {
|
||||
if (strcasecmp(keyword, ssh_bind_config_match_keyword_table[i].name) == 0) {
|
||||
return ssh_bind_config_match_keyword_table[i].opcode;
|
||||
}
|
||||
}
|
||||
|
||||
return BIND_MATCH_UNKNOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_bind_config_parse_line(ssh_bind bind,
|
||||
const char *line,
|
||||
unsigned int count,
|
||||
uint32_t *parser_flags,
|
||||
uint8_t *seen)
|
||||
{
|
||||
enum ssh_bind_config_opcode_e opcode;
|
||||
const char *p = NULL;
|
||||
char *s = NULL, *x = NULL;
|
||||
char *keyword = NULL;
|
||||
size_t len;
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (bind == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((line == NULL) || (parser_flags == NULL)) {
|
||||
ssh_set_error_invalid(bind);
|
||||
return -1;
|
||||
}
|
||||
|
||||
x = s = strdup(line);
|
||||
if (s == NULL) {
|
||||
ssh_set_error_oom(bind);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove trailing spaces */
|
||||
for (len = strlen(s) - 1; len > 0; len--) {
|
||||
if (! isspace(s[len])) {
|
||||
break;
|
||||
}
|
||||
s[len] = '\0';
|
||||
}
|
||||
|
||||
keyword = ssh_config_get_token(&s);
|
||||
if (keyword == NULL || *keyword == '#' ||
|
||||
*keyword == '\0' || *keyword == '\n') {
|
||||
SAFE_FREE(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
opcode = ssh_bind_config_get_opcode(keyword, parser_flags);
|
||||
if ((*parser_flags & PARSING) &&
|
||||
opcode != BIND_CFG_HOSTKEY &&
|
||||
opcode != BIND_CFG_INCLUDE &&
|
||||
opcode != BIND_CFG_MATCH &&
|
||||
opcode > BIND_CFG_UNSUPPORTED) { /* Ignore all unknown types here */
|
||||
/* Skip all the options that were already applied */
|
||||
if (seen[opcode] != 0) {
|
||||
SAFE_FREE(x);
|
||||
return 0;
|
||||
}
|
||||
seen[opcode] = 1;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case BIND_CFG_INCLUDE:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
|
||||
local_parse_glob(bind, p, parser_flags, seen);
|
||||
#else
|
||||
local_parse_file(bind, p, parser_flags, seen);
|
||||
#endif /* HAVE_GLOB */
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_CFG_HOSTKEY:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set Hostkey value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_LISTENADDRESS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDADDR, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set ListenAddress value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_PORT:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set Port value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_CIPHERS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_C_S, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set C->S Ciphers value '%s'",
|
||||
count, p);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_S_C, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set S->C Ciphers value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_MACS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_C_S, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set C->S MAC value '%s'",
|
||||
count, p);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_S_C, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set S->C MAC value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_LOGLEVEL:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
int value = -1;
|
||||
|
||||
if (strcasecmp(p, "quiet") == 0) {
|
||||
value = SSH_LOG_NONE;
|
||||
} else if (strcasecmp(p, "fatal") == 0 ||
|
||||
strcasecmp(p, "error")== 0 ||
|
||||
strcasecmp(p, "info") == 0) {
|
||||
value = SSH_LOG_WARN;
|
||||
} else if (strcasecmp(p, "verbose") == 0) {
|
||||
value = SSH_LOG_INFO;
|
||||
} else if (strcasecmp(p, "DEBUG") == 0 ||
|
||||
strcasecmp(p, "DEBUG1") == 0) {
|
||||
value = SSH_LOG_DEBUG;
|
||||
} else if (strcasecmp(p, "DEBUG2") == 0 ||
|
||||
strcasecmp(p, "DEBUG3") == 0) {
|
||||
value = SSH_LOG_TRACE;
|
||||
}
|
||||
if (value != -1) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY,
|
||||
&value);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set LogLevel value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_KEXALGORITHMS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_KEY_EXCHANGE, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set KexAlgorithms value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_MATCH: {
|
||||
bool negate;
|
||||
int result = PARSING;
|
||||
size_t args = 0;
|
||||
enum ssh_bind_config_match_e opt;
|
||||
const char *p2 = NULL;
|
||||
|
||||
/* The options set in Match blocks should be applied when a connection
|
||||
* is accepted, and not right away when parsing the file (as it is
|
||||
* currently done). This means the configuration files should be parsed
|
||||
* again or the options set in the Match blocks should be stored and
|
||||
* applied as necessary. */
|
||||
|
||||
/* If this is the first Match block, erase the seen table to allow
|
||||
* options to be overridden. Erasing the seen table was the easiest way
|
||||
* to allow overriding an option, but only for the first occurrence of
|
||||
* an option in a Match block. This is sufficient for the current
|
||||
* implementation which supports only the 'All' criterion, meaning the
|
||||
* options can be applied right away. */
|
||||
if (!(*parser_flags & IN_MATCH)) {
|
||||
memset(seen, 0x00, BIND_CFG_MAX * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
/* In this line the PARSING bit is cleared from the flags */
|
||||
*parser_flags = IN_MATCH;
|
||||
do {
|
||||
p = p2 = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
break;
|
||||
}
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_TRACE, "line %d: Processing Match keyword '%s'",
|
||||
count, p);
|
||||
|
||||
/* If the option is prefixed with ! the result should be negated */
|
||||
negate = false;
|
||||
if (p[0] == '!') {
|
||||
negate = true;
|
||||
p++;
|
||||
}
|
||||
|
||||
opt = ssh_bind_config_get_match_opcode(p);
|
||||
switch (opt) {
|
||||
case BIND_MATCH_ALL:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if ((args == 1) && (p == NULL || p[0] == '\0')) {
|
||||
/* The "all" keyword does not accept arguments or modifiers
|
||||
*/
|
||||
if (negate == true) {
|
||||
result = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ssh_set_error(bind, SSH_FATAL,
|
||||
"line %d: ERROR - Match all cannot be combined with "
|
||||
"other Match attributes", count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
case BIND_MATCH_USER:
|
||||
case BIND_MATCH_GROUP:
|
||||
case BIND_MATCH_HOST:
|
||||
case BIND_MATCH_LOCALADDRESS:
|
||||
case BIND_MATCH_LOCALPORT:
|
||||
case BIND_MATCH_RDOMAIN:
|
||||
case BIND_MATCH_ADDRESS:
|
||||
/* Only "All" is supported for now */
|
||||
/* Skip one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||
"'%s' requires argument\n", count, p2);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', ignoring\n",
|
||||
count,
|
||||
p2);
|
||||
result = 0;
|
||||
break;
|
||||
case BIND_MATCH_UNKNOWN:
|
||||
default:
|
||||
ssh_set_error(bind, SSH_FATAL,
|
||||
"ERROR - Unknown argument '%s' for Match keyword", p);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
} while (p != NULL && p[0] != '\0');
|
||||
if (args == 0) {
|
||||
ssh_set_error(bind, SSH_FATAL,
|
||||
"ERROR - Match keyword requires an argument");
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
/* This line only sets the PARSING flag if all checks passed */
|
||||
*parser_flags |= result;
|
||||
break;
|
||||
}
|
||||
case BIND_CFG_PUBKEY_ACCEPTED_KEY_TYPES:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind,
|
||||
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set PubKeyAcceptedKeyTypes value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_HOSTKEY_ALGORITHMS:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && (*parser_flags & PARSING)) {
|
||||
rc = ssh_bind_options_set(bind,
|
||||
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, p);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Failed to set HostkeyAlgorithms value '%s'",
|
||||
count, p);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BIND_CFG_NOT_ALLOWED_IN_MATCH:
|
||||
SSH_LOG(SSH_LOG_WARN, "Option not allowed in Match block: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
case BIND_CFG_UNKNOWN:
|
||||
SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
case BIND_CFG_UNSUPPORTED:
|
||||
SSH_LOG(SSH_LOG_WARN, "Unsupported option: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
case BIND_CFG_NA:
|
||||
SSH_LOG(SSH_LOG_WARN, "Option not applicable: %s, line: %d",
|
||||
keyword, count);
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(bind, SSH_FATAL, "ERROR - unimplemented opcode: %d",
|
||||
opcode);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
SAFE_FREE(x);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_bind_config_parse_file(ssh_bind bind, const char *filename)
|
||||
{
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
FILE *f;
|
||||
uint32_t parser_flags;
|
||||
int rv;
|
||||
|
||||
/* This local table is used during the parsing of the current file (and
|
||||
* files included recursively in this file) to prevent an option to be
|
||||
* redefined, i.e. the first value set is kept. But this DO NOT prevent the
|
||||
* option to be redefined later by another file. */
|
||||
uint8_t seen[BIND_CFG_MAX] = {0};
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename);
|
||||
|
||||
parser_flags = PARSING;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
rv = ssh_bind_config_parse_line(bind, line, count, &parser_flags, seen);
|
||||
if (rv) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
85
src/buffer.c
85
src/buffer.c
@@ -809,20 +809,20 @@ ssh_buffer_get_ssh_string(struct ssh_buffer_struct *buffer)
|
||||
*/
|
||||
static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
va_list ap)
|
||||
{
|
||||
const char *p = NULL;
|
||||
ssh_string string = NULL;
|
||||
char *cstring = NULL;
|
||||
size_t needed_size = 0;
|
||||
size_t len;
|
||||
size_t count;
|
||||
size_t len;
|
||||
int rc = SSH_OK;
|
||||
|
||||
for (p = format, count = 0; *p != '\0'; p++, count++) {
|
||||
/* Invalid number of arguments passed */
|
||||
if (count > argc) {
|
||||
if (argc != -1 && count > argc) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -881,7 +881,7 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != count) {
|
||||
if (argc != -1 && argc != count) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -891,7 +891,11 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
||||
*/
|
||||
uint32_t canary = va_arg(ap, uint32_t);
|
||||
if (canary != SSH_BUFFER_PACK_END) {
|
||||
abort();
|
||||
if (argc == -1){
|
||||
return SSH_ERROR;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,7 +918,7 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
|
||||
*/
|
||||
int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
va_list ap)
|
||||
{
|
||||
int rc = SSH_ERROR;
|
||||
@@ -930,15 +934,11 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
char *cstring;
|
||||
bignum b;
|
||||
size_t len;
|
||||
size_t count;
|
||||
|
||||
if (argc > 256) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
int count;
|
||||
|
||||
for (p = format, count = 0; *p != '\0'; p++, count++) {
|
||||
/* Invalid number of arguments passed */
|
||||
if (count > argc) {
|
||||
if (argc != -1 && count > argc) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -1010,15 +1010,19 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != count) {
|
||||
if (argc != -1 && argc != count) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (rc != SSH_ERROR){
|
||||
/* Check if our canary is intact, if not something really bad happened */
|
||||
/* Check if our canary is intact, if not somthing really bad happened */
|
||||
uint32_t canary = va_arg(ap, uint32_t);
|
||||
if (canary != SSH_BUFFER_PACK_END) {
|
||||
abort();
|
||||
if (argc == -1){
|
||||
return SSH_ERROR;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -1046,16 +1050,12 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
|
||||
*/
|
||||
int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
if (argc > 256) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
va_start(ap, argc);
|
||||
rc = ssh_buffer_pack_allocate_va(buffer, format, argc, ap);
|
||||
va_end(ap);
|
||||
@@ -1082,11 +1082,11 @@ int _ssh_buffer_pack(struct ssh_buffer_struct *buffer,
|
||||
*/
|
||||
int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
va_list ap)
|
||||
{
|
||||
int rc = SSH_ERROR;
|
||||
const char *p = format, *last;
|
||||
const char *p, *last;
|
||||
union {
|
||||
uint8_t *byte;
|
||||
uint16_t *word;
|
||||
@@ -1094,27 +1094,20 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
uint64_t *qword;
|
||||
ssh_string *string;
|
||||
char **cstring;
|
||||
bignum *bignum;
|
||||
void **data;
|
||||
} o;
|
||||
size_t len, rlen, max_len;
|
||||
ssh_string tmp_string = NULL;
|
||||
va_list ap_copy;
|
||||
size_t count;
|
||||
int count;
|
||||
|
||||
max_len = ssh_buffer_get_len(buffer);
|
||||
|
||||
/* copy the argument list in case a rollback is needed */
|
||||
va_copy(ap_copy, ap);
|
||||
|
||||
if (argc > 256) {
|
||||
rc = SSH_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (count = 0; *p != '\0'; p++, count++) {
|
||||
for (p = format, count = 0; *p != '\0'; p++, count++) {
|
||||
/* Invalid number of arguments passed */
|
||||
if (count > argc) {
|
||||
if (argc != -1 && count > argc) {
|
||||
rc = SSH_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -1143,19 +1136,6 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
*o.qword = ntohll(*o.qword);
|
||||
rc = rlen==8 ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'B':
|
||||
o.bignum = va_arg(ap, bignum *);
|
||||
*o.bignum = NULL;
|
||||
tmp_string = ssh_buffer_get_ssh_string(buffer);
|
||||
if (tmp_string == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
*o.bignum = ssh_make_string_bn(tmp_string);
|
||||
ssh_string_burn(tmp_string);
|
||||
SSH_STRING_FREE(tmp_string);
|
||||
rc = (*o.bignum != NULL) ? SSH_OK : SSH_ERROR;
|
||||
break;
|
||||
case 'S':
|
||||
o.string = va_arg(ap, ssh_string *);
|
||||
*o.string = ssh_buffer_get_ssh_string(buffer);
|
||||
@@ -1237,7 +1217,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != count) {
|
||||
if (argc != -1 && argc != count) {
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -1246,7 +1226,11 @@ cleanup:
|
||||
/* Check if our canary is intact, if not something really bad happened */
|
||||
uint32_t canary = va_arg(ap, uint32_t);
|
||||
if (canary != SSH_BUFFER_PACK_END){
|
||||
abort();
|
||||
if (argc == -1){
|
||||
rc = SSH_ERROR;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1283,10 +1267,6 @@ cleanup:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
o.bignum = va_arg(ap_copy, bignum *);
|
||||
bignum_safe_free(*o.bignum);
|
||||
break;
|
||||
case 'S':
|
||||
o.string = va_arg(ap_copy, ssh_string *);
|
||||
if (buffer->secure) {
|
||||
@@ -1333,7 +1313,6 @@ cleanup:
|
||||
* 's': char ** (C string, pulled as SSH string)
|
||||
* 'P': size_t, void ** (len of data, pointer to data)
|
||||
* only pulls data.
|
||||
* 'B': bignum * (pulled 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
|
||||
@@ -1341,7 +1320,7 @@ cleanup:
|
||||
*/
|
||||
int _ssh_buffer_unpack(struct ssh_buffer_struct *buffer,
|
||||
const char *format,
|
||||
size_t argc,
|
||||
int argc,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@@ -192,7 +192,6 @@ static void chacha20_cleanup(struct ssh_cipher_struct *cipher) {
|
||||
}
|
||||
|
||||
const struct ssh_cipher_struct chacha20poly1305_cipher = {
|
||||
.ciphertype = SSH_AEAD_CHACHA20_POLY1305,
|
||||
.name = "chacha20-poly1305@openssh.com",
|
||||
.blocksize = 8,
|
||||
.lenfield_blocksize = 4,
|
||||
|
||||
213
src/channels.c
213
src/channels.c
@@ -85,11 +85,6 @@ ssh_channel ssh_channel_new(ssh_session session)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check if we have an authenticated session */
|
||||
if (!(session->flags & SSH_SESSION_FLAG_AUTHENTICATED)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
channel = calloc(1, sizeof(struct ssh_channel_struct));
|
||||
if (channel == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
@@ -159,8 +154,8 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
|
||||
channel=ssh_channel_from_local(session,channelid);
|
||||
if(channel==NULL){
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Unknown channel id %"PRIu32,
|
||||
(uint32_t) channelid);
|
||||
"Unknown channel id %lu",
|
||||
(long unsigned int) channelid);
|
||||
/* TODO: Set error marking in channel object */
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
@@ -187,9 +182,9 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Remote window : %"PRIu32", maxpacket : %"PRIu32,
|
||||
(uint32_t) channel->remote_window,
|
||||
(uint32_t) channel->remote_maxpacket);
|
||||
"Remote window : %lu, maxpacket : %lu",
|
||||
(long unsigned int) channel->remote_window,
|
||||
(long unsigned int) channel->remote_maxpacket);
|
||||
|
||||
channel->state = SSH_CHANNEL_STATE_OPEN;
|
||||
channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
|
||||
@@ -235,9 +230,9 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
|
||||
}
|
||||
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Channel opening failure: channel %u error (%"PRIu32") %s",
|
||||
"Channel opening failure: channel %u error (%lu) %s",
|
||||
channel->local_channel,
|
||||
(uint32_t) code,
|
||||
(long unsigned int) code,
|
||||
error);
|
||||
SAFE_FREE(error);
|
||||
channel->state=SSH_CHANNEL_STATE_OPEN_DENIED;
|
||||
@@ -274,8 +269,6 @@ static int ssh_channel_open_termination(void *c){
|
||||
* @param[in] maxpacket The maximum packet size allowed (like MTU).
|
||||
*
|
||||
* @param[in] payload The buffer containing additional payload for the query.
|
||||
*
|
||||
* @return SSH_OK if successful; SSH_ERROR otherwise.
|
||||
*/
|
||||
static int channel_open(ssh_channel channel, const char *type, int window,
|
||||
int maxpacket, ssh_buffer payload) {
|
||||
@@ -371,7 +364,6 @@ ssh_channel ssh_channel_from_local(ssh_session session, uint32_t id) {
|
||||
* @param session SSH session
|
||||
* @param channel SSH channel
|
||||
* @param minimumsize The minimum acceptable size for the new window.
|
||||
* @return SSH_OK if successful; SSH_ERROR otherwise.
|
||||
*/
|
||||
static int grow_window(ssh_session session, ssh_channel channel, int minimumsize) {
|
||||
uint32_t new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE;
|
||||
@@ -427,7 +419,7 @@ error:
|
||||
* @param[in] packet The buffer to parse packet from. The read pointer will
|
||||
* be moved after the call.
|
||||
*
|
||||
* @return The related ssh_channel, or NULL if the channel is
|
||||
* @returns The related ssh_channel, or NULL if the channel is
|
||||
* unknown or the packet is invalid.
|
||||
*/
|
||||
static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
|
||||
@@ -445,8 +437,8 @@ static ssh_channel channel_from_msg(ssh_session session, ssh_buffer packet) {
|
||||
channel = ssh_channel_from_local(session, chan);
|
||||
if (channel == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Server specified invalid channel %"PRIu32,
|
||||
(uint32_t) chan);
|
||||
"Server specified invalid channel %lu",
|
||||
(long unsigned int) chan);
|
||||
}
|
||||
|
||||
return channel;
|
||||
@@ -692,10 +684,6 @@ SSH_PACKET_CALLBACK(channel_rcv_request) {
|
||||
if (strcmp(request,"exit-status") == 0) {
|
||||
SAFE_FREE(request);
|
||||
rc = ssh_buffer_unpack(packet, "d", &channel->exit_status);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_PACKET, "Invalid exit-status packet");
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PACKET, "received exit-status %d", channel->exit_status);
|
||||
|
||||
ssh_callbacks_execute_list(channel->callbacks,
|
||||
@@ -1004,88 +992,6 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open a TCP/IP - UNIX domain socket forwarding channel.
|
||||
*
|
||||
* @param[in] channel An allocated channel.
|
||||
*
|
||||
* @param[in] remotepath The UNIX socket path on the remote machine
|
||||
*
|
||||
* @param[in] sourcehost The numeric IP address of the machine from where the
|
||||
* connection request originates. This is mostly for
|
||||
* logging purposes.
|
||||
*
|
||||
* @param[in] localport The port on the host from where the connection
|
||||
* originated. This is mostly for logging purposes.
|
||||
*
|
||||
* @return SSH_OK on success,
|
||||
* SSH_ERROR if an error occurred,
|
||||
* SSH_AGAIN if in nonblocking mode and call has
|
||||
* to be done again.
|
||||
*
|
||||
* @warning This function does not bind the local port and does not
|
||||
* automatically forward the content of a socket to the channel.
|
||||
* You still have to use channel_read and channel_write for this.
|
||||
* @warning Requires support of OpenSSH for UNIX domain socket forwarding.
|
||||
*/
|
||||
int ssh_channel_open_forward_unix(ssh_channel channel,
|
||||
const char *remotepath,
|
||||
const char *sourcehost,
|
||||
int localport)
|
||||
{
|
||||
ssh_session session = NULL;
|
||||
ssh_buffer payload = NULL;
|
||||
ssh_string str = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
int version;
|
||||
|
||||
if (channel == NULL) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
session = channel->session;
|
||||
|
||||
version = ssh_get_openssh_version(session);
|
||||
if (version == 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"We're not connected to an OpenSSH server!");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (remotepath == NULL || sourcehost == NULL) {
|
||||
ssh_set_error_invalid(session);
|
||||
return rc;
|
||||
}
|
||||
|
||||
payload = ssh_buffer_new();
|
||||
if (payload == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(payload,
|
||||
"ssd",
|
||||
remotepath,
|
||||
sourcehost,
|
||||
localport);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = channel_open(channel,
|
||||
"direct-streamlocal@openssh.com",
|
||||
CHANNEL_INITIAL_WINDOW,
|
||||
CHANNEL_MAX_PACKET,
|
||||
payload);
|
||||
|
||||
error:
|
||||
ssh_buffer_free(payload);
|
||||
ssh_string_free(str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close and free a channel.
|
||||
@@ -1155,15 +1061,13 @@ void ssh_channel_do_free(ssh_channel channel)
|
||||
ssh_list_remove(session->channels, it);
|
||||
}
|
||||
|
||||
SSH_BUFFER_FREE(channel->stdout_buffer);
|
||||
SSH_BUFFER_FREE(channel->stderr_buffer);
|
||||
ssh_buffer_free(channel->stdout_buffer);
|
||||
ssh_buffer_free(channel->stderr_buffer);
|
||||
|
||||
if (channel->callbacks != NULL) {
|
||||
ssh_list_free(channel->callbacks);
|
||||
channel->callbacks = NULL;
|
||||
}
|
||||
|
||||
channel->session = NULL;
|
||||
SAFE_FREE(channel);
|
||||
}
|
||||
|
||||
@@ -1195,52 +1099,43 @@ void ssh_channel_do_free(ssh_channel channel)
|
||||
* @see ssh_channel_free()
|
||||
* @see ssh_channel_is_eof()
|
||||
*/
|
||||
int ssh_channel_send_eof(ssh_channel channel)
|
||||
{
|
||||
ssh_session session;
|
||||
int rc = SSH_ERROR;
|
||||
int err;
|
||||
int ssh_channel_send_eof(ssh_channel channel){
|
||||
ssh_session session;
|
||||
int rc = SSH_ERROR;
|
||||
int err;
|
||||
|
||||
if (channel == NULL || channel->session == NULL) {
|
||||
return rc;
|
||||
}
|
||||
if(channel == NULL) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* If the EOF has already been sent we're done here. */
|
||||
if (channel->local_eof != 0) {
|
||||
return SSH_OK;
|
||||
}
|
||||
session = channel->session;
|
||||
|
||||
session = channel->session;
|
||||
err = ssh_buffer_pack(session->out_buffer,
|
||||
"bd",
|
||||
SSH2_MSG_CHANNEL_EOF,
|
||||
channel->remote_channel);
|
||||
if (err != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = ssh_buffer_pack(session->out_buffer,
|
||||
"bd",
|
||||
SSH2_MSG_CHANNEL_EOF,
|
||||
channel->remote_channel);
|
||||
if (err != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a EOF on client channel (%d:%d)",
|
||||
channel->local_channel,
|
||||
channel->remote_channel);
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Sent a EOF on client channel (%d:%d)",
|
||||
channel->local_channel,
|
||||
channel->remote_channel);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_channel_flush(channel);
|
||||
if(rc == SSH_ERROR)
|
||||
goto error;
|
||||
|
||||
rc = ssh_channel_flush(channel);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
channel->local_eof = 1;
|
||||
channel->local_eof = 1;
|
||||
|
||||
return rc;
|
||||
return rc;
|
||||
error:
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1272,7 +1167,10 @@ int ssh_channel_close(ssh_channel channel)
|
||||
|
||||
session = channel->session;
|
||||
|
||||
rc = ssh_channel_send_eof(channel);
|
||||
if (channel->local_eof == 0) {
|
||||
rc = ssh_channel_send_eof(channel);
|
||||
}
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
@@ -1339,9 +1237,9 @@ static int ssh_waitsession_unblocked(void *s){
|
||||
* @brief Flushes a channel (and its session) until the output buffer
|
||||
* is empty, or timeout elapsed.
|
||||
* @param channel SSH channel
|
||||
* @return SSH_OK On success,
|
||||
* SSH_ERROR On error.
|
||||
* SSH_AGAIN Timeout elapsed (or in nonblocking mode).
|
||||
* @returns SSH_OK On success,
|
||||
* SSH_ERROR on error
|
||||
* SSH_AGAIN Timeout elapsed (or in nonblocking mode)
|
||||
*/
|
||||
int ssh_channel_flush(ssh_channel channel){
|
||||
return ssh_blocking_flush(channel->session, SSH_TIMEOUT_DEFAULT);
|
||||
@@ -2876,7 +2774,7 @@ int ssh_channel_read_timeout(ssh_channel channel,
|
||||
ctx.buffer = stdbuf;
|
||||
ctx.count = 1;
|
||||
|
||||
if (timeout_ms < SSH_TIMEOUT_DEFAULT) {
|
||||
if (timeout_ms < 0) {
|
||||
timeout_ms = SSH_TIMEOUT_INFINITE;
|
||||
}
|
||||
|
||||
@@ -2891,13 +2789,8 @@ int ssh_channel_read_timeout(ssh_channel channel,
|
||||
/*
|
||||
* If the channel is closed or in an error state, reading from it is an error
|
||||
*/
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (channel->state == SSH_CHANNEL_STATE_CLOSED) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Remote channel is closed.");
|
||||
if (session->session_state == SSH_SESSION_STATE_ERROR ||
|
||||
channel->state == SSH_CHANNEL_STATE_CLOSED) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) {
|
||||
@@ -3113,8 +3006,8 @@ static int ssh_channel_exit_status_termination(void *c){
|
||||
*
|
||||
* @param[in] channel The channel to get the status from.
|
||||
*
|
||||
* @return The exit status, -1 if no exit status has been returned
|
||||
* (yet), or SSH_ERROR on error.
|
||||
* @returns The exit status, -1 if no exit status has been returned
|
||||
* (yet).
|
||||
* @warning This function may block until a timeout (or never)
|
||||
* if the other side is not willing to close the channel.
|
||||
*
|
||||
@@ -3224,7 +3117,7 @@ static int count_ptrs(ssh_channel *ptrs) {
|
||||
*
|
||||
* @return SSH_OK on a successful operation, SSH_EINTR if the
|
||||
* select(2) syscall was interrupted, then relaunch the
|
||||
* function, or SSH_ERROR on error.
|
||||
* function.
|
||||
*/
|
||||
int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
|
||||
ssh_channel *exceptchans, struct timeval * timeout) {
|
||||
|
||||
30
src/client.c
30
src/client.c
@@ -38,9 +38,6 @@
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/dh.h"
|
||||
#ifdef WITH_GEX
|
||||
#include "libssh/dh-gex.h"
|
||||
#endif /* WITH_GEX */
|
||||
#include "libssh/ecdh.h"
|
||||
#include "libssh/threads.h"
|
||||
#include "libssh/misc.h"
|
||||
@@ -183,6 +180,7 @@ int ssh_send_banner(ssh_session session, int server)
|
||||
|
||||
if (server == 1) {
|
||||
if (session->opts.custombanner == NULL){
|
||||
len = strlen(banner);
|
||||
session->serverbanner = strdup(banner);
|
||||
if (session->serverbanner == NULL) {
|
||||
goto end;
|
||||
@@ -256,12 +254,6 @@ static int dh_handshake(ssh_session session) {
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
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;
|
||||
#endif /* WITH_GEX */
|
||||
#ifdef HAVE_ECDH
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
case SSH_KEX_ECDH_SHA2_NISTP384:
|
||||
@@ -279,7 +271,11 @@ static int dh_handshake(ssh_session session) {
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
case DH_STATE_INIT_SENT:
|
||||
/* wait until ssh_packet_dh_reply is called */
|
||||
break;
|
||||
@@ -399,7 +395,7 @@ static void ssh_client_connection_callback(ssh_session session)
|
||||
goto error;
|
||||
}
|
||||
set_status(session, 0.4f);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"SSH server banner: %s", session->serverbanner);
|
||||
|
||||
/* Here we analyze the different protocols the server allows. */
|
||||
@@ -531,16 +527,6 @@ int ssh_connect(ssh_session session) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* If the system configuration files were not yet processed, do it now */
|
||||
if (!session->opts.config_processed) {
|
||||
ret = ssh_options_parse_config(session, NULL);
|
||||
if (ret != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to process system configuration files");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ssh_options_apply(session);
|
||||
if (ret < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Couldn't apply options");
|
||||
@@ -750,7 +736,7 @@ error:
|
||||
}
|
||||
|
||||
const char *ssh_copyright(void) {
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2019 "
|
||||
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2018 "
|
||||
"Aris Adamantiadis, Andreas Schneider "
|
||||
"and libssh contributors. "
|
||||
"Distributed under the LGPL, please refer to COPYING "
|
||||
|
||||
568
src/config.c
568
src/config.c
@@ -31,10 +31,7 @@
|
||||
# include <glob.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "libssh/config_parser.h"
|
||||
#include "libssh/config.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
@@ -42,6 +39,45 @@
|
||||
|
||||
#define MAX_LINE_SIZE 1024
|
||||
|
||||
enum ssh_config_opcode_e {
|
||||
/* Unknown opcode */
|
||||
SOC_UNKNOWN = -3,
|
||||
/* Known and not applicable to libssh */
|
||||
SOC_NA = -2,
|
||||
/* Known but not supported by current libssh version */
|
||||
SOC_UNSUPPORTED = -1,
|
||||
SOC_HOST,
|
||||
SOC_MATCH,
|
||||
SOC_HOSTNAME,
|
||||
SOC_PORT,
|
||||
SOC_USERNAME,
|
||||
SOC_IDENTITY,
|
||||
SOC_CIPHERS,
|
||||
SOC_MACS,
|
||||
SOC_COMPRESSION,
|
||||
SOC_TIMEOUT,
|
||||
SOC_PROTOCOL,
|
||||
SOC_STRICTHOSTKEYCHECK,
|
||||
SOC_KNOWNHOSTS,
|
||||
SOC_PROXYCOMMAND,
|
||||
SOC_GSSAPISERVERIDENTITY,
|
||||
SOC_GSSAPICLIENTIDENTITY,
|
||||
SOC_GSSAPIDELEGATECREDENTIALS,
|
||||
SOC_INCLUDE,
|
||||
SOC_BINDADDRESS,
|
||||
SOC_GLOBALKNOWNHOSTSFILE,
|
||||
SOC_LOGLEVEL,
|
||||
SOC_HOSTKEYALGORITHMS,
|
||||
SOC_KEXALGORITHMS,
|
||||
SOC_GSSAPIAUTHENTICATION,
|
||||
SOC_KBDINTERACTIVEAUTHENTICATION,
|
||||
SOC_PASSWORDAUTHENTICATION,
|
||||
SOC_PUBKEYAUTHENTICATION,
|
||||
SOC_PUBKEYACCEPTEDTYPES,
|
||||
|
||||
SOC_END /* Keep this one last in the list */
|
||||
};
|
||||
|
||||
struct ssh_config_keyword_table_s {
|
||||
const char *name;
|
||||
enum ssh_config_opcode_e opcode;
|
||||
@@ -108,10 +144,10 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "numberofpasswordprompts", SOC_UNSUPPORTED},
|
||||
{ "pkcs11provider", SOC_UNSUPPORTED},
|
||||
{ "preferredauthentications", SOC_UNSUPPORTED},
|
||||
{ "proxyjump", SOC_PROXYJUMP},
|
||||
{ "proxyjump", SOC_UNSUPPORTED},
|
||||
{ "proxyusefdpass", SOC_UNSUPPORTED},
|
||||
{ "pubkeyacceptedtypes", SOC_PUBKEYACCEPTEDTYPES},
|
||||
{ "rekeylimit", SOC_REKEYLIMIT},
|
||||
{ "rekeylimit", SOC_UNSUPPORTED},
|
||||
{ "remotecommand", SOC_UNSUPPORTED},
|
||||
{ "revokedhostkeys", SOC_UNSUPPORTED},
|
||||
{ "rhostsrsaauthentication", SOC_UNSUPPORTED},
|
||||
@@ -147,14 +183,12 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
||||
{ "tunnel", SOC_NA},
|
||||
{ "tunneldevice", SOC_NA},
|
||||
{ "xauthlocation", SOC_NA},
|
||||
{ "pubkeyacceptedkeytypes", SOC_PUBKEYACCEPTEDTYPES},
|
||||
{ NULL, SOC_UNKNOWN }
|
||||
};
|
||||
|
||||
enum ssh_config_match_e {
|
||||
MATCH_UNKNOWN = -1,
|
||||
MATCH_ALL,
|
||||
MATCH_FINAL,
|
||||
MATCH_CANONICAL,
|
||||
MATCH_EXEC,
|
||||
MATCH_HOST,
|
||||
@@ -171,7 +205,6 @@ struct ssh_config_match_keyword_table_s {
|
||||
static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[] = {
|
||||
{ "all", MATCH_ALL },
|
||||
{ "canonical", MATCH_CANONICAL },
|
||||
{ "final", MATCH_FINAL },
|
||||
{ "exec", MATCH_EXEC },
|
||||
{ "host", MATCH_HOST },
|
||||
{ "originalhost", MATCH_ORIGINALHOST },
|
||||
@@ -181,7 +214,7 @@ static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[]
|
||||
};
|
||||
|
||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
unsigned int count, int *parsing);
|
||||
unsigned int count, int *parsing, int seen[]);
|
||||
|
||||
static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
|
||||
int i;
|
||||
@@ -195,47 +228,137 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
|
||||
return SOC_UNKNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
local_parse_file(ssh_session session,
|
||||
const char *filename,
|
||||
int *parsing)
|
||||
{
|
||||
FILE *f;
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
int rv;
|
||||
static char *ssh_config_get_cmd(char **str) {
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
|
||||
filename);
|
||||
return;
|
||||
/* Ignore leading spaces */
|
||||
for (c = *str; *c; c++) {
|
||||
if (! isblank(*c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s", filename);
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
rv = ssh_config_parse_line(session, line, count, parsing);
|
||||
if (rv < 0) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
if (*c == '\"') {
|
||||
for (r = ++c; *c; c++) {
|
||||
if (*c == '\"') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
for (r = c; *c; c++) {
|
||||
if (*c == '\n') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *ssh_config_get_token(char **str) {
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
c = ssh_config_get_cmd(str);
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (isblank(*c) || *c == '=') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static long ssh_config_get_long(char **str, long notfound) {
|
||||
char *p, *endp;
|
||||
long i;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
i = strtol(p, &endp, 10);
|
||||
if (p == endp) {
|
||||
return notfound;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
static const char *ssh_config_get_str_tok(char **str, const char *def) {
|
||||
char *p;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static int ssh_config_get_yesno(char **str, int notfound) {
|
||||
const char *p;
|
||||
|
||||
p = ssh_config_get_str_tok(str, NULL);
|
||||
if (p == NULL) {
|
||||
return notfound;
|
||||
}
|
||||
|
||||
if (strncasecmp(p, "yes", 3) == 0) {
|
||||
return 1;
|
||||
} else if (strncasecmp(p, "no", 2) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
static void local_parse_file(ssh_session session, const char *filename, int *parsing, int seen[]) {
|
||||
FILE *f;
|
||||
char line[MAX_LINE_SIZE] = {0};
|
||||
unsigned int count = 0;
|
||||
|
||||
if ((f = fopen(filename, "r")) == NULL) {
|
||||
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
|
||||
filename);
|
||||
return;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s", filename);
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
if (ssh_config_parse_line(session, line, count, parsing, seen) < 0) {
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
|
||||
static void local_parse_glob(ssh_session session,
|
||||
const char *fileglob,
|
||||
int *parsing)
|
||||
int *parsing,
|
||||
int seen[])
|
||||
{
|
||||
glob_t globbuf = {
|
||||
.gl_flags = 0,
|
||||
};
|
||||
int rt;
|
||||
size_t i;
|
||||
u_int i;
|
||||
|
||||
rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
|
||||
if (rt == GLOB_NOMATCH) {
|
||||
@@ -249,7 +372,7 @@ static void local_parse_glob(ssh_session session,
|
||||
}
|
||||
|
||||
for (i = 0; i < globbuf.gl_pathc; i++) {
|
||||
local_parse_file(session, globbuf.gl_pathv[i], parsing);
|
||||
local_parse_file(session, globbuf.gl_pathv[i], parsing, seen);
|
||||
}
|
||||
|
||||
globfree(&globbuf);
|
||||
@@ -290,112 +413,16 @@ ssh_config_match(char *value, const char *pattern, bool negate)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* @brief: Parse the ProxyJump configuration line and if parsing,
|
||||
* stores the result in the configuration option
|
||||
*/
|
||||
static int
|
||||
ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
||||
{
|
||||
char *c = NULL, *cp = NULL, *endp = NULL;
|
||||
char *username = NULL;
|
||||
char *hostname = NULL;
|
||||
char *port = NULL;
|
||||
char *next = NULL;
|
||||
int cmp, rv = SSH_ERROR;
|
||||
bool parse_entry = do_parsing;
|
||||
|
||||
/* Special value none disables the proxy */
|
||||
cmp = strcasecmp(s, "none");
|
||||
if (cmp == 0 && do_parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, s);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/* This is comma-separated list of [user@]host[:port] entries */
|
||||
c = strdup(s);
|
||||
if (c == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
cp = c;
|
||||
do {
|
||||
endp = strchr(cp, ',');
|
||||
if (endp != NULL) {
|
||||
/* Split out the token */
|
||||
*endp = '\0';
|
||||
}
|
||||
if (parse_entry) {
|
||||
/* We actually care only about the first item */
|
||||
rv = ssh_config_parse_uri(cp, &username, &hostname, &port);
|
||||
/* The rest of the list needs to be passed on */
|
||||
if (endp != NULL) {
|
||||
next = strdup(endp + 1);
|
||||
if (next == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
rv = SSH_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* The rest is just sanity-checked to avoid failures later */
|
||||
rv = ssh_config_parse_uri(cp, NULL, NULL, NULL);
|
||||
}
|
||||
if (rv != SSH_OK) {
|
||||
goto out;
|
||||
}
|
||||
parse_entry = 0;
|
||||
if (endp != NULL) {
|
||||
cp = endp + 1;
|
||||
} else {
|
||||
cp = NULL; /* end */
|
||||
}
|
||||
} while (cp != NULL);
|
||||
|
||||
if (hostname != NULL && do_parsing) {
|
||||
char com[512] = {0};
|
||||
|
||||
rv = snprintf(com, sizeof(com), "ssh%s%s%s%s%s%s -W [%%h]:%%p %s",
|
||||
username ? " -l " : "",
|
||||
username ? username : "",
|
||||
port ? " -p " : "",
|
||||
port ? port : "",
|
||||
next ? " -J " : "",
|
||||
next ? next : "",
|
||||
hostname);
|
||||
if (rv < 0 || rv >= (int)sizeof(com)) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Too long ProxyJump configuration line");
|
||||
rv = SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, com);
|
||||
}
|
||||
rv = SSH_OK;
|
||||
|
||||
out:
|
||||
SAFE_FREE(username);
|
||||
SAFE_FREE(hostname);
|
||||
SAFE_FREE(port);
|
||||
SAFE_FREE(next);
|
||||
SAFE_FREE(c);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_config_parse_line(ssh_session session,
|
||||
const char *line,
|
||||
unsigned int count,
|
||||
int *parsing)
|
||||
{
|
||||
static int ssh_config_parse_line(ssh_session session, const char *line,
|
||||
unsigned int count, int *parsing, int seen[]) {
|
||||
enum ssh_config_opcode_e opcode;
|
||||
const char *p = NULL, *p2 = NULL;
|
||||
char *s = NULL, *x = NULL;
|
||||
char *keyword = NULL;
|
||||
char *lowerhost = NULL;
|
||||
const char *p;
|
||||
char *s, *x;
|
||||
char *keyword;
|
||||
char *lowerhost;
|
||||
size_t len;
|
||||
int i, rv;
|
||||
uint8_t *seen = session->opts.options_seen;
|
||||
int i;
|
||||
long l;
|
||||
int64_t ll;
|
||||
|
||||
x = s = strdup(line);
|
||||
if (s == NULL) {
|
||||
@@ -424,7 +451,6 @@ ssh_config_parse_line(ssh_session session,
|
||||
opcode != SOC_MATCH &&
|
||||
opcode != SOC_INCLUDE &&
|
||||
opcode > SOC_UNSUPPORTED) { /* Ignore all unknown types here */
|
||||
/* Skip all the options that were already applied */
|
||||
if (seen[opcode] != 0) {
|
||||
SAFE_FREE(x);
|
||||
return 0;
|
||||
@@ -438,9 +464,9 @@ ssh_config_parse_line(ssh_session session,
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
|
||||
local_parse_glob(session, p, parsing);
|
||||
local_parse_glob(session, p, parsing, seen);
|
||||
#else
|
||||
local_parse_file(session, p, parsing);
|
||||
local_parse_file(session, p, parsing, seen);
|
||||
#endif /* HAVE_GLOB */
|
||||
}
|
||||
break;
|
||||
@@ -453,7 +479,7 @@ ssh_config_parse_line(ssh_session session,
|
||||
|
||||
*parsing = 0;
|
||||
do {
|
||||
p = p2 = ssh_config_get_str_tok(&s, NULL);
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
break;
|
||||
}
|
||||
@@ -472,10 +498,8 @@ ssh_config_parse_line(ssh_session session,
|
||||
switch (opt) {
|
||||
case MATCH_ALL:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (args <= 2 && (p == NULL || p[0] == '\0')) {
|
||||
/* The first or second, but last argument. The "all" keyword
|
||||
* can be prefixed with either "final" or "canonical"
|
||||
* keywords which do not have any effect here. */
|
||||
if (args == 1 && (p == NULL || p[0] == '\0')) {
|
||||
/* The first argument and end of line */
|
||||
if (negate == true) {
|
||||
result = 0;
|
||||
}
|
||||
@@ -483,53 +507,21 @@ ssh_config_parse_line(ssh_session session,
|
||||
}
|
||||
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"line %d: ERROR - Match all cannot be combined with "
|
||||
"line %d: ERROR - Match all can not be combined with "
|
||||
"other Match attributes", count);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
|
||||
case MATCH_FINAL:
|
||||
case MATCH_CANONICAL:
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', skipping",
|
||||
count,
|
||||
p);
|
||||
/* Not set any result here -- the result is dependent on the
|
||||
* following matches after this keyword */
|
||||
break;
|
||||
|
||||
case MATCH_EXEC:
|
||||
/* Skip to the end of line as unsupported */
|
||||
p = ssh_config_get_cmd(&s);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||
"'%s' requires argument", count, p2);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', ignoring",
|
||||
count,
|
||||
p2);
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
case MATCH_ORIGINALHOST:
|
||||
case MATCH_LOCALUSER:
|
||||
/* Skip one argument */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL || p[0] == '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
|
||||
"'%s' requires argument", count, p2);
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
args++;
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"line %d: Unsupported Match keyword '%s', ignoring",
|
||||
count,
|
||||
p2);
|
||||
FALL_THROUGH;
|
||||
case MATCH_CANONICAL:
|
||||
SSH_LOG(SSH_LOG_WARN, "line: %d: Unsupported Match keyword "
|
||||
"'%s', Ignoring\n", count, p);
|
||||
result = 0;
|
||||
break;
|
||||
|
||||
@@ -704,25 +696,10 @@ ssh_config_parse_line(ssh_session session,
|
||||
break;
|
||||
case SOC_PROXYCOMMAND:
|
||||
p = ssh_config_get_cmd(&s);
|
||||
/* We share the seen value with the ProxyJump */
|
||||
if (p && *parsing && !seen[SOC_PROXYJUMP]) {
|
||||
if (p && *parsing) {
|
||||
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
|
||||
}
|
||||
break;
|
||||
case SOC_PROXYJUMP:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL) {
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
/* We share the seen value with the ProxyCommand */
|
||||
rv = ssh_config_parse_proxy_jump(session, p,
|
||||
(*parsing && !seen[SOC_PROXYCOMMAND]));
|
||||
if (rv != SSH_OK) {
|
||||
SAFE_FREE(x);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SOC_GSSAPISERVERIDENTITY:
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p && *parsing) {
|
||||
@@ -796,141 +773,6 @@ ssh_config_parse_line(ssh_session session,
|
||||
ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
|
||||
}
|
||||
break;
|
||||
case SOC_REKEYLIMIT:
|
||||
/* Parse the data limit */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL) {
|
||||
break;
|
||||
} else if (strcmp(p, "default") == 0) {
|
||||
/* Default rekey limits enforced automaticaly */
|
||||
ll = 0;
|
||||
} else {
|
||||
char *endp = NULL;
|
||||
ll = strtoll(p, &endp, 10);
|
||||
if (p == endp || ll < 0) {
|
||||
/* No number or negative */
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
|
||||
break;
|
||||
}
|
||||
switch (*endp) {
|
||||
case 'G':
|
||||
if (ll > LLONG_MAX / 1024) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 1024;
|
||||
FALL_THROUGH;
|
||||
case 'M':
|
||||
if (ll > LLONG_MAX / 1024) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 1024;
|
||||
FALL_THROUGH;
|
||||
case 'K':
|
||||
if (ll > LLONG_MAX / 1024) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 1024;
|
||||
endp++;
|
||||
FALL_THROUGH;
|
||||
case '\0':
|
||||
/* just the number */
|
||||
break;
|
||||
default:
|
||||
/* Invalid suffix */
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
if (*endp != ' ' && *endp != '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN,
|
||||
"Invalid trailing characters after the rekey limit: %s",
|
||||
endp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ll > -1 && *parsing) {
|
||||
uint64_t v = (uint64_t)ll;
|
||||
ssh_options_set(session, SSH_OPTIONS_REKEY_DATA, &v);
|
||||
}
|
||||
/* Parse the time limit */
|
||||
p = ssh_config_get_str_tok(&s, NULL);
|
||||
if (p == NULL) {
|
||||
break;
|
||||
} else if (strcmp(p, "none") == 0) {
|
||||
ll = 0;
|
||||
} else {
|
||||
char *endp = NULL;
|
||||
ll = strtoll(p, &endp, 10);
|
||||
if (p == endp || ll < 0) {
|
||||
/* No number or negative */
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit");
|
||||
break;
|
||||
}
|
||||
switch (*endp) {
|
||||
case 'w':
|
||||
case 'W':
|
||||
if (ll > LLONG_MAX / 7) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 7;
|
||||
FALL_THROUGH;
|
||||
case 'd':
|
||||
case 'D':
|
||||
if (ll > LLONG_MAX / 24) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 24;
|
||||
FALL_THROUGH;
|
||||
case 'h':
|
||||
case 'H':
|
||||
if (ll > LLONG_MAX / 60) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 60;
|
||||
FALL_THROUGH;
|
||||
case 'm':
|
||||
case 'M':
|
||||
if (ll > LLONG_MAX / 60) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit");
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
ll = ll * 60;
|
||||
FALL_THROUGH;
|
||||
case 's':
|
||||
case 'S':
|
||||
endp++;
|
||||
FALL_THROUGH;
|
||||
case '\0':
|
||||
/* just the number */
|
||||
break;
|
||||
default:
|
||||
/* Invalid suffix */
|
||||
ll = -1;
|
||||
break;
|
||||
}
|
||||
if (*endp != '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "Invalid trailing characters after the"
|
||||
" rekey limit: %s", endp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ll > -1 && *parsing) {
|
||||
uint32_t v = (uint32_t)ll;
|
||||
ssh_options_set(session, SSH_OPTIONS_REKEY_TIME, &v);
|
||||
}
|
||||
break;
|
||||
case SOC_GSSAPIAUTHENTICATION:
|
||||
case SOC_KBDINTERACTIVEAUTHENTICATION:
|
||||
case SOC_PASSWORDAUTHENTICATION:
|
||||
@@ -957,7 +799,7 @@ ssh_config_parse_line(ssh_session session,
|
||||
}
|
||||
break;
|
||||
case SOC_NA:
|
||||
SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d",
|
||||
SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d\n",
|
||||
keyword, count);
|
||||
break;
|
||||
case SOC_UNSUPPORTED:
|
||||
@@ -965,7 +807,7 @@ ssh_config_parse_line(ssh_session session,
|
||||
keyword, count);
|
||||
break;
|
||||
case SOC_UNKNOWN:
|
||||
SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d",
|
||||
SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d\n",
|
||||
keyword, count);
|
||||
break;
|
||||
default:
|
||||
@@ -980,37 +822,29 @@ ssh_config_parse_line(ssh_session session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @brief Parse configuration file and set the options to the given session
|
||||
*
|
||||
* @params[in] session The ssh session
|
||||
* @params[in] filename The path to the ssh configuration file
|
||||
*
|
||||
* @returns 0 on successful parsing the configuration file, -1 on error
|
||||
*/
|
||||
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;
|
||||
/* ssh_config_parse_file */
|
||||
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;
|
||||
int seen[SOC_END - SOC_UNSUPPORTED] = {0};
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
if (rv < 0) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
if ((f = fopen(filename, "r")) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename);
|
||||
|
||||
parsing = 1;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
count++;
|
||||
if (ssh_config_parse_line(session, line, count, &parsing, seen) < 0) {
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* config_parser.c - Common configuration file parser functions
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libssh/config_parser.h"
|
||||
#include "libssh/priv.h"
|
||||
|
||||
char *ssh_config_get_cmd(char **str)
|
||||
{
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
/* Ignore leading spaces */
|
||||
for (c = *str; *c; c++) {
|
||||
if (! isblank(*c)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*c == '\"') {
|
||||
for (r = ++c; *c; c++) {
|
||||
if (*c == '\"') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (*c == '\n') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *ssh_config_get_token(char **str)
|
||||
{
|
||||
register char *c;
|
||||
char *r;
|
||||
|
||||
c = ssh_config_get_cmd(str);
|
||||
|
||||
for (r = c; *c; c++) {
|
||||
if (isblank(*c) || *c == '=') {
|
||||
*c = '\0';
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*str = c + 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
long ssh_config_get_long(char **str, long notfound)
|
||||
{
|
||||
char *p, *endp;
|
||||
long i;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
i = strtol(p, &endp, 10);
|
||||
if (p == endp) {
|
||||
return notfound;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
const char *ssh_config_get_str_tok(char **str, const char *def)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = ssh_config_get_token(str);
|
||||
if (p && *p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
int ssh_config_get_yesno(char **str, int notfound)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = ssh_config_get_str_tok(str, NULL);
|
||||
if (p == NULL) {
|
||||
return notfound;
|
||||
}
|
||||
|
||||
if (strncasecmp(p, "yes", 3) == 0) {
|
||||
return 1;
|
||||
} else if (strncasecmp(p, "no", 2) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return notfound;
|
||||
}
|
||||
|
||||
int ssh_config_parse_uri(const char *tok,
|
||||
char **username,
|
||||
char **hostname,
|
||||
char **port)
|
||||
{
|
||||
char *endp = NULL;
|
||||
long port_n;
|
||||
|
||||
/* Sanitize inputs */
|
||||
if (username != NULL) {
|
||||
*username = NULL;
|
||||
}
|
||||
if (hostname != NULL) {
|
||||
*hostname = NULL;
|
||||
}
|
||||
if (port != NULL) {
|
||||
*port = NULL;
|
||||
}
|
||||
|
||||
/* Username part (optional) */
|
||||
endp = strchr(tok, '@');
|
||||
if (endp != NULL) {
|
||||
/* Zero-length username is not valid */
|
||||
if (tok == endp) {
|
||||
goto error;
|
||||
}
|
||||
if (username != NULL) {
|
||||
*username = strndup(tok, endp - tok);
|
||||
if (*username == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
tok = endp + 1;
|
||||
/* If there is second @ character, this does not look like our URI */
|
||||
endp = strchr(tok, '@');
|
||||
if (endp != NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hostname */
|
||||
if (*tok == '[') {
|
||||
/* IPv6 address is enclosed with square brackets */
|
||||
tok++;
|
||||
endp = strchr(tok, ']');
|
||||
if (endp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
/* Hostnames or aliases expand to the last colon or to the end */
|
||||
endp = strrchr(tok, ':');
|
||||
if (endp == NULL) {
|
||||
endp = strchr(tok, '\0');
|
||||
}
|
||||
}
|
||||
if (tok == endp) {
|
||||
/* Zero-length hostnames are not valid */
|
||||
goto error;
|
||||
}
|
||||
if (hostname != NULL) {
|
||||
*hostname = strndup(tok, endp - tok);
|
||||
if (*hostname == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
/* Skip also the closing bracket */
|
||||
if (*endp == ']') {
|
||||
endp++;
|
||||
}
|
||||
|
||||
/* Port (optional) */
|
||||
if (*endp != '\0') {
|
||||
char *port_end = NULL;
|
||||
|
||||
/* Verify the port is valid positive number */
|
||||
port_n = strtol(endp + 1, &port_end, 10);
|
||||
if (port_n < 1 || *port_end != '\0') {
|
||||
SSH_LOG(SSH_LOG_WARN, "Failed to parse port number."
|
||||
" The value '%ld' is invalid or there are some"
|
||||
" trailing characters: '%s'", port_n, port_end);
|
||||
goto error;
|
||||
}
|
||||
if (port != NULL) {
|
||||
*port = strdup(endp + 1);
|
||||
if (*port == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
if (username != NULL) {
|
||||
SAFE_FREE(*username);
|
||||
}
|
||||
if (hostname != NULL) {
|
||||
SAFE_FREE(*hostname);
|
||||
}
|
||||
if (port != NULL) {
|
||||
SAFE_FREE(*port);
|
||||
}
|
||||
return SSH_ERROR;
|
||||
}
|
||||
542
src/connect.c
542
src/connect.c
@@ -90,55 +90,131 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef gai_strerror
|
||||
char WSAAPI *gai_strerrorA(int code)
|
||||
{
|
||||
static char buf[256];
|
||||
char WSAAPI *gai_strerrorA(int code) {
|
||||
static char buf[256];
|
||||
|
||||
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
|
||||
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
|
||||
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
#endif /* gai_strerror */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static int ssh_connect_socket_close(socket_t s)
|
||||
{
|
||||
static int ssh_connect_socket_close(socket_t s){
|
||||
#ifdef _WIN32
|
||||
return closesocket(s);
|
||||
return closesocket(s);
|
||||
#else
|
||||
return close(s);
|
||||
return close(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int getai(const char *host, int port, struct addrinfo **ai)
|
||||
{
|
||||
const char *service = NULL;
|
||||
struct addrinfo hints;
|
||||
char s_port[10];
|
||||
|
||||
ZERO_STRUCT(hints);
|
||||
static int getai(const char *host, int port, struct addrinfo **ai) {
|
||||
const char *service = NULL;
|
||||
struct addrinfo hints;
|
||||
char s_port[10];
|
||||
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
ZERO_STRUCT(hints);
|
||||
|
||||
if (port == 0) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
} else {
|
||||
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
|
||||
service = s_port;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (port == 0) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
} else {
|
||||
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
|
||||
service = s_port;
|
||||
#ifdef AI_NUMERICSERV
|
||||
hints.ai_flags = AI_NUMERICSERV;
|
||||
hints.ai_flags=AI_NUMERICSERV;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_is_ipaddr(host)) {
|
||||
/* this is an IP address */
|
||||
SSH_LOG(SSH_LOG_PACKET, "host %s matches an IP address", host);
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
if (ssh_is_ipaddr(host)) {
|
||||
/* this is an IP address */
|
||||
SSH_LOG(SSH_LOG_PACKET,"host %s matches an IP address",host);
|
||||
hints.ai_flags |= AI_NUMERICHOST;
|
||||
}
|
||||
|
||||
return getaddrinfo(host, service, &hints, ai);
|
||||
return getaddrinfo(host, service, &hints, ai);
|
||||
}
|
||||
|
||||
static int ssh_connect_ai_timeout(ssh_session session, const char *host,
|
||||
int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
|
||||
int timeout_ms;
|
||||
ssh_pollfd_t fds;
|
||||
int rc = 0;
|
||||
int ret;
|
||||
socklen_t len = sizeof(rc);
|
||||
|
||||
/* I know we're losing some precision. But it's not like poll-like family
|
||||
* type of mechanisms are precise up to the microsecond.
|
||||
*/
|
||||
timeout_ms=timeout * 1000 + usec / 1000;
|
||||
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket non-blocking for %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_RARE, "Trying to connect to host: %s:%d with "
|
||||
"timeout %d ms", host, port, timeout_ms);
|
||||
|
||||
/* The return value is checked later */
|
||||
connect(s, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
|
||||
fds.fd=s;
|
||||
fds.revents=0;
|
||||
fds.events=POLLOUT;
|
||||
#ifdef _WIN32
|
||||
fds.events |= POLLWRNORM;
|
||||
#endif
|
||||
rc = ssh_poll(&fds,1,timeout_ms);
|
||||
|
||||
if (rc == 0) {
|
||||
/* timeout */
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Timeout while connecting to %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"poll error: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
rc = -1;
|
||||
|
||||
/* Get connect(2) return code. Zero means no error */
|
||||
ret = getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len);
|
||||
if (ret < 0 || rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Connect to %s:%d failed: %s", host, port, strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* s is connected ? */
|
||||
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout");
|
||||
ret = ssh_socket_set_blocking(s);
|
||||
if (ret < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket as blocking connecting to %s:%d failed: %s",
|
||||
host, port, strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int set_tcp_nodelay(socket_t socket)
|
||||
@@ -152,6 +228,99 @@ static int set_tcp_nodelay(socket_t socket)
|
||||
sizeof(opt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Connect to an IPv4 or IPv6 host specified by its IP address or
|
||||
* hostname.
|
||||
*
|
||||
* @returns A file descriptor, < 0 on error.
|
||||
*/
|
||||
socket_t ssh_connect_host(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port, long timeout, long usec) {
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *itr;
|
||||
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
freeaddrinfo(ai);
|
||||
close(s);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout || usec) {
|
||||
socket_t ret = ssh_connect_ai_timeout(session, host, port, itr,
|
||||
timeout, usec, s);
|
||||
|
||||
freeaddrinfo(ai);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
} else {
|
||||
/* We are connected */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -162,109 +331,102 @@ static int set_tcp_nodelay(socket_t socket)
|
||||
* @warning very ugly !!!
|
||||
*/
|
||||
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
const char *bind_addr, int port)
|
||||
{
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai = NULL;
|
||||
struct addrinfo *itr = NULL;
|
||||
const char *bind_addr, int port) {
|
||||
socket_t s = -1;
|
||||
int rc;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *itr;
|
||||
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)",
|
||||
host, gai_strerror(rc));
|
||||
rc = getai(host, port, &ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next){
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (itr = ai; itr != NULL; itr = itr->ai_next) {
|
||||
/* create socket */
|
||||
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
|
||||
if (s < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Socket create failed: %s", strerror(errno));
|
||||
continue;
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
s=-1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
if (bind_addr) {
|
||||
struct addrinfo *bind_ai;
|
||||
struct addrinfo *bind_itr;
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket non-blocking for %s:%d", host, port);
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = getai(bind_addr, 0, &bind_ai);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to resolve bind address %s (%s)",
|
||||
bind_addr,
|
||||
gai_strerror(rc));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (bind_itr = bind_ai;
|
||||
bind_itr != NULL;
|
||||
bind_itr = bind_itr->ai_next)
|
||||
{
|
||||
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Binding local address: %s", strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(bind_ai);
|
||||
|
||||
/* Cannot bind to any local addresses */
|
||||
if (bind_itr == NULL) {
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ssh_socket_set_nonblocking(s);
|
||||
if (session->opts.nodelay) {
|
||||
/* For winsock, socket options are only effective before connect */
|
||||
rc = set_tcp_nodelay(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set socket non-blocking for %s:%d",
|
||||
host, port);
|
||||
"Failed to set TCP_NODELAY on socket: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (session->opts.nodelay) {
|
||||
/* For winsock, socket options are only effective before connect */
|
||||
rc = set_tcp_nodelay(s);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to set TCP_NODELAY on socket: %s",
|
||||
strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to connect: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
errno = 0;
|
||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Failed to connect: %s", strerror(errno));
|
||||
ssh_connect_socket_close(s);
|
||||
s = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
return s;
|
||||
break;
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,13 +435,11 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
* @{
|
||||
*/
|
||||
|
||||
static int ssh_select_cb (socket_t fd, int revents, void *userdata)
|
||||
{
|
||||
fd_set *set = (fd_set *)userdata;
|
||||
if (revents & POLLIN) {
|
||||
FD_SET(fd, set);
|
||||
}
|
||||
return 0;
|
||||
static int ssh_select_cb (socket_t fd, int revents, void *userdata){
|
||||
fd_set *set = (fd_set *)userdata;
|
||||
if(revents & POLLIN)
|
||||
FD_SET(fd, set);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,84 +473,72 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata)
|
||||
* @see select(2)
|
||||
*/
|
||||
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||
fd_set *readfds, struct timeval *timeout)
|
||||
{
|
||||
fd_set origfds;
|
||||
socket_t fd;
|
||||
size_t i, j;
|
||||
int rc;
|
||||
int base_tm, tm;
|
||||
struct ssh_timestamp ts;
|
||||
ssh_event event = ssh_event_new();
|
||||
int firstround = 1;
|
||||
fd_set *readfds, struct timeval *timeout) {
|
||||
fd_set origfds;
|
||||
socket_t fd;
|
||||
size_t i, j;
|
||||
int rc;
|
||||
int base_tm, tm;
|
||||
struct ssh_timestamp ts;
|
||||
ssh_event event = ssh_event_new();
|
||||
int firstround=1;
|
||||
|
||||
base_tm = tm = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
|
||||
for (i = 0 ; channels[i] != NULL; ++i) {
|
||||
ssh_event_add_session(event, channels[i]->session);
|
||||
base_tm = tm=timeout->tv_sec * 1000 + timeout->tv_usec/1000;
|
||||
for (i=0 ; channels[i] != NULL; ++i){
|
||||
ssh_event_add_session(event, channels[i]->session);
|
||||
}
|
||||
|
||||
FD_ZERO(&origfds);
|
||||
for (fd = 0; fd < maxfd ; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||
FD_SET(fd, &origfds);
|
||||
}
|
||||
}
|
||||
outchannels[0] = NULL;
|
||||
FD_ZERO(readfds);
|
||||
ssh_timestamp_init(&ts);
|
||||
do {
|
||||
/* Poll every channel */
|
||||
j = 0;
|
||||
for (i = 0; channels[i]; i++) {
|
||||
if(ssh_channel_poll(channels[i], 0) != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
} else if(ssh_channel_poll(channels[i], 1) != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
ZERO_STRUCT(origfds);
|
||||
FD_ZERO(&origfds);
|
||||
for (fd = 0; fd < maxfd ; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
|
||||
FD_SET(fd, &origfds);
|
||||
}
|
||||
}
|
||||
outchannels[0] = NULL;
|
||||
FD_ZERO(readfds);
|
||||
ssh_timestamp_init(&ts);
|
||||
do {
|
||||
/* Poll every channel */
|
||||
j = 0;
|
||||
for (i = 0; channels[i]; i++) {
|
||||
rc = ssh_channel_poll(channels[i], 0);
|
||||
if (rc != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
} else {
|
||||
rc = ssh_channel_poll(channels[i], 1);
|
||||
if (rc != 0) {
|
||||
outchannels[j] = channels[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outchannels[j] = NULL;
|
||||
if (j != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* watch if a user socket was triggered */
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the timeout is elapsed, we should go out */
|
||||
if (!firstround && ssh_timeout_elapsed(&ts, base_tm)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* since there's nothing, let's fire the polling */
|
||||
rc = ssh_event_dopoll(event,tm);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
tm = ssh_timeout_update(&ts, base_tm);
|
||||
firstround = 0;
|
||||
} while (1);
|
||||
out:
|
||||
outchannels[j] = NULL;
|
||||
if(j != 0)
|
||||
break;
|
||||
/* watch if a user socket was triggered */
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, &origfds)) {
|
||||
ssh_event_remove_fd(event, fd);
|
||||
if (FD_ISSET(fd, readfds)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ssh_event_free(event);
|
||||
return SSH_OK;
|
||||
|
||||
/* If the timeout is elapsed, we should go out */
|
||||
if(!firstround && ssh_timeout_elapsed(&ts, base_tm))
|
||||
goto out;
|
||||
/* since there's nothing, let's fire the polling */
|
||||
rc = ssh_event_dopoll(event,tm);
|
||||
if (rc == SSH_ERROR){
|
||||
goto out;
|
||||
}
|
||||
tm = ssh_timeout_update(&ts, base_tm);
|
||||
firstround=0;
|
||||
} while (1);
|
||||
out:
|
||||
for (fd = 0; fd < maxfd; fd++) {
|
||||
if (FD_ISSET(fd, &origfds)) {
|
||||
ssh_event_remove_fd(event, fd);
|
||||
}
|
||||
}
|
||||
ssh_event_free(event);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -267,13 +267,8 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
|
||||
|
||||
if (connector->out_channel != NULL) {
|
||||
if (r == 0) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "input fd %d is EOF", connector->in_fd);
|
||||
if (connector->out_channel->local_eof == 0) {
|
||||
rc = ssh_channel_send_eof(connector->out_channel);
|
||||
(void)rc; /* TODO Handle rc? */
|
||||
}
|
||||
connector->in_available = 1; /* Don't poll on it */
|
||||
return;
|
||||
rc = ssh_channel_send_eof(connector->out_channel);
|
||||
(void)rc; /* TODO Handle rc? */
|
||||
} else if (r> 0) {
|
||||
/* loop around ssh_channel_write in case our window reduced due to a race */
|
||||
while (total != r){
|
||||
@@ -294,7 +289,7 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
|
||||
}
|
||||
} else if (connector->out_fd != SSH_INVALID_SOCKET) {
|
||||
if (r == 0){
|
||||
close(connector->out_fd);
|
||||
close (connector->out_fd);
|
||||
connector->out_fd = SSH_INVALID_SOCKET;
|
||||
} else {
|
||||
/*
|
||||
|
||||
111
src/curve25519.c
111
src/curve25519.c
@@ -39,19 +39,6 @@
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply);
|
||||
|
||||
static ssh_packet_callback dh_client_callbacks[] = {
|
||||
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
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief Starts curve25519-sha256@libssh.org / curve25519-sha256 key exchange
|
||||
*/
|
||||
@@ -77,9 +64,7 @@ int ssh_client_curve25519_init(ssh_session session){
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_curve25519_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
return rc;
|
||||
@@ -88,6 +73,20 @@ int ssh_client_curve25519_init(ssh_session session){
|
||||
static int ssh_curve25519_build_k(ssh_session session) {
|
||||
ssh_curve25519_pubkey k;
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
session->next_crypto->k = bignum_new();
|
||||
|
||||
if (session->next_crypto->k == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
session->next_crypto->k = bignum_new();
|
||||
|
||||
if (session->next_crypto->k == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (session->server)
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_client_pubkey);
|
||||
@@ -95,17 +94,20 @@ static int ssh_curve25519_build_k(ssh_session session) {
|
||||
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
|
||||
session->next_crypto->curve25519_server_pubkey);
|
||||
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->k);
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
|
||||
#elif defined HAVE_LIBMBEDCRYPTO
|
||||
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
ssh_print_hexa("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -115,15 +117,11 @@ static int ssh_curve25519_build_k(ssh_session session) {
|
||||
* @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){
|
||||
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_curve25519_client_callbacks);
|
||||
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL) {
|
||||
@@ -173,47 +171,18 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
|
||||
}
|
||||
|
||||
rc=ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
return rc;
|
||||
error:
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#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 struct ssh_packet_callbacks_struct ssh_curve25519_server_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_INIT,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = dh_server_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief sets up the curve25519-sha256@libssh.org kex callbacks
|
||||
*/
|
||||
void ssh_server_curve25519_init(ssh_session session){
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_curve25519_server_callbacks);
|
||||
}
|
||||
|
||||
/** @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){
|
||||
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
@@ -224,24 +193,18 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
ssh_string sig_blob = NULL;
|
||||
int ok;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_curve25519_server_callbacks);
|
||||
|
||||
/* Extract the client pubkey from the init packet */
|
||||
q_c_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_c_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Incorrect size for server Curve25519 public key: %zu",
|
||||
ssh_string_len(q_c_string));
|
||||
ssh_string_free(q_c_string);
|
||||
goto error;
|
||||
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
|
||||
(int)ssh_string_len(q_c_string));
|
||||
ssh_string_free(q_c_string);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
memcpy(session->next_crypto->curve25519_client_pubkey,
|
||||
@@ -252,7 +215,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
|
||||
if (!ok) {
|
||||
ssh_set_error(session, SSH_FATAL, "PRNG error");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
|
||||
@@ -342,16 +305,12 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
return rc;
|
||||
error:
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
677
src/dh-gex.c
677
src/dh-gex.c
@@ -1,677 +0,0 @@
|
||||
/*
|
||||
* dh-gex.c - diffie-hellman group exchange
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2016 by Aris Adamantiadis <aris@0xbadc0de.be>
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/dh-gex.h"
|
||||
#include "libssh/libssh.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/callbacks.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
|
||||
/* Minimum, recommanded and maximum size of DH group */
|
||||
#define DH_PMIN 2048
|
||||
#define DH_PREQ 2048
|
||||
#define DH_PMAX 8192
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group);
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply);
|
||||
|
||||
static ssh_packet_callback dhgex_client_callbacks[] = {
|
||||
ssh_packet_client_dhgex_group, /* SSH_MSG_KEX_DH_GEX_GROUP */
|
||||
NULL, /* SSH_MSG_KEX_DH_GEX_INIT */
|
||||
ssh_packet_client_dhgex_reply /* SSH_MSG_KEX_DH_GEX_REPLY */
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_dhgex_client_callbacks = {
|
||||
.start = SSH2_MSG_KEX_DH_GEX_GROUP,
|
||||
.n_callbacks = 3,
|
||||
.callbacks = dhgex_client_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief initiates a diffie-hellman-group-exchange kex
|
||||
*/
|
||||
int ssh_client_dhgex_init(ssh_session session)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ssh_dh_init_common(session->next_crypto);
|
||||
if (rc != SSH_OK){
|
||||
goto error;
|
||||
}
|
||||
|
||||
session->next_crypto->dh_pmin = DH_PMIN;
|
||||
session->next_crypto->dh_pn = DH_PREQ;
|
||||
session->next_crypto->dh_pmax = DH_PMAX;
|
||||
/* Minimum group size, preferred group size, maximum group size */
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bddd",
|
||||
SSH2_MSG_KEX_DH_GEX_REQUEST,
|
||||
session->next_crypto->dh_pmin,
|
||||
session->next_crypto->dh_pn,
|
||||
session->next_crypto->dh_pmax);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_dhgex_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_REQUEST_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
return rc;
|
||||
error:
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief handle a DH_GEX_GROUP packet, client side. This packet contains
|
||||
* the group parameters.
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
|
||||
{
|
||||
int rc;
|
||||
int blen;
|
||||
bignum pmin1 = NULL, one = NULL;
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
bignum modulus, generator;
|
||||
const_bignum pubkey;
|
||||
(void) type;
|
||||
(void) user;
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_GROUP received");
|
||||
|
||||
if (bignum_ctx_invalid(ctx)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_REQUEST_SENT) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Received DH_GEX_GROUP in invalid state");
|
||||
goto error;
|
||||
}
|
||||
one = bignum_new();
|
||||
pmin1 = bignum_new();
|
||||
if (one == NULL || pmin1 == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_buffer_unpack(packet,
|
||||
"BB",
|
||||
&modulus,
|
||||
&generator);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid DH_GEX_GROUP packet");
|
||||
goto error;
|
||||
}
|
||||
/* basic checks */
|
||||
if (ssh_fips_mode() &&
|
||||
!ssh_dh_is_known_group(modulus, generator)) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"The received DH group is not FIPS approved");
|
||||
goto error;
|
||||
}
|
||||
rc = bignum_set_word(one, 1);
|
||||
if (rc != 1) {
|
||||
goto error;
|
||||
}
|
||||
blen = bignum_num_bits(modulus);
|
||||
if (blen < DH_PMIN || blen > DH_PMAX) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid dh group parameter p: %d not in [%d:%d]",
|
||||
blen,
|
||||
DH_PMIN,
|
||||
DH_PMAX);
|
||||
goto error;
|
||||
}
|
||||
if (bignum_cmp(modulus, one) <= 0) {
|
||||
/* p must be positive and preferably bigger than one */
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter p");
|
||||
}
|
||||
if (!bignum_is_bit_set(modulus, 0)) {
|
||||
/* p must be a prime and therefore not divisible by 2 */
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter p");
|
||||
goto error;
|
||||
}
|
||||
bignum_sub(pmin1, modulus, one);
|
||||
if (bignum_cmp(generator, one) <= 0 ||
|
||||
bignum_cmp(generator, pmin1) > 0) {
|
||||
/* generator must be at least 2 and smaller than p-1*/
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter g");
|
||||
goto error;
|
||||
}
|
||||
bignum_ctx_free(ctx);
|
||||
ctx = NULL;
|
||||
|
||||
/* all checks passed, set parameters */
|
||||
rc = ssh_dh_set_parameters(session->next_crypto->dh_ctx,
|
||||
modulus, generator);
|
||||
if (rc != SSH_OK) {
|
||||
bignum_safe_free(modulus);
|
||||
bignum_safe_free(generator);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* compute and send DH public parameter */
|
||||
rc = ssh_dh_keypair_gen_keys(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR, NULL, &pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bB",
|
||||
SSH2_MSG_KEX_DH_GEX_INIT,
|
||||
pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
bignum_safe_free(one);
|
||||
bignum_safe_free(pmin1);
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
error:
|
||||
bignum_safe_free(one);
|
||||
bignum_safe_free(pmin1);
|
||||
if(!bignum_ctx_invalid(ctx)) {
|
||||
bignum_ctx_free(ctx);
|
||||
}
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto=session->next_crypto;
|
||||
int rc;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
bignum server_pubkey = NULL;
|
||||
(void)type;
|
||||
(void)user;
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_REPLY received");
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
|
||||
rc = ssh_buffer_unpack(packet,
|
||||
"SBS",
|
||||
&pubkey_blob, &server_pubkey,
|
||||
&crypto->dh_server_signature);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid DH_GEX_REPLY packet");
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_dh_keypair_set_keys(crypto->dh_ctx, DH_SERVER_KEYPAIR,
|
||||
NULL, server_pubkey);
|
||||
if (rc != SSH_OK) {
|
||||
bignum_safe_free(server_pubkey);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
|
||||
ssh_string_free(pubkey_blob);
|
||||
if (rc != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_dh_compute_shared_secret(session->next_crypto->dh_ctx,
|
||||
DH_CLIENT_KEYPAIR, DH_SERVER_KEYPAIR,
|
||||
&session->next_crypto->shared_secret);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
error:
|
||||
ssh_dh_cleanup(session->next_crypto);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
#define MODULI_FILE "/etc/ssh/moduli"
|
||||
/* 2 "Safe" prime; (p-1)/2 is also prime. */
|
||||
#define SAFE_PRIME 2
|
||||
/* 0x04 Probabilistic Miller-Rabin primality tests. */
|
||||
#define PRIM_TEST_REQUIRED 0x04
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Determines if the proposed modulus size is more appropriate than the
|
||||
* current one.
|
||||
*
|
||||
* @returns 1 if it's more appropriate. Returns 0 if same or less appropriate
|
||||
*/
|
||||
static bool dhgroup_better_size(uint32_t pmin,
|
||||
uint32_t pn,
|
||||
uint32_t pmax,
|
||||
size_t current_size,
|
||||
size_t proposed_size)
|
||||
{
|
||||
if (current_size == proposed_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current_size == pn) {
|
||||
/* can't do better */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current_size == 0 && proposed_size >= pmin && proposed_size <= pmax) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (proposed_size < pmin || proposed_size > pmax) {
|
||||
/* out of bounds */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (current_size == 0) {
|
||||
/* not in the allowed window */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (proposed_size >= pn && proposed_size < current_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (proposed_size <= pn && proposed_size > current_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (proposed_size >= pn && current_size < pn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We're in the allowed window but a better match already exists. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief returns 1 with 1/n probability
|
||||
* @returns 1 on with P(1/n), 0 with P(n-1/n).
|
||||
*/
|
||||
static bool invn_chance(int n)
|
||||
{
|
||||
uint32_t nounce;
|
||||
ssh_get_random(&nounce, sizeof(nounce), 0);
|
||||
return (nounce % n) == 0;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief retrieves a DH group from an open moduli file.
|
||||
*/
|
||||
static int ssh_retrieve_dhgroup_file(FILE *moduli,
|
||||
uint32_t pmin,
|
||||
uint32_t pn,
|
||||
uint32_t pmax,
|
||||
size_t *best_size,
|
||||
char **best_generator,
|
||||
char **best_modulus)
|
||||
{
|
||||
char timestamp[32] = {0};
|
||||
char generator[32] = {0};
|
||||
char modulus[4096] = {0};
|
||||
size_t type, tests, tries, size, proposed_size;
|
||||
int firstbyte;
|
||||
int rc;
|
||||
size_t line = 0;
|
||||
size_t best_nlines = 0;
|
||||
|
||||
for(;;) {
|
||||
line++;
|
||||
firstbyte = getc(moduli);
|
||||
if (firstbyte == '#'){
|
||||
do {
|
||||
firstbyte = getc(moduli);
|
||||
} while(firstbyte != '\n' && firstbyte != EOF);
|
||||
continue;
|
||||
}
|
||||
if (firstbyte == EOF) {
|
||||
break;
|
||||
}
|
||||
ungetc(firstbyte, moduli);
|
||||
rc = fscanf(moduli,
|
||||
"%31s %zu %zu %zu %zu %31s %4095s\n",
|
||||
timestamp,
|
||||
&type,
|
||||
&tests,
|
||||
&tries,
|
||||
&size,
|
||||
generator,
|
||||
modulus);
|
||||
if (rc != 7){
|
||||
if (rc == EOF) {
|
||||
break;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_INFO, "Invalid moduli entry line %zu", line);
|
||||
do {
|
||||
firstbyte = getc(moduli);
|
||||
} while(firstbyte != '\n' && firstbyte != EOF);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we only want safe primes that were tested */
|
||||
if (type != SAFE_PRIME || !(tests & PRIM_TEST_REQUIRED)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
proposed_size = size + 1;
|
||||
if (proposed_size != *best_size &&
|
||||
dhgroup_better_size(pmin, pn, pmax, *best_size, proposed_size)) {
|
||||
best_nlines = 0;
|
||||
*best_size = proposed_size;
|
||||
}
|
||||
if (proposed_size == *best_size) {
|
||||
best_nlines++;
|
||||
}
|
||||
|
||||
/* Use reservoir sampling algorithm */
|
||||
if (proposed_size == *best_size && invn_chance(best_nlines)) {
|
||||
SAFE_FREE(*best_generator);
|
||||
SAFE_FREE(*best_modulus);
|
||||
*best_generator = strdup(generator);
|
||||
if (*best_generator == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
*best_modulus = strdup(modulus);
|
||||
if (*best_modulus == NULL) {
|
||||
SAFE_FREE(*best_generator);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*best_size != 0) {
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Selected %zu bits modulus out of %zu candidates in %zu lines",
|
||||
*best_size,
|
||||
best_nlines - 1,
|
||||
line);
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"No moduli found for [%u:%u:%u]",
|
||||
pmin,
|
||||
pn,
|
||||
pmax);
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief retrieves a DH group from the moduli file based on bits len parameters
|
||||
* @param[in] pmin minimum group size in bits
|
||||
* @param[in] pn preferred group size
|
||||
* @param[in] pmax maximum group size
|
||||
* @param[out] size size of the chosen modulus
|
||||
* @param[out] p modulus
|
||||
* @param[out] g generator
|
||||
* @return SSH_OK on success, SSH_ERROR otherwise.
|
||||
*/
|
||||
static int ssh_retrieve_dhgroup(uint32_t pmin,
|
||||
uint32_t pn,
|
||||
uint32_t pmax,
|
||||
size_t *size,
|
||||
bignum *p,
|
||||
bignum *g)
|
||||
{
|
||||
FILE *moduli = NULL;
|
||||
char *generator = NULL;
|
||||
char *modulus = NULL;
|
||||
int rc;
|
||||
|
||||
/* In FIPS mode, we can not negotiate arbitrary primes,
|
||||
* but just the approved ones */
|
||||
if (ssh_fips_mode()) {
|
||||
SSH_LOG(SSH_LOG_TRACE, "In FIPS mode, using built-in primes");
|
||||
return ssh_fallback_group(pmax, p, g);
|
||||
}
|
||||
|
||||
moduli = fopen(MODULI_FILE, "r");
|
||||
if (moduli == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"Unable to open moduli file: %s",
|
||||
strerror(errno));
|
||||
return ssh_fallback_group(pmax, p, g);
|
||||
}
|
||||
|
||||
*size = 0;
|
||||
*p = NULL;
|
||||
*g = NULL;
|
||||
|
||||
rc = ssh_retrieve_dhgroup_file(moduli,
|
||||
pmin,
|
||||
pn,
|
||||
pmax,
|
||||
size,
|
||||
&generator,
|
||||
&modulus);
|
||||
fclose(moduli);
|
||||
if (rc == SSH_ERROR || *size == 0) {
|
||||
goto error;
|
||||
}
|
||||
rc = bignum_hex2bn(generator, g);
|
||||
if (rc == 0) {
|
||||
goto error;
|
||||
}
|
||||
rc = bignum_hex2bn(modulus, p);
|
||||
if (rc == 0) {
|
||||
goto error;
|
||||
}
|
||||
SAFE_FREE(generator);
|
||||
SAFE_FREE(modulus);
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
error:
|
||||
bignum_safe_free(*g);
|
||||
bignum_safe_free(*p);
|
||||
SAFE_FREE(generator);
|
||||
SAFE_FREE(modulus);
|
||||
|
||||
return SSH_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 */
|
||||
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 */
|
||||
|
||||
};
|
||||
|
||||
static struct ssh_packet_callbacks_struct ssh_dhgex_server_callbacks = {
|
||||
.start = SSH2_MSG_KEX_DH_GEX_REQUEST_OLD,
|
||||
.n_callbacks = 5,
|
||||
.callbacks = dhgex_server_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief sets up the diffie-hellman-groupx kex callbacks
|
||||
*/
|
||||
void ssh_server_dhgex_init(ssh_session session){
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_dhgex_server_callbacks);
|
||||
ssh_dh_init_common(session->next_crypto);
|
||||
session->dh_handshake_state = DH_STATE_INIT;
|
||||
}
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request)
|
||||
{
|
||||
bignum modulus = NULL, generator = NULL;
|
||||
uint32_t pmin, pn, pmax;
|
||||
size_t size = 0;
|
||||
int rc;
|
||||
|
||||
(void) type;
|
||||
(void) user;
|
||||
|
||||
if (session->dh_handshake_state != DH_STATE_INIT) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Received DH_GEX_REQUEST in invalid state");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Minimum group size, preferred group size, maximum group size */
|
||||
rc = ssh_buffer_unpack(packet, "ddd", &pmin, &pn, &pmax);
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error_invalid(session);
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_INFO, "dh-gex: DHGEX_REQUEST[%u:%u:%u]", pmin, pn, pmax);
|
||||
|
||||
if (pmin > pn || pn > pmax || pn > DH_PMAX || pmax < DH_PMIN) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid dh-gex arguments [%u:%u:%u]",
|
||||
pmin,
|
||||
pn,
|
||||
pmax);
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->dh_pmin = pmin;
|
||||
session->next_crypto->dh_pn = pn;
|
||||
session->next_crypto->dh_pmax = pmax;
|
||||
|
||||
/* ensure safe parameters */
|
||||
if (pmin < DH_PMIN) {
|
||||
pmin = DH_PMIN;
|
||||
if (pn < pmin) {
|
||||
pn = pmin;
|
||||
}
|
||||
}
|
||||
rc = ssh_retrieve_dhgroup(pmin,
|
||||
pn,
|
||||
pmax,
|
||||
&size,
|
||||
&modulus,
|
||||
&generator);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Couldn't find DH group for [%u:%u:%u]",
|
||||
pmin,
|
||||
pn,
|
||||
pmax);
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_dh_set_parameters(session->next_crypto->dh_ctx,
|
||||
modulus, generator);
|
||||
if (rc != SSH_OK) {
|
||||
bignum_safe_free(generator);
|
||||
bignum_safe_free(modulus);
|
||||
goto error;
|
||||
}
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bBB",
|
||||
SSH2_MSG_KEX_DH_GEX_GROUP,
|
||||
modulus,
|
||||
generator);
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
bignum_safe_free(generator);
|
||||
bignum_safe_free(modulus);
|
||||
#endif
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_invalid(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_GROUP_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief parse an incoming SSH_MSG_KEX_DH_GEX_INIT packet and complete
|
||||
* Diffie-Hellman key exchange
|
||||
**/
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_init){
|
||||
(void) type;
|
||||
(void) user;
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_KEX_DHGEX_INIT");
|
||||
ssh_packet_remove_callbacks(session, &ssh_dhgex_server_callbacks);
|
||||
ssh_server_dh_process_init(session, packet);
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
263
src/dh_crypto.c
263
src/dh_crypto.c
@@ -1,263 +0,0 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2019 by Simo Sorce - Red Hat, Inc.
|
||||
*
|
||||
* The SSH Library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#include "openssl/crypto.h"
|
||||
#include "openssl/dh.h"
|
||||
#include "libcrypto-compat.h"
|
||||
|
||||
extern bignum ssh_dh_generator;
|
||||
extern bignum ssh_dh_group1;
|
||||
extern bignum ssh_dh_group14;
|
||||
extern bignum ssh_dh_group16;
|
||||
extern bignum ssh_dh_group18;
|
||||
|
||||
struct dh_ctx {
|
||||
DH *keypair[2];
|
||||
};
|
||||
|
||||
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
|
||||
const_bignum *priv, const_bignum *pub)
|
||||
{
|
||||
if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
|
||||
((priv == NULL) && (pub == NULL)) || (ctx == NULL) ||
|
||||
(ctx->keypair[peer] == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
DH_get0_key(ctx->keypair[peer], pub, priv);
|
||||
if (priv && (*priv == NULL || bignum_num_bits(*priv) == 0)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (pub && (*pub == NULL || bignum_num_bits(*pub) == 0)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
|
||||
const bignum priv, const bignum pub)
|
||||
{
|
||||
bignum priv_key = NULL;
|
||||
bignum pub_key = NULL;
|
||||
|
||||
if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
|
||||
((priv == NULL) && (pub == NULL)) || (ctx == NULL) ||
|
||||
(ctx->keypair[peer] == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (priv) {
|
||||
priv_key = priv;
|
||||
}
|
||||
if (pub) {
|
||||
pub_key = pub;
|
||||
}
|
||||
(void)DH_set0_key(ctx->keypair[peer], pub_key, priv_key);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_get_parameters(struct dh_ctx *ctx,
|
||||
const_bignum *modulus, const_bignum *generator)
|
||||
{
|
||||
if (ctx == NULL || ctx->keypair[0] == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
DH_get0_pqg(ctx->keypair[0], modulus, NULL, generator);
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_set_parameters(struct dh_ctx *ctx,
|
||||
const bignum modulus, const bignum generator)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((ctx == NULL) || (modulus == NULL) || (generator == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
bignum p = NULL;
|
||||
bignum g = NULL;
|
||||
|
||||
/* when setting modulus or generator,
|
||||
* make sure to invalidate existing keys */
|
||||
DH_free(ctx->keypair[i]);
|
||||
ctx->keypair[i] = DH_new();
|
||||
if (ctx->keypair[i] == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
p = BN_dup(modulus);
|
||||
g = BN_dup(generator);
|
||||
rc = DH_set0_pqg(ctx->keypair[i], p, NULL, g);
|
||||
if (rc != 1) {
|
||||
BN_free(p);
|
||||
BN_free(g);
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
rc = SSH_OK;
|
||||
done:
|
||||
if (rc != SSH_OK) {
|
||||
DH_free(ctx->keypair[0]);
|
||||
DH_free(ctx->keypair[1]);
|
||||
ctx->keypair[0] = NULL;
|
||||
ctx->keypair[1] = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief allocate and initialize ephemeral values used in dh kex
|
||||
*/
|
||||
int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
struct dh_ctx *ctx;
|
||||
int rc;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
crypto->dh_ctx = ctx;
|
||||
|
||||
switch (crypto->kex_type) {
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group1, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group14, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP16_SHA512:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group16, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group18, ssh_dh_generator);
|
||||
break;
|
||||
default:
|
||||
rc = SSH_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_dh_cleanup(crypto);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ssh_dh_cleanup(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
if (crypto->dh_ctx != NULL) {
|
||||
DH_free(crypto->dh_ctx->keypair[0]);
|
||||
DH_free(crypto->dh_ctx->keypair[1]);
|
||||
free(crypto->dh_ctx);
|
||||
crypto->dh_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief generates a secret DH parameter of at least DH_SECURITY_BITS
|
||||
* security as well as the corresponding public key.
|
||||
* @param[out] parms a dh_ctx that will hold the new keys.
|
||||
* @param peer Select either client or server key storage. Valid values are:
|
||||
* DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR
|
||||
*
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int ssh_dh_keypair_gen_keys(struct dh_ctx *dh_ctx, int peer)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((dh_ctx == NULL) || (dh_ctx->keypair[peer] == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
rc = DH_generate_key(dh_ctx->keypair[peer]);
|
||||
if (rc != 1) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief generates a shared secret between the local peer and the remote
|
||||
* peer. The local peer must have been initialized using either the
|
||||
* ssh_dh_keypair_gen_keys() function or by seetting manually both
|
||||
* the private and public keys. The remote peer only needs to have
|
||||
* the remote's peer public key set.
|
||||
* @param[in] local peer identifier (DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR)
|
||||
* @param[in] remote peer identifier (DH_CLIENT_KEYPAIR or DH_SERVER_KEYPAIR)
|
||||
* @param[out] dest a new bignum with the shared secret value is returned.
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
|
||||
bignum *dest)
|
||||
{
|
||||
unsigned char *kstring = NULL;
|
||||
const_bignum pub_key = NULL;
|
||||
int klen, rc;
|
||||
|
||||
if ((dh_ctx == NULL) ||
|
||||
(dh_ctx->keypair[local] == NULL) ||
|
||||
(dh_ctx->keypair[remote] == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
kstring = malloc(DH_size(dh_ctx->keypair[local]));
|
||||
if (kstring == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = ssh_dh_keypair_get_keys(dh_ctx, remote, NULL, &pub_key);
|
||||
if (rc != SSH_OK) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
klen = DH_compute_key(kstring, pub_key, dh_ctx->keypair[local]);
|
||||
if (klen == -1) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*dest = BN_bin2bn(kstring, klen, NULL);
|
||||
if (*dest == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = SSH_OK;
|
||||
done:
|
||||
free(kstring);
|
||||
return rc;
|
||||
}
|
||||
378
src/dh_key.c
378
src/dh_key.c
@@ -1,378 +0,0 @@
|
||||
/*
|
||||
* dh-int.c - Diffie-Helman algorithm code against SSH 2
|
||||
*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2003-2018 by Aris Adamantiadis
|
||||
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
|
||||
* Copyright (c) 2012 by Dmitriy Kuznetsov <dk@yandex.ru>
|
||||
* Copyright (c) 2019 by Simo Sorce <simo@redhat.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; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* The SSH Library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with the SSH Library; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
extern bignum ssh_dh_generator;
|
||||
extern bignum ssh_dh_group1;
|
||||
extern bignum ssh_dh_group14;
|
||||
extern bignum ssh_dh_group16;
|
||||
extern bignum ssh_dh_group18;
|
||||
|
||||
/*
|
||||
* How many bits of security we want for fast DH. DH private key size must be
|
||||
* twice that size.
|
||||
*/
|
||||
#define DH_SECURITY_BITS 512
|
||||
|
||||
struct dh_keypair {
|
||||
bignum priv_key;
|
||||
bignum pub_key;
|
||||
};
|
||||
|
||||
struct dh_ctx {
|
||||
/* 0 is client, 1 is server */
|
||||
struct dh_keypair keypair[2];
|
||||
bignum generator;
|
||||
bignum modulus;
|
||||
};
|
||||
|
||||
static void ssh_dh_free_modulus(struct dh_ctx *ctx)
|
||||
{
|
||||
if ((ctx->modulus != ssh_dh_group1) &&
|
||||
(ctx->modulus != ssh_dh_group14) &&
|
||||
(ctx->modulus != ssh_dh_group16) &&
|
||||
(ctx->modulus != ssh_dh_group18)) {
|
||||
bignum_safe_free(ctx->modulus);
|
||||
}
|
||||
ctx->modulus = NULL;
|
||||
}
|
||||
|
||||
static void ssh_dh_free_generator(struct dh_ctx *ctx)
|
||||
{
|
||||
if (ctx->generator != ssh_dh_generator) {
|
||||
bignum_safe_free(ctx->generator);
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh_dh_free_dh_keypair(struct dh_keypair *keypair)
|
||||
{
|
||||
bignum_safe_free(keypair->priv_key);
|
||||
bignum_safe_free(keypair->pub_key);
|
||||
}
|
||||
|
||||
static int ssh_dh_init_dh_keypair(struct dh_keypair *keypair)
|
||||
{
|
||||
int rc;
|
||||
|
||||
keypair->priv_key = bignum_new();
|
||||
if (keypair->priv_key == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
keypair->pub_key = bignum_new();
|
||||
if (keypair->pub_key == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = SSH_OK;
|
||||
done:
|
||||
if (rc != SSH_OK) {
|
||||
ssh_dh_free_dh_keypair(keypair);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
|
||||
const_bignum *priv, const_bignum *pub)
|
||||
{
|
||||
if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
|
||||
((priv == NULL) && (pub == NULL)) || (ctx == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (priv) {
|
||||
/* check that we have something in it */
|
||||
if (bignum_num_bits(ctx->keypair[peer].priv_key)) {
|
||||
*priv = ctx->keypair[peer].priv_key;
|
||||
} else {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (pub) {
|
||||
/* check that we have something in it */
|
||||
if (bignum_num_bits(ctx->keypair[peer].pub_key)) {
|
||||
*pub = ctx->keypair[peer].pub_key;
|
||||
} else {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
|
||||
bignum priv, bignum pub)
|
||||
{
|
||||
if (((peer != DH_CLIENT_KEYPAIR) && (peer != DH_SERVER_KEYPAIR)) ||
|
||||
((priv == NULL) && (pub == NULL)) || (ctx == NULL)) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (priv) {
|
||||
bignum_safe_free(ctx->keypair[peer].priv_key);
|
||||
ctx->keypair[peer].priv_key = priv;
|
||||
}
|
||||
if (pub) {
|
||||
bignum_safe_free(ctx->keypair[peer].pub_key);
|
||||
ctx->keypair[peer].pub_key = pub;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_get_parameters(struct dh_ctx *ctx,
|
||||
const_bignum *modulus, const_bignum *generator)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if (modulus) {
|
||||
*modulus = ctx->modulus;
|
||||
}
|
||||
if (generator) {
|
||||
*generator = ctx->generator;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
int ssh_dh_set_parameters(struct dh_ctx *ctx,
|
||||
bignum modulus, bignum generator)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((ctx == NULL) || ((modulus == NULL) && (generator == NULL))) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* when setting modulus or generator,
|
||||
* make sure to invalidate existing keys */
|
||||
ssh_dh_free_dh_keypair(&ctx->keypair[DH_CLIENT_KEYPAIR]);
|
||||
ssh_dh_free_dh_keypair(&ctx->keypair[DH_SERVER_KEYPAIR]);
|
||||
|
||||
rc = ssh_dh_init_dh_keypair(&ctx->keypair[DH_CLIENT_KEYPAIR]);
|
||||
if (rc != SSH_OK) {
|
||||
goto done;
|
||||
}
|
||||
rc = ssh_dh_init_dh_keypair(&ctx->keypair[DH_SERVER_KEYPAIR]);
|
||||
if (rc != SSH_OK) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (modulus) {
|
||||
ssh_dh_free_modulus(ctx);
|
||||
ctx->modulus = modulus;
|
||||
}
|
||||
if (generator) {
|
||||
ssh_dh_free_generator(ctx);
|
||||
ctx->generator = generator;
|
||||
}
|
||||
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief allocate and initialize ephemeral values used in dh kex
|
||||
*/
|
||||
int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
struct dh_ctx *ctx = NULL;
|
||||
int rc;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
switch (crypto->kex_type) {
|
||||
case SSH_KEX_DH_GROUP1_SHA1:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group1, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group14, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP16_SHA512:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group16, ssh_dh_generator);
|
||||
break;
|
||||
case SSH_KEX_DH_GROUP18_SHA512:
|
||||
rc = ssh_dh_set_parameters(ctx, ssh_dh_group18, ssh_dh_generator);
|
||||
break;
|
||||
default:
|
||||
rc = SSH_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
crypto->dh_ctx = ctx;
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_dh_cleanup(crypto);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ssh_dh_cleanup(struct ssh_crypto_struct *crypto)
|
||||
{
|
||||
struct dh_ctx *ctx = crypto->dh_ctx;
|
||||
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_dh_free_dh_keypair(&ctx->keypair[DH_CLIENT_KEYPAIR]);
|
||||
ssh_dh_free_dh_keypair(&ctx->keypair[DH_SERVER_KEYPAIR]);
|
||||
|
||||
ssh_dh_free_modulus(ctx);
|
||||
ssh_dh_free_generator(ctx);
|
||||
free(ctx);
|
||||
crypto->dh_ctx = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CRYPTO
|
||||
static void ssh_dh_debug(ssh_session session)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = session->next_crypto;
|
||||
const_bignum x, y, e, f;
|
||||
ssh_dh_keypair_get_keys(crypto->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
|
||||
ssh_dh_keypair_get_keys(crypto->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
|
||||
ssh_print_bignum("p", crypto->dh_ctx->modulus);
|
||||
ssh_print_bignum("g", crypto->dh_ctx->generator);
|
||||
ssh_print_bignum("x", x);
|
||||
ssh_print_bignum("y", y);
|
||||
ssh_print_bignum("e", e);
|
||||
ssh_print_bignum("f", f);
|
||||
|
||||
ssh_print_hexa("Session server cookie",
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("k", session->next_crypto->shared_secret);
|
||||
}
|
||||
#else
|
||||
#define ssh_dh_debug(session)
|
||||
#endif
|
||||
|
||||
/** @internal
|
||||
* @brief generates a secret DH parameter of at least DH_SECURITY_BITS
|
||||
* security as well as the corresponding public key.
|
||||
* @param[out] parms a dh_kex paramters structure with preallocated bignum
|
||||
* where to store the parameters
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int ssh_dh_keypair_gen_keys(struct dh_ctx *dh_ctx, int peer)
|
||||
{
|
||||
bignum tmp = NULL;
|
||||
bignum_CTX ctx = NULL;
|
||||
int rc = 0;
|
||||
int bits = 0;
|
||||
int p_bits = 0;
|
||||
|
||||
ctx = bignum_ctx_new();
|
||||
if (bignum_ctx_invalid(ctx)){
|
||||
goto error;
|
||||
}
|
||||
tmp = bignum_new();
|
||||
if (tmp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
p_bits = bignum_num_bits(dh_ctx->modulus);
|
||||
/* we need at most DH_SECURITY_BITS */
|
||||
bits = MIN(DH_SECURITY_BITS * 2, p_bits);
|
||||
/* ensure we're not too close of p so rnd()%p stays uniform */
|
||||
if (bits <= p_bits && bits + 64 > p_bits) {
|
||||
bits += 64;
|
||||
}
|
||||
rc = bignum_rand(tmp, bits);
|
||||
if (rc != 1) {
|
||||
goto error;
|
||||
}
|
||||
rc = bignum_mod(dh_ctx->keypair[peer].priv_key, tmp, dh_ctx->modulus, ctx);
|
||||
if (rc != 1) {
|
||||
goto error;
|
||||
}
|
||||
/* Now compute the corresponding public key */
|
||||
rc = bignum_mod_exp(dh_ctx->keypair[peer].pub_key, dh_ctx->generator,
|
||||
dh_ctx->keypair[peer].priv_key, dh_ctx->modulus, ctx);
|
||||
if (rc != 1) {
|
||||
goto error;
|
||||
}
|
||||
bignum_safe_free(tmp);
|
||||
bignum_ctx_free(ctx);
|
||||
return SSH_OK;
|
||||
error:
|
||||
bignum_safe_free(tmp);
|
||||
bignum_ctx_free(ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/** @internal
|
||||
* @brief generates a shared secret between the local peer and the remote peer
|
||||
* @param[in] local peer identifier
|
||||
* @param[in] remote peer identifier
|
||||
* @param[out] dest a preallocated bignum where to store parameter
|
||||
* @return SSH_OK on success, SSH_ERROR on error
|
||||
*/
|
||||
int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
|
||||
bignum *dest)
|
||||
{
|
||||
int rc;
|
||||
bignum_CTX ctx = bignum_ctx_new();
|
||||
if (bignum_ctx_invalid(ctx)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*dest == NULL) {
|
||||
*dest = bignum_new();
|
||||
if (*dest == NULL) {
|
||||
rc = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
rc = bignum_mod_exp(*dest, dh_ctx->keypair[remote].pub_key,
|
||||
dh_ctx->keypair[local].priv_key,
|
||||
dh_ctx->modulus, ctx);
|
||||
|
||||
done:
|
||||
bignum_ctx_free(ctx);
|
||||
ssh_dh_debug(session);
|
||||
if (rc != 1) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
51
src/ecdh.c
51
src/ecdh.c
@@ -30,32 +30,16 @@
|
||||
|
||||
#ifdef HAVE_ECDH
|
||||
|
||||
static SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply);
|
||||
|
||||
static ssh_packet_callback ecdh_client_callbacks[]= {
|
||||
ssh_packet_client_ecdh_reply
|
||||
};
|
||||
|
||||
struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_REPLY,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = ecdh_client_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
|
||||
* a SSH_MSG_NEWKEYS
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){
|
||||
int ssh_client_ecdh_reply(ssh_session session, ssh_buffer packet){
|
||||
ssh_string q_s_string = NULL;
|
||||
ssh_string pubkey_blob = NULL;
|
||||
ssh_string signature = NULL;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||
pubkey_blob = ssh_buffer_get_ssh_string(packet);
|
||||
if (pubkey_blob == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No public key in packet");
|
||||
@@ -93,39 +77,10 @@ SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){
|
||||
}
|
||||
|
||||
rc=ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
return rc;
|
||||
error:
|
||||
session->session_state=SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
static ssh_packet_callback ecdh_server_callbacks[] = {
|
||||
ssh_packet_server_ecdh_init
|
||||
};
|
||||
|
||||
struct ssh_packet_callbacks_struct ssh_ecdh_server_callbacks = {
|
||||
.start = SSH2_MSG_KEX_ECDH_INIT,
|
||||
.n_callbacks = 1,
|
||||
.callbacks = ecdh_server_callbacks,
|
||||
.user = NULL
|
||||
};
|
||||
|
||||
/** @internal
|
||||
* @brief sets up the ecdh kex callbacks
|
||||
*/
|
||||
void ssh_server_ecdh_init(ssh_session session){
|
||||
ssh_packet_set_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
#endif /* HAVE_ECDH */
|
||||
|
||||
@@ -108,10 +108,6 @@ int ssh_client_ecdh_init(ssh_session session){
|
||||
session->next_crypto->ecdh_privkey = key;
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
return rc;
|
||||
@@ -128,6 +124,12 @@ int ecdh_build_k(ssh_session session) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
session->next_crypto->k = bignum_new();
|
||||
if (session->next_crypto->k == NULL) {
|
||||
bignum_ctx_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pubkey = EC_POINT_new(group);
|
||||
if (pubkey == NULL) {
|
||||
bignum_ctx_free(ctx);
|
||||
@@ -170,13 +172,9 @@ int ecdh_build_k(ssh_session session) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bignum_bin2bn(buffer, len, &session->next_crypto->shared_secret);
|
||||
bignum_bin2bn(buffer, len, session->next_crypto->k);
|
||||
free(buffer);
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
EC_KEY_free(session->next_crypto->ecdh_privkey);
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
EC_KEY_free(session->next_crypto->ecdh_privkey);
|
||||
session->next_crypto->ecdh_privkey = NULL;
|
||||
|
||||
@@ -185,7 +183,7 @@ int ecdh_build_k(ssh_session session) {
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -193,10 +191,11 @@ int ecdh_build_k(ssh_session session) {
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
/** @brief Handle a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
* SSH_MSG_KEXDH_REPLY
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
ssh_string q_s_string;
|
||||
@@ -211,15 +210,12 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
int curve;
|
||||
int len;
|
||||
int rc;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||
/* Extract the client pubkey from the init packet */
|
||||
q_c_string = ssh_buffer_get_ssh_string(packet);
|
||||
if (q_c_string == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
session->next_crypto->ecdh_client_pubkey = q_c_string;
|
||||
|
||||
@@ -237,7 +233,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
if (ecdh_key == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
BN_CTX_free(ctx);
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
group = EC_KEY_get0_group(ecdh_key);
|
||||
@@ -255,7 +251,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
if (q_s_string == NULL) {
|
||||
EC_KEY_free(ecdh_key);
|
||||
BN_CTX_free(ctx);
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
EC_POINT_point2oct(group,
|
||||
@@ -273,25 +269,25 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
rc = ecdh_build_k(session);
|
||||
if (rc < 0) {
|
||||
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* privkey is not allocated */
|
||||
rc = ssh_get_key_params(session, &privkey);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_make_sessionid(session);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
|
||||
if (sig_blob == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
|
||||
@@ -313,33 +309,26 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent");
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Send the MSG_NEWKEYS */
|
||||
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
|
||||
if (rc < 0) {
|
||||
goto error;
|
||||
return SSH_ERROR;;
|
||||
}
|
||||
|
||||
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
if (rc == SSH_ERROR){
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
error:
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
return SSH_PACKET_USED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
@@ -106,10 +106,6 @@ int ssh_client_ecdh_init(ssh_session session)
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
client_pubkey = NULL;
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
out:
|
||||
@@ -198,9 +194,8 @@ int ecdh_build_k(ssh_session session)
|
||||
goto out;
|
||||
}
|
||||
|
||||
session->next_crypto->shared_secret = gcry_mpi_new(0);
|
||||
gcry_mpi_point_snatch_get(session->next_crypto->shared_secret,
|
||||
NULL, NULL, point);
|
||||
session->next_crypto->k = gcry_mpi_new(0);
|
||||
gcry_mpi_point_snatch_get(session->next_crypto->k, NULL, NULL, point);
|
||||
#else
|
||||
s = ssh_sexp_extract_mpi(result, "s", GCRYMPI_FMT_USG, GCRYMPI_FMT_USG);
|
||||
if (s == NULL) {
|
||||
@@ -225,7 +220,7 @@ int ecdh_build_k(ssh_session session)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = gcry_mpi_scan(&session->next_crypto->shared_secret,
|
||||
err = gcry_mpi_scan(&session->next_crypto->k,
|
||||
GCRYMPI_FMT_USG,
|
||||
(const char *)ssh_string_data(s) + 1,
|
||||
k_len / 2,
|
||||
@@ -246,7 +241,7 @@ int ecdh_build_k(ssh_session session)
|
||||
session->next_crypto->server_kex.cookie, 16);
|
||||
ssh_print_hexa("Session client cookie",
|
||||
session->next_crypto->client_kex.cookie, 16);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
|
||||
ssh_print_bignum("Shared secret key", session->next_crypto->k);
|
||||
#endif
|
||||
|
||||
out:
|
||||
@@ -260,11 +255,10 @@ int ecdh_build_k(ssh_session session)
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
|
||||
/** @brief Handle a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
|
||||
* SSH_MSG_KEXDH_REPLY
|
||||
*/
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) {
|
||||
gpg_error_t err;
|
||||
/* ECDH keys */
|
||||
ssh_string q_c_string;
|
||||
@@ -277,10 +271,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
ssh_string pubkey_blob = NULL;
|
||||
int rc = SSH_ERROR;
|
||||
const char *curve = NULL;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
||||
if (curve == NULL) {
|
||||
goto out;
|
||||
@@ -385,11 +376,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
out:
|
||||
gcry_sexp_release(param);
|
||||
gcry_sexp_release(key);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
}
|
||||
return SSH_PACKET_USED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
@@ -106,9 +106,6 @@ int ssh_client_ecdh_init(ssh_session session)
|
||||
session->next_crypto->ecdh_client_pubkey = client_pubkey;
|
||||
client_pubkey = NULL;
|
||||
|
||||
/* register the packet callbacks */
|
||||
ssh_packet_set_callbacks(session, &ssh_ecdh_client_callbacks);
|
||||
session->dh_handshake_state = DH_STATE_INIT_SENT;
|
||||
rc = ssh_packet_send(session);
|
||||
|
||||
out:
|
||||
@@ -154,16 +151,16 @@ int ecdh_build_k(ssh_session session)
|
||||
goto out;
|
||||
}
|
||||
|
||||
session->next_crypto->shared_secret = malloc(sizeof(mbedtls_mpi));
|
||||
if (session->next_crypto->shared_secret == NULL) {
|
||||
session->next_crypto->k = malloc(sizeof(mbedtls_mpi));
|
||||
if (session->next_crypto->k == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mbedtls_mpi_init(session->next_crypto->shared_secret);
|
||||
mbedtls_mpi_init(session->next_crypto->k);
|
||||
|
||||
rc = mbedtls_ecdh_compute_shared(&grp,
|
||||
session->next_crypto->shared_secret,
|
||||
session->next_crypto->k,
|
||||
&pubkey,
|
||||
&session->next_crypto->ecdh_privkey->d,
|
||||
mbedtls_ctr_drbg_random,
|
||||
@@ -182,8 +179,8 @@ out:
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet)
|
||||
{
|
||||
ssh_string q_c_string = NULL;
|
||||
ssh_string q_s_string = NULL;
|
||||
mbedtls_ecp_group grp;
|
||||
@@ -192,10 +189,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
ssh_string pubkey_blob = NULL;
|
||||
int rc;
|
||||
mbedtls_ecp_group_id curve;
|
||||
(void)type;
|
||||
(void)user;
|
||||
|
||||
ssh_packet_remove_callbacks(session, &ssh_ecdh_server_callbacks);
|
||||
curve = ecdh_kex_type_to_curve(session->next_crypto->kex_type);
|
||||
if (curve == MBEDTLS_ECP_DP_NONE) {
|
||||
return SSH_ERROR;
|
||||
@@ -311,11 +305,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
|
||||
|
||||
out:
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
if (rc == SSH_ERROR) {
|
||||
ssh_buffer_reinit(session->out_buffer);
|
||||
session->session_state = SSH_SESSION_STATE_ERROR;
|
||||
}
|
||||
return SSH_PACKET_USED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
16
src/external/ed25519.c
vendored
16
src/external/ed25519.c
vendored
@@ -63,9 +63,9 @@ static void get_hram(unsigned char *hram,
|
||||
const unsigned char *sm,
|
||||
const unsigned char *pk,
|
||||
unsigned char *playground,
|
||||
uint64_t smlen)
|
||||
unsigned long long smlen)
|
||||
{
|
||||
uint64_t i;
|
||||
unsigned long long i;
|
||||
SHA512CTX ctx;
|
||||
for (i = 0;i < 32;++i) playground[i] = sm[i];
|
||||
for (i = 32;i < 64;++i) playground[i] = pk[i-32];
|
||||
@@ -111,9 +111,9 @@ int crypto_sign_ed25519_keypair(unsigned char *pk,
|
||||
}
|
||||
|
||||
int crypto_sign_ed25519(unsigned char *sm,
|
||||
uint64_t *smlen,
|
||||
unsigned long long *smlen,
|
||||
const unsigned char *m,
|
||||
uint64_t mlen,
|
||||
unsigned long long mlen,
|
||||
const unsigned char *sk)
|
||||
{
|
||||
sc25519 sck, scs, scsk;
|
||||
@@ -122,7 +122,7 @@ int crypto_sign_ed25519(unsigned char *sm,
|
||||
unsigned char r[32];
|
||||
unsigned char s[32];
|
||||
unsigned char extsk[64];
|
||||
uint64_t i;
|
||||
unsigned long long i;
|
||||
unsigned char hmg[SHA512_DIGEST_LEN];
|
||||
unsigned char hram[SHA512_DIGEST_LEN];
|
||||
|
||||
@@ -174,9 +174,9 @@ int crypto_sign_ed25519(unsigned char *sm,
|
||||
}
|
||||
|
||||
int crypto_sign_ed25519_open(unsigned char *m,
|
||||
uint64_t *mlen,
|
||||
unsigned long long *mlen,
|
||||
const unsigned char *sm,
|
||||
uint64_t smlen,
|
||||
unsigned long long smlen,
|
||||
const unsigned char *pk)
|
||||
{
|
||||
unsigned int i;
|
||||
@@ -186,7 +186,7 @@ int crypto_sign_ed25519_open(unsigned char *m,
|
||||
sc25519 schram, scs;
|
||||
unsigned char hram[SHA512_DIGEST_LEN];
|
||||
|
||||
*mlen = (uint64_t) -1;
|
||||
*mlen = (unsigned long long) -1;
|
||||
if (smlen < 64) return -1;
|
||||
|
||||
if (ge25519_unpackneg_vartime(&get1, pk)) {
|
||||
|
||||
@@ -99,26 +99,4 @@ char *ssh_gcry_bn2dec(bignum bn) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @brief generates a random integer between 0 and max
|
||||
* @returns 1 in case of success, 0 otherwise
|
||||
*/
|
||||
int ssh_gcry_rand_range(bignum dest, bignum max)
|
||||
{
|
||||
size_t bits;
|
||||
bignum rnd;
|
||||
int rc;
|
||||
|
||||
bits = bignum_num_bits(max) + 64;
|
||||
rnd = bignum_new();
|
||||
if (rnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
rc = bignum_rand(rnd, bits);
|
||||
if (rc != 1) {
|
||||
return rc;
|
||||
}
|
||||
gcry_mpi_mod(dest, rnd, max);
|
||||
bignum_safe_free(rnd);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
33
src/gssapi.c
33
src/gssapi.c
@@ -172,10 +172,10 @@ static void ssh_gssapi_log_error(int verb,
|
||||
|
||||
out:
|
||||
if (msg_maj.value) {
|
||||
gss_release_buffer(&dummy_min, &msg_maj);
|
||||
dummy_maj = gss_release_buffer(&dummy_min, &msg_maj);
|
||||
}
|
||||
if (msg_min.value) {
|
||||
gss_release_buffer(&dummy_min, &msg_min);
|
||||
dummy_maj = gss_release_buffer(&dummy_min, &msg_min);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,15 +217,6 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
|
||||
gss_create_empty_oid_set(&min_stat, &both_supported);
|
||||
|
||||
maj_stat = gss_indicate_mechs(&min_stat, &supported);
|
||||
if (maj_stat != GSS_S_COMPLETE) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "indicate mecks %d, %d", maj_stat, min_stat);
|
||||
ssh_gssapi_log_error(SSH_LOG_WARNING,
|
||||
"indicate mechs",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
for (i=0; i < supported->count; ++i){
|
||||
ptr = ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Supported mech %zu: %s", i, ptr);
|
||||
@@ -328,10 +319,7 @@ static char *ssh_gssapi_name_to_char(gss_name_t name){
|
||||
"converting name",
|
||||
maj_stat,
|
||||
min_stat);
|
||||
ptr = malloc(buffer.length + 1);
|
||||
if (ptr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ptr=malloc(buffer.length + 1);
|
||||
memcpy(ptr, buffer.value, buffer.length);
|
||||
ptr[buffer.length] = '\0';
|
||||
gss_release_buffer(&min_stat, &buffer);
|
||||
@@ -438,10 +426,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
static ssh_buffer ssh_gssapi_build_mic(ssh_session session)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
ssh_buffer mic_buffer = NULL;
|
||||
static ssh_buffer ssh_gssapi_build_mic(ssh_session session){
|
||||
ssh_buffer mic_buffer;
|
||||
int rc;
|
||||
|
||||
mic_buffer = ssh_buffer_new();
|
||||
@@ -450,11 +436,10 @@ static ssh_buffer ssh_gssapi_build_mic(ssh_session session)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_BOTH);
|
||||
rc = ssh_buffer_pack(mic_buffer,
|
||||
"dPbsss",
|
||||
crypto->digest_len,
|
||||
(size_t)crypto->digest_len, crypto->session_id,
|
||||
session->current_crypto->digest_len,
|
||||
(size_t)session->current_crypto->digest_len, session->current_crypto->session_id,
|
||||
SSH2_MSG_USERAUTH_REQUEST,
|
||||
session->gssapi->user,
|
||||
"ssh-connection",
|
||||
@@ -797,10 +782,6 @@ static gss_OID ssh_gssapi_oid_from_string(ssh_string oid_s){
|
||||
return NULL;
|
||||
}
|
||||
ret->elements = malloc(len - 2);
|
||||
if (ret->elements == NULL) {
|
||||
SAFE_FREE(ret);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ret->elements, &data[2], len-2);
|
||||
ret->length = len-2;
|
||||
|
||||
|
||||
25
src/gzip.c
25
src/gzip.c
@@ -55,10 +55,8 @@ static z_stream *initcompress(ssh_session session, int level) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
static ssh_buffer gzip_compress(ssh_session session, ssh_buffer source, int level)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
z_stream *zout = NULL;
|
||||
static ssh_buffer gzip_compress(ssh_session session,ssh_buffer source,int level){
|
||||
z_stream *zout = session->current_crypto->compress_out_ctx;
|
||||
void *in_ptr = ssh_buffer_get(source);
|
||||
unsigned long in_size = ssh_buffer_get_len(source);
|
||||
ssh_buffer dest = NULL;
|
||||
@@ -66,13 +64,8 @@ static ssh_buffer gzip_compress(ssh_session session, ssh_buffer source, int leve
|
||||
unsigned long len;
|
||||
int status;
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT);
|
||||
if (crypto == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
zout = crypto->compress_out_ctx;
|
||||
if (zout == NULL) {
|
||||
zout = crypto->compress_out_ctx = initcompress(session, level);
|
||||
if(zout == NULL) {
|
||||
zout = session->current_crypto->compress_out_ctx = initcompress(session, level);
|
||||
if (zout == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -150,10 +143,8 @@ static z_stream *initdecompress(ssh_session session) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t maxlen)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
z_stream *zin = NULL;
|
||||
static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t maxlen) {
|
||||
z_stream *zin = session->current_crypto->compress_in_ctx;
|
||||
void *in_ptr = ssh_buffer_get(source);
|
||||
unsigned long in_size = ssh_buffer_get_len(source);
|
||||
unsigned char out_buf[BLOCKSIZE] = {0};
|
||||
@@ -161,10 +152,8 @@ static ssh_buffer gzip_decompress(ssh_session session, ssh_buffer source, size_t
|
||||
unsigned long len;
|
||||
int status;
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
|
||||
zin = crypto->compress_in_ctx;
|
||||
if (zin == NULL) {
|
||||
zin = crypto->compress_in_ctx = initdecompress(session);
|
||||
zin = session->current_crypto->compress_in_ctx = initdecompress(session);
|
||||
if (zin == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ void libssh_constructor(void)
|
||||
* If the library is already initialized, increments the _ssh_initialized
|
||||
* counter and return the error code cached in _ssh_init_ret.
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
* @returns 0 on success, -1 if an error occured.
|
||||
*/
|
||||
int ssh_init(void) {
|
||||
return _ssh_init(0);
|
||||
@@ -188,7 +188,7 @@ _ret:
|
||||
*
|
||||
* This function is automatically called when the library is unloaded.
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_ERROR if an error occurred.
|
||||
* @returns 0 on succes, -1 if an error occured.
|
||||
*
|
||||
*/
|
||||
void libssh_destructor(void)
|
||||
|
||||
167
src/kdf.c
167
src/kdf.c
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* This file is part of the SSH Library
|
||||
*
|
||||
* Copyright (c) 2009 by Aris Adamantiadis
|
||||
* Copyrihgt (c) 2018 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/misc.h"
|
||||
#include "libssh/dh.h"
|
||||
#include "libssh/ssh2.h"
|
||||
#include "libssh/pki.h"
|
||||
#include "libssh/bignum.h"
|
||||
|
||||
#include "libssh/string.h"
|
||||
|
||||
|
||||
/* The following implements the SSHKDF for crypto backend that
|
||||
* do not have a native implementations */
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_kdf_digest digest_type;
|
||||
union {
|
||||
SHACTX sha1_ctx;
|
||||
SHA256CTX sha256_ctx;
|
||||
SHA384CTX sha384_ctx;
|
||||
SHA512CTX sha512_ctx;
|
||||
} ctx;
|
||||
};
|
||||
|
||||
static ssh_mac_ctx ssh_mac_ctx_init(enum ssh_kdf_digest type)
|
||||
{
|
||||
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->digest_type = type;
|
||||
switch(type){
|
||||
case SSH_KDF_SHA1:
|
||||
ctx->ctx.sha1_ctx = sha1_init();
|
||||
return ctx;
|
||||
case SSH_KDF_SHA256:
|
||||
ctx->ctx.sha256_ctx = sha256_init();
|
||||
return ctx;
|
||||
case SSH_KDF_SHA384:
|
||||
ctx->ctx.sha384_ctx = sha384_init();
|
||||
return ctx;
|
||||
case SSH_KDF_SHA512:
|
||||
ctx->ctx.sha512_ctx = sha512_init();
|
||||
return ctx;
|
||||
default:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh_mac_update(ssh_mac_ctx ctx, const void *data, size_t len)
|
||||
{
|
||||
switch(ctx->digest_type){
|
||||
case SSH_KDF_SHA1:
|
||||
sha1_update(ctx->ctx.sha1_ctx, data, len);
|
||||
break;
|
||||
case SSH_KDF_SHA256:
|
||||
sha256_update(ctx->ctx.sha256_ctx, data, len);
|
||||
break;
|
||||
case SSH_KDF_SHA384:
|
||||
sha384_update(ctx->ctx.sha384_ctx, data, len);
|
||||
break;
|
||||
case SSH_KDF_SHA512:
|
||||
sha512_update(ctx->ctx.sha512_ctx, data, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx)
|
||||
{
|
||||
switch(ctx->digest_type){
|
||||
case SSH_KDF_SHA1:
|
||||
sha1_final(md,ctx->ctx.sha1_ctx);
|
||||
break;
|
||||
case SSH_KDF_SHA256:
|
||||
sha256_final(md,ctx->ctx.sha256_ctx);
|
||||
break;
|
||||
case SSH_KDF_SHA384:
|
||||
sha384_final(md,ctx->ctx.sha384_ctx);
|
||||
break;
|
||||
case SSH_KDF_SHA512:
|
||||
sha512_final(md,ctx->ctx.sha512_ctx);
|
||||
break;
|
||||
}
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
{
|
||||
/* Can't use VLAs with Visual Studio, so allocate the biggest
|
||||
* digest buffer we can possibly need */
|
||||
unsigned char digest[DIGEST_MAX_LEN];
|
||||
size_t output_len = crypto->digest_len;
|
||||
char letter = key_type;
|
||||
ssh_mac_ctx ctx;
|
||||
|
||||
if (DIGEST_MAX_LEN < crypto->digest_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx = ssh_mac_ctx_init(crypto->digest_type);
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssh_mac_update(ctx, key, key_len);
|
||||
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
|
||||
ssh_mac_update(ctx, &letter, 1);
|
||||
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
|
||||
ssh_mac_final(digest, ctx);
|
||||
|
||||
if (requested_len < output_len) {
|
||||
output_len = requested_len;
|
||||
}
|
||||
memcpy(output, digest, output_len);
|
||||
|
||||
while (requested_len > output_len) {
|
||||
ctx = ssh_mac_ctx_init(crypto->digest_type);
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ssh_mac_update(ctx, key, key_len);
|
||||
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
|
||||
ssh_mac_update(ctx, output, output_len);
|
||||
ssh_mac_final(digest, ctx);
|
||||
if (requested_len < output_len + crypto->digest_len) {
|
||||
memcpy(output + output_len, digest, requested_len - output_len);
|
||||
} else {
|
||||
memcpy(output + output_len, digest, crypto->digest_len);
|
||||
}
|
||||
output_len += crypto->digest_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -38,7 +38,15 @@
|
||||
#include "libssh/knownhosts.h"
|
||||
/*todo: remove this include */
|
||||
#include "libssh/string.h"
|
||||
#include "libssh/token.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
#elif defined HAVE_LIBCRYPTO
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rsa.h>
|
||||
#endif /* HAVE_LIBCRYPTO */
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <netinet/in.h>
|
||||
@@ -51,6 +59,23 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Free a token array.
|
||||
*/
|
||||
static void tokens_free(char **tokens) {
|
||||
if (tokens == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
SAFE_FREE(tokens[0]);
|
||||
/* It's not needed to free other pointers because tokens generated by
|
||||
* space_tokenize fit all in one malloc
|
||||
*/
|
||||
SAFE_FREE(tokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -70,63 +95,58 @@
|
||||
* free that value. NULL if no match was found or the file
|
||||
* was not found.
|
||||
*/
|
||||
static struct ssh_tokens_st *ssh_get_knownhost_line(FILE **file,
|
||||
const char *filename,
|
||||
const char **found_type)
|
||||
{
|
||||
char buffer[4096] = {0};
|
||||
char *ptr;
|
||||
struct ssh_tokens_st *tokens;
|
||||
static char **ssh_get_knownhost_line(FILE **file, const char *filename,
|
||||
const char **found_type) {
|
||||
char buffer[4096] = {0};
|
||||
char *ptr;
|
||||
char **tokens;
|
||||
|
||||
if(*file == NULL){
|
||||
*file = fopen(filename,"r");
|
||||
if (*file == NULL) {
|
||||
*file = fopen(filename,"r");
|
||||
if (*file == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), *file)) {
|
||||
ptr = strchr(buffer, '\n');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), *file)) {
|
||||
ptr = strchr(buffer, '\n');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
ptr = strchr(buffer,'\r');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
if (buffer[0] == '\0' || buffer[0] == '#') {
|
||||
continue; /* skip empty lines */
|
||||
}
|
||||
|
||||
tokens = ssh_tokenize(buffer, ' ');
|
||||
if (tokens == NULL) {
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tokens->tokens[0] == NULL ||
|
||||
tokens->tokens[1] == NULL ||
|
||||
tokens->tokens[2] == NULL)
|
||||
{
|
||||
/* it should have at least 3 tokens */
|
||||
ssh_tokens_free(tokens);
|
||||
continue;
|
||||
}
|
||||
|
||||
*found_type = tokens->tokens[1];
|
||||
|
||||
return tokens;
|
||||
ptr = strchr(buffer,'\r');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
if (buffer[0] == '\0' || buffer[0] == '#') {
|
||||
continue; /* skip empty lines */
|
||||
}
|
||||
|
||||
/* we did not find anything, end of file*/
|
||||
return NULL;
|
||||
tokens = ssh_space_tokenize(buffer);
|
||||
if (tokens == NULL) {
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(tokens[0] == NULL || tokens[1] == NULL || tokens[2] == NULL) {
|
||||
/* it should have at least 3 tokens */
|
||||
tokens_free(tokens);
|
||||
continue;
|
||||
}
|
||||
|
||||
*found_type = tokens[1];
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
fclose(*file);
|
||||
*file = NULL;
|
||||
|
||||
/* we did not find anything, end of file*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,143 +300,143 @@ static int match_hashed_host(const char *host, const char *sourcehash)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief This function is deprecated
|
||||
* @brief This function is depcrecated
|
||||
*
|
||||
* @deprecated Please use ssh_session_is_known_server()
|
||||
* @see ssh_session_is_known_server()
|
||||
*/
|
||||
int ssh_is_server_known(ssh_session session)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
char *host;
|
||||
char *hostport;
|
||||
const char *type;
|
||||
int match;
|
||||
int i = 0;
|
||||
char *files[3];
|
||||
int ssh_is_server_known(ssh_session session) {
|
||||
FILE *file = NULL;
|
||||
char **tokens;
|
||||
char *host;
|
||||
char *hostport;
|
||||
const char *type;
|
||||
int match;
|
||||
int i=0;
|
||||
char * files[3];
|
||||
int ret = SSH_SERVER_NOT_KNOWN;
|
||||
|
||||
struct ssh_tokens_st *tokens;
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Can't find a known_hosts file");
|
||||
|
||||
int ret = SSH_SERVER_NOT_KNOWN;
|
||||
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||
"Can't find a known_hosts file");
|
||||
|
||||
return SSH_SERVER_FILE_NOT_FOUND;
|
||||
}
|
||||
return SSH_SERVER_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Can't verify host in known hosts if the hostname isn't known");
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Can't verify host in known hosts if the hostname isn't known");
|
||||
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (session->current_crypto == NULL){
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"ssh_is_host_known called without cryptographic context");
|
||||
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
host = ssh_lowercase(session->opts.host);
|
||||
hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
|
||||
if (host == NULL || hostport == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* Set the list of known hosts files */
|
||||
i = 0;
|
||||
if (session->opts.global_knownhosts != NULL){
|
||||
files[i++] = session->opts.global_knownhosts;
|
||||
}
|
||||
files[i++] = session->opts.knownhosts;
|
||||
files[i] = NULL;
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
tokens = ssh_get_knownhost_line(&file,
|
||||
files[i],
|
||||
&type);
|
||||
|
||||
/* End of file, return the current state or use next file */
|
||||
if (tokens == NULL) {
|
||||
++i;
|
||||
if(files[i] == NULL)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
match = match_hashed_host(host, tokens->tokens[0]);
|
||||
if (match == 0){
|
||||
match = match_hostname(hostport, tokens->tokens[0],
|
||||
strlen(tokens->tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hostname(host, tokens->tokens[0],
|
||||
strlen(tokens->tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hashed_host(hostport, tokens->tokens[0]);
|
||||
}
|
||||
if (match) {
|
||||
ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
|
||||
const char *pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey));
|
||||
|
||||
/* We got a match. Now check the key type */
|
||||
if (strcmp(pubkey_type, type) != 0) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"ssh_is_server_known: server type [%s] doesn't match the "
|
||||
"type [%s] in known_hosts file",
|
||||
pubkey_type,
|
||||
type);
|
||||
/* Different type. We don't override the known_changed error which is
|
||||
* more important */
|
||||
if (ret != SSH_SERVER_KNOWN_CHANGED)
|
||||
ret = SSH_SERVER_FOUND_OTHER;
|
||||
ssh_tokens_free(tokens);
|
||||
continue;
|
||||
}
|
||||
/* so we know the key type is good. We may get a good key or a bad key. */
|
||||
match = check_public_key(session, tokens->tokens);
|
||||
ssh_tokens_free(tokens);
|
||||
|
||||
if (match < 0) {
|
||||
ret = SSH_SERVER_ERROR;
|
||||
break;
|
||||
} else if (match == 1) {
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
break;
|
||||
} else if(match == 0) {
|
||||
/* We override the status with the wrong key state */
|
||||
ret = SSH_SERVER_KNOWN_CHANGED;
|
||||
}
|
||||
} else {
|
||||
ssh_tokens_free(tokens);
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if ((ret == SSH_SERVER_NOT_KNOWN) &&
|
||||
(session->opts.StrictHostKeyChecking == 0)) {
|
||||
ssh_write_knownhost(session);
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
}
|
||||
if (session->current_crypto == NULL){
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"ssh_is_host_known called without cryptographic context");
|
||||
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
host = ssh_lowercase(session->opts.host);
|
||||
hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
|
||||
if (host == NULL || hostport == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
if (file != NULL) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* Return the current state at end of file */
|
||||
return ret;
|
||||
return SSH_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* set the list of known hosts */
|
||||
i = 0;
|
||||
if (session->opts.global_knownhosts != NULL){
|
||||
files[i++]=session->opts.global_knownhosts;
|
||||
}
|
||||
files[i++] = session->opts.knownhosts;
|
||||
files[i] = NULL;
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
tokens = ssh_get_knownhost_line(&file,
|
||||
files[i],
|
||||
&type);
|
||||
|
||||
/* End of file, return the current state or use next file */
|
||||
if (tokens == NULL) {
|
||||
++i;
|
||||
if(files[i] == NULL)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
match = match_hashed_host(host, tokens[0]);
|
||||
if (match == 0){
|
||||
match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hostname(host, tokens[0], strlen(tokens[0]));
|
||||
}
|
||||
if (match == 0) {
|
||||
match = match_hashed_host(hostport, tokens[0]);
|
||||
}
|
||||
if (match) {
|
||||
ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
|
||||
const char *pubkey_type = NULL;
|
||||
|
||||
if (ssh_key_type(pubkey) == SSH_KEYTYPE_ECDSA) {
|
||||
pubkey_type = ssh_pki_key_ecdsa_name(pubkey);
|
||||
} else {
|
||||
pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey));
|
||||
}
|
||||
|
||||
/* We got a match. Now check the key type */
|
||||
if (strcmp(pubkey_type, type) != 0) {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"ssh_is_server_known: server type [%s] doesn't match the "
|
||||
"type [%s] in known_hosts file",
|
||||
pubkey_type,
|
||||
type);
|
||||
/* Different type. We don't override the known_changed error which is
|
||||
* more important */
|
||||
if (ret != SSH_SERVER_KNOWN_CHANGED)
|
||||
ret = SSH_SERVER_FOUND_OTHER;
|
||||
tokens_free(tokens);
|
||||
continue;
|
||||
}
|
||||
/* so we know the key type is good. We may get a good key or a bad key. */
|
||||
match = check_public_key(session, tokens);
|
||||
tokens_free(tokens);
|
||||
|
||||
if (match < 0) {
|
||||
ret = SSH_SERVER_ERROR;
|
||||
break;
|
||||
} else if (match == 1) {
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
break;
|
||||
} else if(match == 0) {
|
||||
/* We override the status with the wrong key state */
|
||||
ret = SSH_SERVER_KNOWN_CHANGED;
|
||||
}
|
||||
} else {
|
||||
tokens_free(tokens);
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if ((ret == SSH_SERVER_NOT_KNOWN) &&
|
||||
(session->opts.StrictHostKeyChecking == 0)) {
|
||||
ssh_write_knownhost(session);
|
||||
ret = SSH_SERVER_KNOWN_OK;
|
||||
}
|
||||
|
||||
SAFE_FREE(host);
|
||||
SAFE_FREE(hostport);
|
||||
if (file != NULL) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
/* Return the current state at end of file */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
174
src/knownhosts.c
174
src/knownhosts.c
@@ -182,29 +182,6 @@ static int known_hosts_read_line(FILE *fp,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_known_hosts_entries_compare(struct ssh_knownhosts_entry *k1,
|
||||
struct ssh_knownhosts_entry *k2)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
if (k1 == NULL || k2 == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
cmp = strcmp(k1->hostname, k2->hostname);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
cmp = ssh_key_cmp(k1->publickey, k2->publickey, SSH_KEY_CMP_PUBLIC);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This method reads the known_hosts file referenced by the path
|
||||
* in filename argument, and entries matching the match argument
|
||||
* will be added to the list in entries argument.
|
||||
@@ -241,8 +218,7 @@ static int ssh_known_hosts_read_entries(const char *match,
|
||||
rc == 0;
|
||||
rc = known_hosts_read_line(fp, line, sizeof(line), &len, &lineno)) {
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
char *p = NULL;
|
||||
char *p;
|
||||
|
||||
if (line[len] != '\n') {
|
||||
len = strcspn(line, "\n");
|
||||
@@ -257,12 +233,6 @@ static int ssh_known_hosts_read_entries(const char *match,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip lines starting with markers (@cert-authority, @revoked):
|
||||
* we do not completely support them anyway */
|
||||
if (p[0] == '@') {
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = ssh_known_hosts_parse_line(match,
|
||||
line,
|
||||
&entry);
|
||||
@@ -271,24 +241,7 @@ static int ssh_known_hosts_read_entries(const char *match,
|
||||
} else if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check for duplicates */
|
||||
for (it = ssh_list_get_iterator(*entries);
|
||||
it != NULL;
|
||||
it = it->next) {
|
||||
struct ssh_knownhosts_entry *entry2;
|
||||
int cmp;
|
||||
entry2 = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
cmp = ssh_known_hosts_entries_compare(entry, entry2);
|
||||
if (cmp == 0) {
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
entry = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (entry != NULL) {
|
||||
ssh_list_append(*entries, entry);
|
||||
}
|
||||
ssh_list_append(*entries, entry);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
@@ -306,7 +259,7 @@ static char *ssh_session_get_host_port(ssh_session session)
|
||||
if (session->opts.host == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Can't verify server in known hosts if the host we "
|
||||
"Can't verify server inn known hosts if the host we "
|
||||
"should connect to has not been set");
|
||||
|
||||
return NULL;
|
||||
@@ -409,32 +362,15 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
|
||||
for (it = ssh_list_get_iterator(entry_list);
|
||||
it != NULL;
|
||||
it = ssh_list_get_iterator(entry_list)) {
|
||||
struct ssh_iterator *it2 = NULL;
|
||||
struct ssh_knownhosts_entry *entry = NULL;
|
||||
const char *algo = NULL;
|
||||
bool present = false;
|
||||
|
||||
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||
algo = entry->publickey->type_c;
|
||||
|
||||
/* Check for duplicates */
|
||||
for (it2 = ssh_list_get_iterator(list);
|
||||
it2 != NULL;
|
||||
it2 = it2->next) {
|
||||
char *alg2 = ssh_iterator_value(char *, it2);
|
||||
int cmp = strcmp(alg2, algo);
|
||||
if (cmp == 0) {
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add to the new list only if it is unique */
|
||||
if (!present) {
|
||||
rc = ssh_list_append(list, algo);
|
||||
if (rc != SSH_OK) {
|
||||
list_error = 1;
|
||||
}
|
||||
rc = ssh_list_append(list, algo);
|
||||
if (rc != SSH_OK) {
|
||||
list_error = 1;
|
||||
}
|
||||
|
||||
ssh_knownhosts_entry_free(entry);
|
||||
@@ -498,8 +434,8 @@ int ssh_known_hosts_parse_line(const char *hostname,
|
||||
}
|
||||
|
||||
if (hostname != NULL) {
|
||||
char *host_port = NULL;
|
||||
char *q = NULL;
|
||||
char *match_pattern = NULL;
|
||||
char *q;
|
||||
|
||||
/* Hashed */
|
||||
if (p[0] == '|') {
|
||||
@@ -511,30 +447,13 @@ int ssh_known_hosts_parse_line(const char *hostname,
|
||||
q = strtok(NULL, ",")) {
|
||||
int cmp;
|
||||
|
||||
if (q[0] == '[' && hostname[0] != '[') {
|
||||
/* Corner case: We have standard port so we do not have
|
||||
* hostname in square braces. But the patern is enclosed
|
||||
* in braces with, possibly standard or wildcard, port.
|
||||
* We need to test against [host]:port pair here.
|
||||
*/
|
||||
if (host_port == NULL) {
|
||||
host_port = ssh_hostport(hostname, 22);
|
||||
if (host_port == NULL) {
|
||||
rc = SSH_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
cmp = match_hostname(host_port, q, strlen(q));
|
||||
} else {
|
||||
cmp = match_hostname(hostname, q, strlen(q));
|
||||
}
|
||||
cmp = match_hostname(hostname, q, strlen(q));
|
||||
if (cmp == 1) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(host_port);
|
||||
SAFE_FREE(match_pattern);
|
||||
|
||||
if (match == 0) {
|
||||
rc = SSH_AGAIN;
|
||||
@@ -638,79 +557,38 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
|
||||
struct ssh_list *entry_list = NULL;
|
||||
struct ssh_iterator *it = NULL;
|
||||
char *host_port = NULL;
|
||||
bool global_known_hosts_found = false;
|
||||
bool known_hosts_found = false;
|
||||
int rc;
|
||||
|
||||
if (session->opts.knownhosts == NULL) {
|
||||
if (ssh_options_apply(session) < 0) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Cannot find a known_hosts file");
|
||||
"Can't find a known_hosts file");
|
||||
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.knownhosts == NULL &&
|
||||
session->opts.global_knownhosts == NULL) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"No path set for a known_hosts file");
|
||||
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (session->opts.knownhosts != NULL) {
|
||||
known_hosts_found = ssh_file_readaccess_ok(session->opts.knownhosts);
|
||||
if (!known_hosts_found) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
|
||||
session->opts.knownhosts);
|
||||
}
|
||||
}
|
||||
|
||||
if (session->opts.global_knownhosts != NULL) {
|
||||
global_known_hosts_found =
|
||||
ssh_file_readaccess_ok(session->opts.global_knownhosts);
|
||||
if (!global_known_hosts_found) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
|
||||
session->opts.global_knownhosts);
|
||||
}
|
||||
}
|
||||
|
||||
if ((!known_hosts_found) && (!global_known_hosts_found)) {
|
||||
ssh_set_error(session,
|
||||
SSH_REQUEST_DENIED,
|
||||
"Cannot find a known_hosts file");
|
||||
|
||||
return SSH_KNOWN_HOSTS_NOT_FOUND;
|
||||
}
|
||||
|
||||
host_port = ssh_session_get_host_port(session);
|
||||
if (host_port == NULL) {
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
|
||||
if (session->opts.knownhosts != NULL) {
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.knownhosts,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
SAFE_FREE(host_port);
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.knownhosts,
|
||||
&entry_list);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
if (session->opts.global_knownhosts != NULL) {
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.global_knownhosts,
|
||||
&entry_list);
|
||||
SAFE_FREE(host_port);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_ERROR;
|
||||
}
|
||||
rc = ssh_known_hosts_read_entries(host_port,
|
||||
session->opts.global_knownhosts,
|
||||
&entry_list);
|
||||
SAFE_FREE(host_port);
|
||||
if (rc != 0) {
|
||||
ssh_list_free(entry_list);
|
||||
return SSH_KNOWN_HOSTS_UNKNOWN;
|
||||
}
|
||||
|
||||
if (ssh_list_count(entry_list) == 0) {
|
||||
@@ -849,14 +727,12 @@ int ssh_session_update_known_hosts(ssh_session session)
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
SAFE_FREE(dir);
|
||||
if (rc != 0) {
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Cannot create %s directory.", dir);
|
||||
SAFE_FREE(dir);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
SAFE_FREE(dir);
|
||||
|
||||
fp = fopen(session->opts.knownhosts, "a");
|
||||
if (fp == NULL) {
|
||||
|
||||
@@ -545,10 +545,6 @@ ssh_string publickey_to_string(ssh_public_key pubkey) {
|
||||
ssh_string key_blob;
|
||||
int rc;
|
||||
|
||||
if (pubkey == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = ssh_key_new();
|
||||
if (key == NULL) {
|
||||
return NULL;
|
||||
|
||||
@@ -335,62 +335,3 @@ void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
void DH_get0_pqg(const DH *dh,
|
||||
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
|
||||
{
|
||||
if (p) {
|
||||
*p = dh->p;
|
||||
}
|
||||
if (q) {
|
||||
*q = NULL;
|
||||
}
|
||||
if (g) {
|
||||
*g = dh->g;
|
||||
}
|
||||
}
|
||||
|
||||
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
||||
{
|
||||
if (p) {
|
||||
if (dh->p) {
|
||||
BN_free(dh->p);
|
||||
}
|
||||
dh->p = p;
|
||||
}
|
||||
if (g) {
|
||||
if (dh->g) {
|
||||
BN_free(dh->g);
|
||||
}
|
||||
dh->g = g;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DH_get0_key(const DH *dh,
|
||||
const BIGNUM **pub_key, const BIGNUM **priv_key)
|
||||
{
|
||||
if (pub_key) {
|
||||
*pub_key = dh->pub_key;
|
||||
}
|
||||
if (priv_key) {
|
||||
*priv_key = dh->priv_key;
|
||||
}
|
||||
}
|
||||
|
||||
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
|
||||
{
|
||||
if (pub_key) {
|
||||
if (dh->pub_key) {
|
||||
BN_free(dh->pub_key);
|
||||
}
|
||||
dh->pub_key = pub_key;
|
||||
}
|
||||
if (priv_key) {
|
||||
if (dh->priv_key) {
|
||||
BN_free(dh->priv_key);
|
||||
}
|
||||
dh->priv_key = priv_key;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -38,12 +38,6 @@ HMAC_CTX *HMAC_CTX_new(void);
|
||||
int HMAC_CTX_reset(HMAC_CTX *ctx);
|
||||
void HMAC_CTX_free(HMAC_CTX *ctx);
|
||||
|
||||
void DH_get0_pqg(const DH *dh,
|
||||
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
|
||||
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
|
||||
void DH_get0_key(const DH *dh,
|
||||
const BIGNUM **pub_key, const BIGNUM **priv_key);
|
||||
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
|
||||
#endif /* LIBCRYPTO_COMPAT_H */
|
||||
|
||||
494
src/libcrypto.c
494
src/libcrypto.c
@@ -43,7 +43,6 @@
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "libcrypto-compat.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_AES_H
|
||||
@@ -55,22 +54,21 @@
|
||||
#include <openssl/des.h>
|
||||
#endif
|
||||
|
||||
#if (defined(HAVE_VALGRIND_VALGRIND_H) && defined(HAVE_OPENSSL_IA32CAP_LOC))
|
||||
#include <valgrind/valgrind.h>
|
||||
#define CAN_DISABLE_AESNI
|
||||
#if (OPENSSL_VERSION_NUMBER<0x00907000L)
|
||||
#define OLD_CRYPTO
|
||||
#endif
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID
|
||||
#include <openssl/kdf.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT
|
||||
#include <openssl/modes.h>
|
||||
#endif
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_mac_e mac_type;
|
||||
union {
|
||||
SHACTX sha1_ctx;
|
||||
SHA256CTX sha256_ctx;
|
||||
SHA384CTX sha384_ctx;
|
||||
SHA512CTX sha512_ctx;
|
||||
} ctx;
|
||||
};
|
||||
|
||||
static int libcrypto_initialized = 0;
|
||||
|
||||
@@ -139,7 +137,7 @@ void sha1_final(unsigned char *md, SHACTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
void sha1(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha1(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
SHACTX c = sha1_init();
|
||||
if (c != NULL) {
|
||||
@@ -231,7 +229,7 @@ void sha256_final(unsigned char *md, SHA256CTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
void sha256(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
SHA256CTX c = sha256_init();
|
||||
if (c != NULL) {
|
||||
@@ -269,7 +267,7 @@ void sha384_final(unsigned char *md, SHA384CTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
void sha384(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha384(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
SHA384CTX c = sha384_init();
|
||||
if (c != NULL) {
|
||||
@@ -307,7 +305,7 @@ void sha512_final(unsigned char *md, SHA512CTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
void sha512(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha512(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
SHA512CTX c = sha512_init();
|
||||
if (c != NULL) {
|
||||
@@ -345,80 +343,70 @@ void md5_final(unsigned char *md, MD5CTX c)
|
||||
EVP_MD_CTX_destroy(c);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID
|
||||
static const EVP_MD *sshkdf_digest_to_md(enum ssh_kdf_digest digest_type)
|
||||
{
|
||||
switch (digest_type) {
|
||||
case SSH_KDF_SHA1:
|
||||
return EVP_sha1();
|
||||
case SSH_KDF_SHA256:
|
||||
return EVP_sha256();
|
||||
case SSH_KDF_SHA384:
|
||||
return EVP_sha384();
|
||||
case SSH_KDF_SHA512:
|
||||
return EVP_sha512();
|
||||
}
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->mac_type=type;
|
||||
switch(type){
|
||||
case SSH_MAC_SHA1:
|
||||
ctx->ctx.sha1_ctx = sha1_init();
|
||||
return ctx;
|
||||
case SSH_MAC_SHA256:
|
||||
ctx->ctx.sha256_ctx = sha256_init();
|
||||
return ctx;
|
||||
case SSH_MAC_SHA384:
|
||||
ctx->ctx.sha384_ctx = sha384_init();
|
||||
return ctx;
|
||||
case SSH_MAC_SHA512:
|
||||
ctx->ctx.sha512_ctx = sha512_init();
|
||||
return ctx;
|
||||
default:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
{
|
||||
EVP_KDF_CTX *ctx = EVP_KDF_CTX_new_id(EVP_KDF_SSHKDF);
|
||||
int rc;
|
||||
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD,
|
||||
sshkdf_digest_to_md(crypto->digest_type));
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, key, key_len);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_XCGHASH,
|
||||
crypto->secret_hash, crypto->digest_len);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_TYPE, key_type);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID,
|
||||
crypto->session_id, crypto->digest_len);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
rc = EVP_KDF_derive(ctx, output, requested_len);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
EVP_KDF_CTX_free(ctx);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) {
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
sha1_update(ctx->ctx.sha1_ctx, data, len);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
sha256_update(ctx->ctx.sha256_ctx, data, len);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
sha384_update(ctx->ctx.sha384_ctx, data, len);
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
sha512_update(ctx->ctx.sha512_ctx, data, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
{
|
||||
return sshkdf_derive_key(crypto, key, key_len,
|
||||
key_type, output, requested_len);
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
sha1_final(md,ctx->ctx.sha1_ctx);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
sha256_final(md,ctx->ctx.sha256_ctx);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
sha384_final(md,ctx->ctx.sha384_ctx);
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
sha512_final(md,ctx->ctx.sha512_ctx);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
HMACCTX ctx = NULL;
|
||||
@@ -428,6 +416,9 @@ HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef OLD_CRYPTO
|
||||
HMAC_CTX_reset(ctx); // openssl 0.9.7 requires it.
|
||||
#endif
|
||||
|
||||
switch(type) {
|
||||
case SSH_HMAC_SHA1:
|
||||
@@ -444,6 +435,7 @@ HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
break;
|
||||
default:
|
||||
HMAC_CTX_free(ctx);
|
||||
SAFE_FREE(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
@@ -457,14 +449,14 @@ void hmac_update(HMACCTX ctx, const void *data, unsigned long len) {
|
||||
void hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, unsigned int *len) {
|
||||
HMAC_Final(ctx,hashmacbuf,len);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER > 0x10100000L
|
||||
#ifndef OLD_CRYPTO
|
||||
HMAC_CTX_free(ctx);
|
||||
ctx = NULL;
|
||||
#else
|
||||
HMAC_cleanup(ctx);
|
||||
SAFE_FREE(ctx);
|
||||
ctx = NULL;
|
||||
#endif
|
||||
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
static void evp_cipher_init(struct ssh_cipher_struct *cipher) {
|
||||
@@ -499,31 +491,13 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "This cipher is not available in evp_cipher_init");
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_EVP_AES_GCM
|
||||
case SSH_AEAD_AES128_GCM:
|
||||
cipher->cipher = EVP_aes_128_gcm();
|
||||
break;
|
||||
case SSH_AEAD_AES256_GCM:
|
||||
cipher->cipher = EVP_aes_256_gcm();
|
||||
break;
|
||||
#else
|
||||
case SSH_AEAD_AES128_GCM:
|
||||
case SSH_AEAD_AES256_GCM:
|
||||
SSH_LOG(SSH_LOG_WARNING, "This cipher is not available in evp_cipher_init");
|
||||
break;
|
||||
#endif /* HAVE_OPENSSL_EVP_AES_GCM */
|
||||
case SSH_3DES_CBC:
|
||||
cipher->cipher = EVP_des_ede3_cbc();
|
||||
break;
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
case SSH_BLOWFISH_CBC:
|
||||
cipher->cipher = EVP_bf_cbc();
|
||||
break;
|
||||
/* ciphers not using EVP */
|
||||
#endif
|
||||
case SSH_AEAD_CHACHA20_POLY1305:
|
||||
SSH_LOG(SSH_LOG_WARNING, "The ChaCha cipher cannot be handled here");
|
||||
break;
|
||||
case SSH_NO_CIPHER:
|
||||
SSH_LOG(SSH_LOG_WARNING, "No valid ciphertype found");
|
||||
break;
|
||||
@@ -543,22 +517,6 @@ static int evp_cipher_set_encrypt_key(struct ssh_cipher_struct *cipher,
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptInit_ex failed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_EVP_AES_GCM
|
||||
/* For AES-GCM we need to set IV in specific way */
|
||||
if (cipher->ciphertype == SSH_AEAD_AES128_GCM ||
|
||||
cipher->ciphertype == SSH_AEAD_AES256_GCM) {
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_SET_IV_FIXED,
|
||||
-1,
|
||||
(uint8_t *)IV);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_IV_FIXED failed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_EVP_AES_GCM */
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(cipher->ctx, 0);
|
||||
|
||||
return SSH_OK;
|
||||
@@ -576,22 +534,6 @@ static int evp_cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptInit_ex failed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL_EVP_AES_GCM
|
||||
/* For AES-GCM we need to set IV in specific way */
|
||||
if (cipher->ciphertype == SSH_AEAD_AES128_GCM ||
|
||||
cipher->ciphertype == SSH_AEAD_AES256_GCM) {
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_SET_IV_FIXED,
|
||||
-1,
|
||||
(uint8_t *)IV);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_IV_FIXED failed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_OPENSSL_EVP_AES_GCM */
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(cipher->ctx, 0);
|
||||
|
||||
return SSH_OK;
|
||||
@@ -599,25 +541,20 @@ static int evp_cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
|
||||
|
||||
/* EVP wrapper function for encrypt/decrypt */
|
||||
static void evp_cipher_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
void *in,
|
||||
void *out,
|
||||
unsigned long len) {
|
||||
int outlen = 0;
|
||||
int rc = 0;
|
||||
|
||||
rc = EVP_EncryptUpdate(cipher->ctx,
|
||||
(unsigned char *)out,
|
||||
&outlen,
|
||||
(unsigned char *)in,
|
||||
(int)len);
|
||||
rc = EVP_EncryptUpdate(cipher->ctx, (unsigned char *)out, &outlen, (unsigned char *)in, len);
|
||||
if (rc != 1){
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate failed");
|
||||
return;
|
||||
}
|
||||
if (outlen != (int)len){
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"EVP_EncryptUpdate: output size %d for %zu in",
|
||||
"EVP_EncryptUpdate: output size %d for %lu in",
|
||||
outlen,
|
||||
len);
|
||||
return;
|
||||
@@ -625,25 +562,20 @@ static void evp_cipher_encrypt(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
|
||||
static void evp_cipher_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
void *in,
|
||||
void *out,
|
||||
unsigned long len) {
|
||||
int outlen = 0;
|
||||
int rc = 0;
|
||||
|
||||
rc = EVP_DecryptUpdate(cipher->ctx,
|
||||
(unsigned char *)out,
|
||||
&outlen,
|
||||
(unsigned char *)in,
|
||||
(int)len);
|
||||
rc = EVP_DecryptUpdate(cipher->ctx, (unsigned char *)out, &outlen, (unsigned char *)in, len);
|
||||
if (rc != 1){
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptUpdate failed");
|
||||
return;
|
||||
}
|
||||
if (outlen != (int)len){
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"EVP_DecryptUpdate: output size %d for %zu in",
|
||||
"EVP_DecryptUpdate: output size %d for %lu in",
|
||||
outlen,
|
||||
len);
|
||||
return;
|
||||
@@ -710,184 +642,10 @@ static void aes_ctr_cleanup(struct ssh_cipher_struct *cipher){
|
||||
|
||||
#endif /* HAVE_OPENSSL_EVP_AES_CTR */
|
||||
|
||||
#ifdef HAVE_OPENSSL_EVP_AES_GCM
|
||||
static int
|
||||
evp_cipher_aead_get_length(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
uint8_t *out,
|
||||
size_t len,
|
||||
uint64_t seq)
|
||||
{
|
||||
(void)cipher;
|
||||
(void)seq;
|
||||
|
||||
/* The length is not encrypted: Copy it to the result buffer */
|
||||
memcpy(out, in, len);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len,
|
||||
uint8_t *tag,
|
||||
uint64_t seq)
|
||||
{
|
||||
size_t authlen, aadlen;
|
||||
uint8_t lastiv[1];
|
||||
int tmplen = 0;
|
||||
size_t outlen;
|
||||
int rc;
|
||||
|
||||
(void) seq;
|
||||
|
||||
aadlen = cipher->lenfield_blocksize;
|
||||
authlen = cipher->tag_size;
|
||||
|
||||
/* increment IV */
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_IV_GEN,
|
||||
1,
|
||||
lastiv);
|
||||
if (rc == 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_IV_GEN failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pass over the authenticated data (not encrypted) */
|
||||
rc = EVP_EncryptUpdate(cipher->ctx,
|
||||
NULL,
|
||||
&tmplen,
|
||||
(unsigned char *)in,
|
||||
(int)aadlen);
|
||||
outlen = tmplen;
|
||||
if (rc == 0 || outlen != aadlen) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Failed to pass authenticated data");
|
||||
return;
|
||||
}
|
||||
memcpy(out, in, aadlen);
|
||||
|
||||
/* Encrypt the rest of the data */
|
||||
rc = EVP_EncryptUpdate(cipher->ctx,
|
||||
(unsigned char *)out + aadlen,
|
||||
&tmplen,
|
||||
(unsigned char *)in + aadlen,
|
||||
(int)len - aadlen);
|
||||
outlen = tmplen;
|
||||
if (rc != 1 || outlen != (int)len - aadlen) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* compute tag */
|
||||
rc = EVP_EncryptFinal(cipher->ctx,
|
||||
NULL,
|
||||
&tmplen);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptFinal failed: Failed to create a tag");
|
||||
return;
|
||||
}
|
||||
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_GET_TAG,
|
||||
authlen,
|
||||
(unsigned char *)tag);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_GET_TAG failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *complete_packet,
|
||||
uint8_t *out,
|
||||
size_t encrypted_size,
|
||||
uint64_t seq)
|
||||
{
|
||||
size_t authlen, aadlen;
|
||||
uint8_t lastiv[1];
|
||||
int outlen = 0;
|
||||
int rc = 0;
|
||||
|
||||
(void)seq;
|
||||
|
||||
aadlen = cipher->lenfield_blocksize;
|
||||
authlen = cipher->tag_size;
|
||||
|
||||
/* increment IV */
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_IV_GEN,
|
||||
1,
|
||||
lastiv);
|
||||
if (rc == 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_IV_GEN failed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* set tag for authentication */
|
||||
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
|
||||
EVP_CTRL_GCM_SET_TAG,
|
||||
authlen,
|
||||
(unsigned char *)complete_packet + aadlen + encrypted_size);
|
||||
if (rc == 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_TAG failed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Pass over the authenticated data (not encrypted) */
|
||||
rc = EVP_DecryptUpdate(cipher->ctx,
|
||||
NULL,
|
||||
&outlen,
|
||||
(unsigned char *)complete_packet,
|
||||
(int)aadlen);
|
||||
if (rc == 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "Failed to pass authenticated data");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* Do not copy the length to the target buffer, because it is already processed */
|
||||
//memcpy(out, complete_packet, aadlen);
|
||||
|
||||
/* Decrypt the rest of the data */
|
||||
rc = EVP_DecryptUpdate(cipher->ctx,
|
||||
(unsigned char *)out,
|
||||
&outlen,
|
||||
(unsigned char *)complete_packet + aadlen,
|
||||
encrypted_size /* already substracted aadlen*/);
|
||||
if (rc != 1) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptUpdate failed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (outlen != (int)encrypted_size) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"EVP_DecryptUpdate: output size %d for %zd in",
|
||||
outlen,
|
||||
encrypted_size);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* verify tag */
|
||||
rc = EVP_DecryptFinal(cipher->ctx,
|
||||
NULL,
|
||||
&outlen);
|
||||
if (rc < 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptFinal failed: Failed authentication");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
#endif /* HAVE_OPENSSL_EVP_AES_GCM */
|
||||
|
||||
/*
|
||||
* The table of supported ciphers
|
||||
*/
|
||||
static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
{
|
||||
.name = "blowfish-cbc",
|
||||
.blocksize = 8,
|
||||
@@ -899,7 +657,6 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
#endif
|
||||
#ifdef HAS_AES
|
||||
#ifndef BROKEN_AES_CTR
|
||||
/* OpenSSL until 0.9.7c has a broken AES_ctr128_encrypt implementation which
|
||||
@@ -908,7 +665,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#ifdef HAVE_OPENSSL_EVP_AES_CTR
|
||||
{
|
||||
.name = "aes128-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES128_CTR,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
@@ -919,7 +676,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
},
|
||||
{
|
||||
.name = "aes192-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES192_CTR,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
@@ -930,7 +687,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
},
|
||||
{
|
||||
.name = "aes256-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES256_CTR,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
@@ -942,7 +699,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#else /* HAVE_OPENSSL_EVP_AES_CTR */
|
||||
{
|
||||
.name = "aes128-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES128_CTR,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = aes_ctr_set_key,
|
||||
@@ -953,7 +710,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
},
|
||||
{
|
||||
.name = "aes192-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES192_CTR,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = aes_ctr_set_key,
|
||||
@@ -964,7 +721,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
},
|
||||
{
|
||||
.name = "aes256-ctr",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES256_CTR,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = aes_ctr_set_key,
|
||||
@@ -977,7 +734,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#endif /* BROKEN_AES_CTR */
|
||||
{
|
||||
.name = "aes128-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES128_CBC,
|
||||
.keysize = 128,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
@@ -988,7 +745,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
},
|
||||
{
|
||||
.name = "aes192-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES192_CBC,
|
||||
.keysize = 192,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
@@ -999,7 +756,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
},
|
||||
{
|
||||
.name = "aes256-cbc",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.blocksize = 16,
|
||||
.ciphertype = SSH_AES256_CBC,
|
||||
.keysize = 256,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
@@ -1008,36 +765,6 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
.decrypt = evp_cipher_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
#ifdef HAVE_OPENSSL_EVP_AES_GCM
|
||||
{
|
||||
.name = "aes128-gcm@openssh.com",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.ciphertype = SSH_AEAD_AES128_GCM,
|
||||
.keysize = 128,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.aead_encrypt = evp_cipher_aead_encrypt,
|
||||
.aead_decrypt_length = evp_cipher_aead_get_length,
|
||||
.aead_decrypt = evp_cipher_aead_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes256-gcm@openssh.com",
|
||||
.blocksize = AES_BLOCK_SIZE,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.ciphertype = SSH_AEAD_AES256_GCM,
|
||||
.keysize = 256,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.set_encrypt_key = evp_cipher_set_encrypt_key,
|
||||
.set_decrypt_key = evp_cipher_set_decrypt_key,
|
||||
.aead_encrypt = evp_cipher_aead_encrypt,
|
||||
.aead_decrypt_length = evp_cipher_aead_get_length,
|
||||
.aead_decrypt = evp_cipher_aead_decrypt,
|
||||
.cleanup = evp_cipher_cleanup
|
||||
},
|
||||
#endif /* HAVE_OPENSSL_EVP_AES_GCM */
|
||||
#endif /* HAS_AES */
|
||||
#ifdef HAS_DES
|
||||
{
|
||||
@@ -1076,27 +803,8 @@ int ssh_crypto_init(void)
|
||||
if (libcrypto_initialized) {
|
||||
return SSH_OK;
|
||||
}
|
||||
if (SSLeay() != OPENSSL_VERSION_NUMBER){
|
||||
SSH_LOG(SSH_LOG_WARNING, "libssh compiled with %s "
|
||||
"headers, currently running with %s.",
|
||||
OPENSSL_VERSION_TEXT,
|
||||
SSLeay_version(SSLeay())
|
||||
);
|
||||
}
|
||||
#ifdef CAN_DISABLE_AESNI
|
||||
/*
|
||||
* disable AES-NI when running within Valgrind, because they generate
|
||||
* too many "uninitialized memory access" false positives
|
||||
*/
|
||||
if (RUNNING_ON_VALGRIND){
|
||||
SSH_LOG(SSH_LOG_INFO, "Running within Valgrind, disabling AES-NI");
|
||||
/* Bit #57 denotes AES-NI instruction set extension */
|
||||
OPENSSL_ia32cap &= ~(1LL << 57);
|
||||
}
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
#endif
|
||||
|
||||
for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
|
||||
int cmp;
|
||||
@@ -1125,10 +833,8 @@ void ssh_crypto_finalize(void)
|
||||
return;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
#endif
|
||||
|
||||
libcrypto_initialized = 0;
|
||||
}
|
||||
|
||||
283
src/libgcrypt.c
283
src/libgcrypt.c
@@ -31,11 +31,15 @@
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/wrapper.h"
|
||||
#include "libssh/string.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#ifdef HAVE_LIBGCRYPT
|
||||
#include <gcrypt.h>
|
||||
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_mac_e mac_type;
|
||||
gcry_md_hd_t ctx;
|
||||
};
|
||||
|
||||
static int libgcrypt_initialized = 0;
|
||||
|
||||
static int alloc_key(struct ssh_cipher_struct *cipher) {
|
||||
@@ -78,7 +82,7 @@ void sha1_final(unsigned char *md, SHACTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
void sha1(const unsigned char *digest, int len, unsigned char *hash) {
|
||||
void sha1(unsigned char *digest, int len, unsigned char *hash) {
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
|
||||
}
|
||||
|
||||
@@ -152,7 +156,7 @@ void sha256_final(unsigned char *md, SHACTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
void sha256(const unsigned char *digest, int len, unsigned char *hash){
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash){
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA256, hash, digest, len);
|
||||
}
|
||||
|
||||
@@ -173,7 +177,7 @@ void sha384_final(unsigned char *md, SHACTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
void sha384(const unsigned char *digest, int len, unsigned char *hash) {
|
||||
void sha384(unsigned char *digest, int len, unsigned char *hash) {
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA384, hash, digest, len);
|
||||
}
|
||||
|
||||
@@ -194,7 +198,7 @@ void sha512_final(unsigned char *md, SHACTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
void sha512(const unsigned char *digest, int len, unsigned char *hash) {
|
||||
void sha512(unsigned char *digest, int len, unsigned char *hash) {
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA512, hash, digest, len);
|
||||
}
|
||||
|
||||
@@ -215,13 +219,57 @@ void md5_final(unsigned char *md, MD5CTX c) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
{
|
||||
return sshkdf_derive_key(crypto, key, key_len,
|
||||
key_type, output, requested_len);
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
|
||||
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->mac_type=type;
|
||||
switch(type){
|
||||
case SSH_MAC_SHA1:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA1, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA256, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA384, 0);
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
gcry_md_open(&ctx->ctx, GCRY_MD_SHA512, 0);
|
||||
break;
|
||||
default:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len) {
|
||||
gcry_md_write(ctx->ctx,data,len);
|
||||
}
|
||||
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
|
||||
size_t len = 0;
|
||||
switch(ctx->mac_type){
|
||||
case SSH_MAC_SHA1:
|
||||
len=SHA_DIGEST_LEN;
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
len=SHA256_DIGEST_LEN;
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
len=SHA384_DIGEST_LEN;
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
len=SHA512_DIGEST_LEN;
|
||||
break;
|
||||
}
|
||||
gcry_md_final(ctx->ctx);
|
||||
memcpy(md, gcry_md_read(ctx->ctx, 0), len);
|
||||
gcry_md_close(ctx->ctx);
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
|
||||
@@ -259,7 +307,6 @@ void hmac_final(HMACCTX c, unsigned char *hashmacbuf, unsigned int *len) {
|
||||
gcry_md_close(c);
|
||||
}
|
||||
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
/* the wrapper functions for blowfish */
|
||||
static int blowfish_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV){
|
||||
if (cipher->key == NULL) {
|
||||
@@ -294,7 +341,6 @@ static void blowfish_decrypt(struct ssh_cipher_struct *cipher, void *in,
|
||||
void *out, unsigned long len) {
|
||||
gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
|
||||
}
|
||||
#endif /* WITH_BLOWFISH_CIPHER */
|
||||
|
||||
static int aes_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
|
||||
int mode=GCRY_CIPHER_MODE_CBC;
|
||||
@@ -304,8 +350,6 @@ static int aes_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
|
||||
}
|
||||
if(strstr(cipher->name,"-ctr"))
|
||||
mode=GCRY_CIPHER_MODE_CTR;
|
||||
if (strstr(cipher->name, "-gcm"))
|
||||
mode = GCRY_CIPHER_MODE_GCM;
|
||||
switch (cipher->keysize) {
|
||||
case 128:
|
||||
if (gcry_cipher_open(&cipher->key[0], GCRY_CIPHER_AES128,
|
||||
@@ -339,11 +383,6 @@ static int aes_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
|
||||
SAFE_FREE(cipher->key);
|
||||
return -1;
|
||||
}
|
||||
} else if (mode == GCRY_CIPHER_MODE_GCM) {
|
||||
/* Store the IV so we can handle the packet counter increments later
|
||||
* The IV is passed to the cipher context later.
|
||||
*/
|
||||
memcpy(cipher->last_iv, IV, AES_GCM_IVLEN);
|
||||
} else {
|
||||
if(gcry_cipher_setctr(cipher->key[0],IV,16)){
|
||||
SAFE_FREE(cipher->key);
|
||||
@@ -355,174 +394,14 @@ static int aes_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aes_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
|
||||
static void aes_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len) {
|
||||
gcry_cipher_encrypt(cipher->key[0], out, len, in, len);
|
||||
}
|
||||
|
||||
static void aes_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
{
|
||||
gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
|
||||
}
|
||||
|
||||
static int
|
||||
aes_aead_get_length(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
uint8_t *out,
|
||||
size_t len,
|
||||
uint64_t seq)
|
||||
{
|
||||
(void)cipher;
|
||||
(void)seq;
|
||||
|
||||
/* The length is not encrypted: Copy it to the result buffer */
|
||||
memcpy(out, in, len);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
aes_gcm_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len,
|
||||
uint8_t *tag,
|
||||
uint64_t seq)
|
||||
{
|
||||
gpg_error_t err;
|
||||
size_t aadlen, authlen;
|
||||
|
||||
(void)seq;
|
||||
|
||||
aadlen = cipher->lenfield_blocksize;
|
||||
authlen = cipher->tag_size;
|
||||
|
||||
/* increment IV */
|
||||
err = gcry_cipher_setiv(cipher->key[0],
|
||||
cipher->last_iv,
|
||||
AES_GCM_IVLEN);
|
||||
/* This actualy does not increment the packet counter for the
|
||||
* current encryption operation, but for the next one. The first
|
||||
* operation needs to be completed with the derived IV.
|
||||
*
|
||||
* The IV buffer has the following structure:
|
||||
* [ 4B static IV ][ 8B packet counter ][ 4B block counter ]
|
||||
*/
|
||||
uint64_inc(cipher->last_iv + 4);
|
||||
if (err) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_setiv failed: %s",
|
||||
gpg_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pass the authenticated data (packet_length) */
|
||||
err = gcry_cipher_authenticate(cipher->key[0], in, aadlen);
|
||||
if (err) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_authenticate failed: %s",
|
||||
gpg_strerror(err));
|
||||
return;
|
||||
}
|
||||
memcpy(out, in, aadlen);
|
||||
|
||||
/* Encrypt the rest of the data */
|
||||
err = gcry_cipher_encrypt(cipher->key[0],
|
||||
(unsigned char *)out + aadlen,
|
||||
len - aadlen,
|
||||
(unsigned char *)in + aadlen,
|
||||
len - aadlen);
|
||||
if (err) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_encrypt failed: %s",
|
||||
gpg_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Calculate the tag */
|
||||
err = gcry_cipher_gettag(cipher->key[0],
|
||||
(void *)tag,
|
||||
authlen);
|
||||
if (err) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_gettag failed: %s",
|
||||
gpg_strerror(err));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
aes_gcm_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *complete_packet,
|
||||
uint8_t *out,
|
||||
size_t encrypted_size,
|
||||
uint64_t seq)
|
||||
{
|
||||
gpg_error_t err;
|
||||
size_t aadlen, authlen;
|
||||
|
||||
(void)seq;
|
||||
|
||||
aadlen = cipher->lenfield_blocksize;
|
||||
authlen = cipher->tag_size;
|
||||
|
||||
/* increment IV */
|
||||
err = gcry_cipher_setiv(cipher->key[0],
|
||||
cipher->last_iv,
|
||||
AES_GCM_IVLEN);
|
||||
/* This actualy does not increment the packet counter for the
|
||||
* current encryption operation, but for the next one. The first
|
||||
* operation needs to be completed with the derived IV.
|
||||
*
|
||||
* The IV buffer has the following structure:
|
||||
* [ 4B static IV ][ 8B packet counter ][ 4B block counter ]
|
||||
*/
|
||||
uint64_inc(cipher->last_iv + 4);
|
||||
if (err) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_setiv failed: %s",
|
||||
gpg_strerror(err));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Pass the authenticated data (packet_length) */
|
||||
err = gcry_cipher_authenticate(cipher->key[0],
|
||||
complete_packet,
|
||||
aadlen);
|
||||
if (err) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_authenticate failed: %s",
|
||||
gpg_strerror(err));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
/* Do not copy the length to the target buffer, because it is already processed */
|
||||
//memcpy(out, complete_packet, aadlen);
|
||||
|
||||
/* Encrypt the rest of the data */
|
||||
err = gcry_cipher_decrypt(cipher->key[0],
|
||||
out,
|
||||
encrypted_size,
|
||||
(unsigned char *)complete_packet + aadlen,
|
||||
encrypted_size);
|
||||
if (err) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_decrypt failed: %s",
|
||||
gpg_strerror(err));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Check the tag */
|
||||
err = gcry_cipher_checktag(cipher->key[0],
|
||||
(unsigned char *)complete_packet + aadlen + encrypted_size,
|
||||
authlen);
|
||||
if (gpg_err_code(err) == GPG_ERR_CHECKSUM) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "The authentication tag does not match");
|
||||
return SSH_ERROR;
|
||||
} else if (err != GPG_ERR_NO_ERROR) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "General error while decryption: %s",
|
||||
gpg_strerror(err));
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return SSH_OK;
|
||||
static void aes_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len) {
|
||||
gcry_cipher_decrypt(cipher->key[0], out, len, in, len);
|
||||
}
|
||||
|
||||
static int des3_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) {
|
||||
@@ -560,7 +439,6 @@ static void des3_decrypt(struct ssh_cipher_struct *cipher, void *in,
|
||||
|
||||
/* the table of supported ciphers */
|
||||
static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
{
|
||||
.name = "blowfish-cbc",
|
||||
.blocksize = 8,
|
||||
@@ -572,7 +450,6 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
.encrypt = blowfish_encrypt,
|
||||
.decrypt = blowfish_decrypt
|
||||
},
|
||||
#endif /* WITH_BLOWFISH_CIPHER */
|
||||
{
|
||||
.name = "aes128-ctr",
|
||||
.blocksize = 16,
|
||||
@@ -639,34 +516,6 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
.encrypt = aes_encrypt,
|
||||
.decrypt = aes_decrypt
|
||||
},
|
||||
{
|
||||
.name = "aes128-gcm@openssh.com",
|
||||
.blocksize = 16,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.keylen = sizeof(gcry_cipher_hd_t),
|
||||
.key = NULL,
|
||||
.keysize = 128,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.set_encrypt_key = aes_set_key,
|
||||
.set_decrypt_key = aes_set_key,
|
||||
.aead_encrypt = aes_gcm_encrypt,
|
||||
.aead_decrypt_length = aes_aead_get_length,
|
||||
.aead_decrypt = aes_gcm_decrypt,
|
||||
},
|
||||
{
|
||||
.name = "aes256-gcm@openssh.com",
|
||||
.blocksize = 16,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.keylen = sizeof(gcry_cipher_hd_t),
|
||||
.key = NULL,
|
||||
.keysize = 256,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.set_encrypt_key = aes_set_key,
|
||||
.set_decrypt_key = aes_set_key,
|
||||
.aead_encrypt = aes_gcm_encrypt,
|
||||
.aead_decrypt_length = aes_aead_get_length,
|
||||
.aead_decrypt = aes_gcm_decrypt,
|
||||
},
|
||||
{
|
||||
.name = "3des-cbc",
|
||||
.blocksize = 8,
|
||||
|
||||
@@ -26,17 +26,17 @@
|
||||
#include "libssh/wrapper.h"
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/priv.h"
|
||||
#include "libssh/misc.h"
|
||||
|
||||
#ifdef HAVE_LIBMBEDCRYPTO
|
||||
#include <mbedtls/md.h>
|
||||
#ifdef MBEDTLS_GCM_C
|
||||
#include <mbedtls/gcm.h>
|
||||
#endif /* MBEDTLS_GCM_C */
|
||||
|
||||
static mbedtls_entropy_context ssh_mbedtls_entropy;
|
||||
static mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
|
||||
|
||||
struct ssh_mac_ctx_struct {
|
||||
enum ssh_mac_e mac_type;
|
||||
mbedtls_md_context_t ctx;
|
||||
};
|
||||
static int libmbedcrypto_initialized = 0;
|
||||
|
||||
void ssh_reseed(void)
|
||||
@@ -94,7 +94,7 @@ void sha1_final(unsigned char *md, SHACTX c)
|
||||
SAFE_FREE(c);
|
||||
}
|
||||
|
||||
void sha1(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha1(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
const mbedtls_md_info_t *md_info =
|
||||
mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
|
||||
@@ -222,7 +222,7 @@ void sha256_final(unsigned char *md, SHA256CTX c)
|
||||
SAFE_FREE(c);
|
||||
}
|
||||
|
||||
void sha256(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha256(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
const mbedtls_md_info_t *md_info =
|
||||
mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
@@ -276,7 +276,7 @@ void sha384_final(unsigned char *md, SHA384CTX c)
|
||||
SAFE_FREE(c);
|
||||
}
|
||||
|
||||
void sha384(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha384(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
const mbedtls_md_info_t *md_info =
|
||||
mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
|
||||
@@ -329,7 +329,7 @@ void sha512_final(unsigned char *md, SHA512CTX c)
|
||||
SAFE_FREE(c);
|
||||
}
|
||||
|
||||
void sha512(const unsigned char *digest, int len, unsigned char *hash)
|
||||
void sha512(unsigned char *digest, int len, unsigned char *hash)
|
||||
{
|
||||
const mbedtls_md_info_t *md_info =
|
||||
mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
|
||||
@@ -382,13 +382,66 @@ void md5_final(unsigned char *md, MD5CTX c)
|
||||
SAFE_FREE(c);
|
||||
}
|
||||
|
||||
int ssh_kdf(struct ssh_crypto_struct *crypto,
|
||||
unsigned char *key, size_t key_len,
|
||||
int key_type, unsigned char *output,
|
||||
size_t requested_len)
|
||||
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type)
|
||||
{
|
||||
return sshkdf_derive_key(crypto, key, key_len,
|
||||
key_type, output, requested_len);
|
||||
ssh_mac_ctx ctx = malloc(sizeof (struct ssh_mac_ctx_struct));
|
||||
const mbedtls_md_info_t *md_info;
|
||||
int rc;
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->mac_type=type;
|
||||
switch(type) {
|
||||
case SSH_MAC_SHA1:
|
||||
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
|
||||
break;
|
||||
case SSH_MAC_SHA256:
|
||||
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
break;
|
||||
case SSH_MAC_SHA384:
|
||||
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
|
||||
break;
|
||||
case SSH_MAC_SHA512:
|
||||
md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (md_info == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
mbedtls_md_init(&ctx->ctx);
|
||||
|
||||
rc = mbedtls_md_setup(&ctx->ctx, md_info, 0);
|
||||
if (rc != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_md_starts(&ctx->ctx);
|
||||
if (rc != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
|
||||
error:
|
||||
SAFE_FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len)
|
||||
{
|
||||
mbedtls_md_update(&ctx->ctx, data, len);
|
||||
}
|
||||
|
||||
void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx)
|
||||
{
|
||||
mbedtls_md_finish(&ctx->ctx, md);
|
||||
mbedtls_md_free(&ctx->ctx);
|
||||
SAFE_FREE(ctx);
|
||||
}
|
||||
|
||||
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type)
|
||||
@@ -453,68 +506,39 @@ void hmac_final(HMACCTX c, unsigned char *hashmacbuf, unsigned int *len)
|
||||
SAFE_FREE(c);
|
||||
}
|
||||
|
||||
static int
|
||||
cipher_init(struct ssh_cipher_struct *cipher,
|
||||
mbedtls_operation_t operation,
|
||||
void *key,
|
||||
void *IV)
|
||||
static int cipher_set_encrypt_key(struct ssh_cipher_struct *cipher, void *key,
|
||||
void *IV)
|
||||
{
|
||||
|
||||
const mbedtls_cipher_info_t *cipher_info = NULL;
|
||||
mbedtls_cipher_context_t *ctx;
|
||||
int rc;
|
||||
|
||||
if (operation == MBEDTLS_ENCRYPT) {
|
||||
ctx = &cipher->encrypt_ctx;
|
||||
} else if (operation == MBEDTLS_DECRYPT) {
|
||||
ctx = &cipher->decrypt_ctx;
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_WARNING, "unknown operation");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mbedtls_cipher_init(ctx);
|
||||
mbedtls_cipher_init(&cipher->encrypt_ctx);
|
||||
cipher_info = mbedtls_cipher_info_from_type(cipher->type);
|
||||
|
||||
rc = mbedtls_cipher_setup(ctx, cipher_info);
|
||||
rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_setkey(ctx, key,
|
||||
rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, key,
|
||||
cipher_info->key_bitlen,
|
||||
operation);
|
||||
MBEDTLS_ENCRYPT);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_set_iv(ctx, IV, cipher_info->iv_size);
|
||||
rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size);
|
||||
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
mbedtls_cipher_free(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cipher_set_encrypt_key(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
void *IV)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = cipher_init(cipher, MBEDTLS_ENCRYPT, key, IV);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "cipher_init failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_reset(&cipher->encrypt_ctx);
|
||||
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
|
||||
goto error;
|
||||
@@ -522,19 +546,38 @@ cipher_set_encrypt_key(struct ssh_cipher_struct *cipher,
|
||||
|
||||
return SSH_OK;
|
||||
error:
|
||||
mbedtls_cipher_free(&cipher->encrypt_ctx);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
cipher_set_encrypt_key_cbc(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
void *IV)
|
||||
static int cipher_set_encrypt_key_cbc(struct ssh_cipher_struct *cipher, void *key,
|
||||
void *IV)
|
||||
{
|
||||
|
||||
const mbedtls_cipher_info_t *cipher_info = NULL;
|
||||
int rc;
|
||||
|
||||
rc = cipher_init(cipher, MBEDTLS_ENCRYPT, key, IV);
|
||||
mbedtls_cipher_init(&cipher->encrypt_ctx);
|
||||
cipher_info = mbedtls_cipher_info_from_type(cipher->type);
|
||||
|
||||
rc = mbedtls_cipher_setup(&cipher->encrypt_ctx, cipher_info);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "cipher_init failed");
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_setkey(&cipher->encrypt_ctx, key,
|
||||
cipher_info->key_bitlen,
|
||||
MBEDTLS_ENCRYPT);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_set_iv(&cipher->encrypt_ctx, IV, cipher_info->iv_size);
|
||||
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -549,6 +592,7 @@ cipher_set_encrypt_key_cbc(struct ssh_cipher_struct *cipher,
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_reset(&cipher->encrypt_ctx);
|
||||
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
|
||||
goto error;
|
||||
@@ -560,51 +604,37 @@ error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#ifdef MBEDTLS_GCM_C
|
||||
static int
|
||||
cipher_set_key_gcm(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
void *IV)
|
||||
static int cipher_set_decrypt_key(struct ssh_cipher_struct *cipher, void *key,
|
||||
void *IV)
|
||||
{
|
||||
const mbedtls_cipher_info_t *cipher_info = NULL;
|
||||
int rc;
|
||||
|
||||
mbedtls_gcm_init(&cipher->gcm_ctx);
|
||||
mbedtls_cipher_init(&cipher->decrypt_ctx);
|
||||
cipher_info = mbedtls_cipher_info_from_type(cipher->type);
|
||||
|
||||
rc = mbedtls_gcm_setkey(&cipher->gcm_ctx,
|
||||
MBEDTLS_CIPHER_ID_AES,
|
||||
key,
|
||||
cipher_info->key_bitlen);
|
||||
rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_setkey failed");
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Store the IV so we can increment the packet counter later */
|
||||
memcpy(cipher->last_iv, IV, AES_GCM_IVLEN);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
mbedtls_gcm_free(&cipher->gcm_ctx);
|
||||
return 1;
|
||||
}
|
||||
#endif /* MBEDTLS_GCM_C */
|
||||
|
||||
static int
|
||||
cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
void *IV)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = cipher_init(cipher, MBEDTLS_DECRYPT, key, IV);
|
||||
rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, key,
|
||||
cipher_info->key_bitlen,
|
||||
MBEDTLS_DECRYPT);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "cipher_init failed");
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
mbedtls_cipher_reset(&cipher->decrypt_ctx);
|
||||
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
|
||||
goto error;
|
||||
@@ -616,27 +646,45 @@ error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
cipher_set_decrypt_key_cbc(struct ssh_cipher_struct *cipher,
|
||||
void *key,
|
||||
void *IV)
|
||||
static int cipher_set_decrypt_key_cbc(struct ssh_cipher_struct *cipher, void *key,
|
||||
void *IV)
|
||||
{
|
||||
const mbedtls_cipher_info_t *cipher_info;
|
||||
int rc;
|
||||
|
||||
rc = cipher_init(cipher, MBEDTLS_DECRYPT, key, IV);
|
||||
mbedtls_cipher_init(&cipher->decrypt_ctx);
|
||||
cipher_info = mbedtls_cipher_info_from_type(cipher->type);
|
||||
|
||||
rc = mbedtls_cipher_setup(&cipher->decrypt_ctx, cipher_info);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "cipher_init failed");
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_setkey(&cipher->decrypt_ctx, key,
|
||||
cipher_info->key_bitlen,
|
||||
MBEDTLS_DECRYPT);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_set_iv(&cipher->decrypt_ctx, IV, cipher_info->iv_size);
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = mbedtls_cipher_set_padding_mode(&cipher->decrypt_ctx,
|
||||
MBEDTLS_PADDING_NONE);
|
||||
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
mbedtls_cipher_reset(&cipher->decrypt_ctx);
|
||||
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed");
|
||||
goto error;
|
||||
@@ -648,10 +696,8 @@ error:
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
static void cipher_encrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
static void cipher_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len)
|
||||
{
|
||||
size_t outlen = 0;
|
||||
size_t total_len = 0;
|
||||
@@ -705,10 +751,8 @@ static void cipher_encrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void
|
||||
|
||||
}
|
||||
|
||||
static void cipher_decrypt(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len)
|
||||
static void cipher_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||
unsigned long len)
|
||||
{
|
||||
size_t outlen = 0;
|
||||
int rc = 0;
|
||||
@@ -789,109 +833,13 @@ static void cipher_decrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void
|
||||
|
||||
}
|
||||
|
||||
#ifdef MBEDTLS_GCM_C
|
||||
static int
|
||||
cipher_gcm_get_length(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
uint8_t *out,
|
||||
size_t len,
|
||||
uint64_t seq)
|
||||
{
|
||||
(void)cipher;
|
||||
(void)seq;
|
||||
|
||||
/* The length is not encrypted: Copy it to the result buffer */
|
||||
memcpy(out, in, len);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
cipher_encrypt_gcm(struct ssh_cipher_struct *cipher,
|
||||
void *in,
|
||||
void *out,
|
||||
size_t len,
|
||||
uint8_t *tag,
|
||||
uint64_t seq)
|
||||
{
|
||||
size_t authlen, aadlen;
|
||||
int rc;
|
||||
|
||||
(void) seq;
|
||||
|
||||
aadlen = cipher->lenfield_blocksize;
|
||||
authlen = cipher->tag_size;
|
||||
|
||||
/* The length is not encrypted */
|
||||
memcpy(out, in, aadlen);
|
||||
rc = mbedtls_gcm_crypt_and_tag(&cipher->gcm_ctx,
|
||||
MBEDTLS_GCM_ENCRYPT,
|
||||
len - aadlen, /* encrypted data len */
|
||||
cipher->last_iv, /* IV */
|
||||
AES_GCM_IVLEN,
|
||||
in, /* aad */
|
||||
aadlen,
|
||||
(const unsigned char *)in + aadlen, /* input */
|
||||
(unsigned char *)out + aadlen, /* output */
|
||||
authlen,
|
||||
tag); /* tag */
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_crypt_and_tag failed");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Increment the IV for the next invocation */
|
||||
uint64_inc(cipher->last_iv + 4);
|
||||
}
|
||||
|
||||
static int
|
||||
cipher_decrypt_gcm(struct ssh_cipher_struct *cipher,
|
||||
void *complete_packet,
|
||||
uint8_t *out,
|
||||
size_t encrypted_size,
|
||||
uint64_t seq)
|
||||
{
|
||||
size_t authlen, aadlen;
|
||||
int rc;
|
||||
|
||||
(void) seq;
|
||||
|
||||
aadlen = cipher->lenfield_blocksize;
|
||||
authlen = cipher->tag_size;
|
||||
|
||||
rc = mbedtls_gcm_auth_decrypt(&cipher->gcm_ctx,
|
||||
encrypted_size, /* encrypted data len */
|
||||
cipher->last_iv, /* IV */
|
||||
AES_GCM_IVLEN,
|
||||
complete_packet, /* aad */
|
||||
aadlen,
|
||||
(const uint8_t *)complete_packet + aadlen + encrypted_size, /* tag */
|
||||
authlen,
|
||||
(const uint8_t *)complete_packet + aadlen, /* input */
|
||||
(unsigned char *)out); /* output */
|
||||
if (rc != 0) {
|
||||
SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_auth_decrypt failed");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Increment the IV for the next invocation */
|
||||
uint64_inc(cipher->last_iv + 4);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
#endif /* MBEDTLS_GCM_C */
|
||||
|
||||
static void cipher_cleanup(struct ssh_cipher_struct *cipher)
|
||||
{
|
||||
mbedtls_cipher_free(&cipher->encrypt_ctx);
|
||||
mbedtls_cipher_free(&cipher->decrypt_ctx);
|
||||
#ifdef MBEDTLS_GCM_C
|
||||
mbedtls_gcm_free(&cipher->gcm_ctx);
|
||||
#endif /* MBEDTLS_GCM_C */
|
||||
}
|
||||
|
||||
static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
#ifdef WITH_BLOWFISH_CIPHER
|
||||
{
|
||||
.name = "blowfish-cbc",
|
||||
.blocksize = 8,
|
||||
@@ -903,7 +851,6 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
.decrypt = cipher_decrypt_cbc,
|
||||
.cleanup = cipher_cleanup
|
||||
},
|
||||
#endif /* WITH_BLOWFISH_CIPHER */
|
||||
{
|
||||
.name = "aes128-ctr",
|
||||
.blocksize = 16,
|
||||
@@ -970,36 +917,6 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||
.decrypt = cipher_decrypt_cbc,
|
||||
.cleanup = cipher_cleanup
|
||||
},
|
||||
#ifdef MBEDTLS_GCM_C
|
||||
{
|
||||
.name = "aes128-gcm@openssh.com",
|
||||
.blocksize = 16,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.keysize = 128,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.type = MBEDTLS_CIPHER_AES_128_GCM,
|
||||
.set_encrypt_key = cipher_set_key_gcm,
|
||||
.set_decrypt_key = cipher_set_key_gcm,
|
||||
.aead_encrypt = cipher_encrypt_gcm,
|
||||
.aead_decrypt_length = cipher_gcm_get_length,
|
||||
.aead_decrypt = cipher_decrypt_gcm,
|
||||
.cleanup = cipher_cleanup
|
||||
},
|
||||
{
|
||||
.name = "aes256-gcm@openssh.com",
|
||||
.blocksize = 16,
|
||||
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
|
||||
.keysize = 256,
|
||||
.tag_size = AES_GCM_TAGLEN,
|
||||
.type = MBEDTLS_CIPHER_AES_256_GCM,
|
||||
.set_encrypt_key = cipher_set_key_gcm,
|
||||
.set_decrypt_key = cipher_set_key_gcm,
|
||||
.aead_encrypt = cipher_encrypt_gcm,
|
||||
.aead_decrypt_length = cipher_gcm_get_length,
|
||||
.aead_decrypt = cipher_decrypt_gcm,
|
||||
.cleanup = cipher_cleanup
|
||||
},
|
||||
#endif /* MBEDTLS_GCM_C */
|
||||
{
|
||||
.name = "3des-cbc",
|
||||
.blocksize = 8,
|
||||
|
||||
@@ -431,19 +431,3 @@ LIBSSH_4_7_0 # Released
|
||||
ssh_get_fingerprint_hash;
|
||||
ssh_pki_export_privkey_base64;
|
||||
} LIBSSH_4_6_0;
|
||||
|
||||
LIBSSH_4_8_0 # Released
|
||||
{
|
||||
global:
|
||||
sftp_server_free;
|
||||
ssh_bind_options_parse_config;
|
||||
ssh_channel_open_forward_unix;
|
||||
ssh_message_channel_request_open_reply_accept_channel;
|
||||
} LIBSSH_4_7_0;
|
||||
|
||||
LIBSSH_4_8_1 # Released
|
||||
{
|
||||
global:
|
||||
ssh_session_get_known_hosts_entry;
|
||||
ssh_threads_get_default;
|
||||
} LIBSSH_4_8_0;
|
||||
|
||||
@@ -45,14 +45,14 @@ void ssh_mbedcry_bn_free(bignum bn)
|
||||
SAFE_FREE(bn);
|
||||
}
|
||||
|
||||
unsigned char *ssh_mbedcry_bn2num(bignum num, int radix)
|
||||
char *ssh_mbedcry_bn2num(bignum num, int radix)
|
||||
{
|
||||
char *buf = NULL;
|
||||
size_t olen;
|
||||
int rc;
|
||||
|
||||
rc = mbedtls_mpi_write_string(num, radix, buf, 0, &olen);
|
||||
if (rc != 0 && rc != MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL) {
|
||||
if (rc != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ unsigned char *ssh_mbedcry_bn2num(bignum num, int radix)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (unsigned char *) buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom)
|
||||
@@ -81,12 +81,6 @@ int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom)
|
||||
}
|
||||
|
||||
len = bits / 8 + 1;
|
||||
/* FIXME weird bug: over 1024, fill_random function returns an error code
|
||||
* MBEDTLS_ERR_MPI_BAD_INPUT_DATA -0x0004
|
||||
*/
|
||||
if (len > 1024){
|
||||
len = 1024;
|
||||
}
|
||||
rc = mbedtls_mpi_fill_random(rnd,
|
||||
len,
|
||||
mbedtls_ctr_drbg_random,
|
||||
@@ -133,44 +127,4 @@ int ssh_mbedcry_is_bit_set(bignum num, size_t pos)
|
||||
bit = mbedtls_mpi_get_bit(num, pos);
|
||||
return bit;
|
||||
}
|
||||
|
||||
/** @brief generates a random integer between 0 and max
|
||||
* @returns 1 in case of success, 0 otherwise
|
||||
*/
|
||||
int ssh_mbedcry_rand_range(bignum dest, bignum max)
|
||||
{
|
||||
size_t bits;
|
||||
bignum rnd;
|
||||
int rc;
|
||||
|
||||
bits = bignum_num_bits(max) + 64;
|
||||
rnd = bignum_new();
|
||||
if (rnd == NULL){
|
||||
return 0;
|
||||
}
|
||||
rc = bignum_rand(rnd, bits);
|
||||
if (rc != 1){
|
||||
return rc;
|
||||
}
|
||||
mbedtls_mpi_mod_mpi(dest, rnd, max);
|
||||
bignum_safe_free(rnd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ssh_mbedcry_hex2bn(bignum *dest, char *data)
|
||||
{
|
||||
int rc;
|
||||
|
||||
*dest = bignum_new();
|
||||
if (*dest == NULL){
|
||||
return 0;
|
||||
}
|
||||
rc = mbedtls_mpi_read_string(*dest, 16, data);
|
||||
if (rc == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
284
src/messages.c
284
src/messages.c
@@ -63,15 +63,14 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
static ssh_message ssh_message_new(ssh_session session)
|
||||
{
|
||||
ssh_message msg = calloc(1, sizeof(struct ssh_message_struct));
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
msg->session = session;
|
||||
|
||||
return msg;
|
||||
static ssh_message ssh_message_new(ssh_session session){
|
||||
ssh_message msg = malloc(sizeof(struct ssh_message_struct));
|
||||
if (msg == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ZERO_STRUCTP(msg);
|
||||
msg->session = session;
|
||||
return msg;
|
||||
}
|
||||
|
||||
#ifndef WITH_SERVER
|
||||
@@ -156,11 +155,6 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
|
||||
session->server_callbacks->userdata);
|
||||
if (channel != NULL) {
|
||||
rc = ssh_message_channel_request_open_reply_accept_channel(msg, channel);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"Failed to send reply for accepting a channel "
|
||||
"open");
|
||||
}
|
||||
return SSH_OK;
|
||||
} else {
|
||||
ssh_message_reply_default(msg);
|
||||
@@ -233,10 +227,6 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
|
||||
msg->channel_request.height,
|
||||
msg->channel_request.pxwidth,
|
||||
msg->channel_request.pxheight);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_WARNING,
|
||||
"Failed to iterate callbacks for window change");
|
||||
}
|
||||
return SSH_OK;
|
||||
}
|
||||
ssh_callbacks_iterate_end();
|
||||
@@ -382,16 +372,16 @@ static int ssh_execute_message_callback(ssh_session session, ssh_message msg) {
|
||||
session->ssh_message_callback_data);
|
||||
if(ret == 1) {
|
||||
ret = ssh_message_reply_default(msg);
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
ssh_message_free(msg);
|
||||
if(ret != SSH_OK) {
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
ssh_message_free(msg);
|
||||
}
|
||||
} else {
|
||||
ret = ssh_message_reply_default(msg);
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
ssh_message_free(msg);
|
||||
if(ret != SSH_OK) {
|
||||
return ret;
|
||||
}
|
||||
@@ -409,60 +399,46 @@ static int ssh_execute_message_callback(ssh_session session, ssh_message msg) {
|
||||
*
|
||||
* @param[in] message The message to add to the queue.
|
||||
*/
|
||||
static void ssh_message_queue(ssh_session session, ssh_message message)
|
||||
{
|
||||
void ssh_message_queue(ssh_session session, ssh_message message){
|
||||
if (message != NULL) {
|
||||
#ifdef WITH_SERVER
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
if (message == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
/* probably not the best place to execute server callbacks, but still better
|
||||
* than nothing.
|
||||
*/
|
||||
ret = ssh_execute_server_callbacks(session, message);
|
||||
if (ret == SSH_OK) {
|
||||
SSH_MESSAGE_FREE(message);
|
||||
return;
|
||||
}
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
if (session->ssh_message_callback != NULL) {
|
||||
/* This will transfer the message, do not free. */
|
||||
ssh_execute_message_callback(session, message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (session->server_callbacks != NULL) {
|
||||
/* if we have server callbacks, but nothing was executed, it means we are
|
||||
* in non-synchronous mode, and we just don't care about the message we
|
||||
* received. Just send a default response. Do not queue it.
|
||||
int ret;
|
||||
/* probably not the best place to execute server callbacks, but still better
|
||||
* than nothing.
|
||||
*/
|
||||
ssh_message_reply_default(message);
|
||||
SSH_MESSAGE_FREE(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (session->ssh_message_list == NULL) {
|
||||
session->ssh_message_list = ssh_list_new();
|
||||
if (session->ssh_message_list == NULL) {
|
||||
/*
|
||||
* If the message list couldn't be allocated, the message can't be
|
||||
* enqueued
|
||||
ret = ssh_execute_server_callbacks(session, message);
|
||||
if (ret == SSH_OK){
|
||||
ssh_message_free(message);
|
||||
return;
|
||||
}
|
||||
#endif /* WITH_SERVER */
|
||||
if(session->ssh_message_callback != NULL) {
|
||||
ssh_execute_message_callback(session, message);
|
||||
return;
|
||||
}
|
||||
if (session->server_callbacks != NULL){
|
||||
/* if we have server callbacks, but nothing was executed, it means we are
|
||||
* in non-synchronous mode, and we just don't care about the message we
|
||||
* received. Just send a default response. Do not queue it.
|
||||
*/
|
||||
ssh_message_reply_default(message);
|
||||
ssh_message_free(message);
|
||||
return;
|
||||
}
|
||||
if(session->ssh_message_list == NULL) {
|
||||
session->ssh_message_list = ssh_list_new();
|
||||
}
|
||||
if (session->ssh_message_list != NULL) {
|
||||
ssh_list_append(session->ssh_message_list, message);
|
||||
} else {
|
||||
/* If the message list couldn't be allocated, the message can't be
|
||||
* enqueued */
|
||||
ssh_message_reply_default(message);
|
||||
ssh_set_error_oom(session);
|
||||
SSH_MESSAGE_FREE(message);
|
||||
ssh_message_free(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* This will transfer the message, do not free. */
|
||||
ssh_list_append(session->ssh_message_list, message);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -635,42 +611,38 @@ void ssh_message_free(ssh_message msg){
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
|
||||
SSH_PACKET_CALLBACK(ssh_packet_service_request)
|
||||
{
|
||||
char *service_c = NULL;
|
||||
ssh_message msg = NULL;
|
||||
int rc;
|
||||
SSH_PACKET_CALLBACK(ssh_packet_service_request){
|
||||
ssh_string service = NULL;
|
||||
char *service_c = NULL;
|
||||
ssh_message msg=NULL;
|
||||
|
||||
(void)type;
|
||||
(void)user;
|
||||
(void)type;
|
||||
(void)user;
|
||||
service = ssh_buffer_get_ssh_string(packet);
|
||||
if (service == NULL) {
|
||||
ssh_set_error(session, SSH_FATAL, "Invalid SSH_MSG_SERVICE_REQUEST packet");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = ssh_buffer_unpack(packet,
|
||||
"s",
|
||||
&service_c);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Invalid SSH_MSG_SERVICE_REQUEST packet");
|
||||
goto error;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Received a SERVICE_REQUEST for service %s",
|
||||
service_c);
|
||||
|
||||
msg = ssh_message_new(session);
|
||||
if (msg == NULL) {
|
||||
SAFE_FREE(service_c);
|
||||
goto error;
|
||||
}
|
||||
|
||||
msg->type = SSH_REQUEST_SERVICE;
|
||||
msg->service_request.service = service_c;
|
||||
|
||||
ssh_message_queue(session, msg);
|
||||
service_c = ssh_string_to_char(service);
|
||||
if (service_c == NULL) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Received a SERVICE_REQUEST for service %s", service_c);
|
||||
msg=ssh_message_new(session);
|
||||
if(!msg){
|
||||
SAFE_FREE(service_c);
|
||||
goto error;
|
||||
}
|
||||
msg->type=SSH_REQUEST_SERVICE;
|
||||
msg->service_request.service=service_c;
|
||||
error:
|
||||
ssh_string_free(service);
|
||||
if(msg != NULL)
|
||||
ssh_message_queue(session,msg);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
|
||||
@@ -683,13 +655,13 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
|
||||
const char *service,
|
||||
ssh_string algo)
|
||||
{
|
||||
struct ssh_crypto_struct *crypto = NULL;
|
||||
struct ssh_crypto_struct *crypto =
|
||||
session->current_crypto ? session->current_crypto :
|
||||
session->next_crypto;
|
||||
ssh_buffer buffer;
|
||||
ssh_string str=NULL;
|
||||
int rc;
|
||||
|
||||
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
|
||||
|
||||
buffer = ssh_buffer_new();
|
||||
if (buffer == NULL) {
|
||||
return NULL;
|
||||
@@ -868,28 +840,11 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
msg->auth_request.pubkey,
|
||||
&sig);
|
||||
if (rc == SSH_OK) {
|
||||
/* Check if the signature from client matches server preferences */
|
||||
if (session->opts.pubkey_accepted_types) {
|
||||
if (!ssh_match_group(session->opts.pubkey_accepted_types,
|
||||
sig->type_c))
|
||||
{
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Public key from client (%s) doesn't match server "
|
||||
"preference (%s)",
|
||||
sig->type_c,
|
||||
session->opts.pubkey_accepted_types);
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == SSH_OK) {
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
sig,
|
||||
msg->auth_request.pubkey,
|
||||
ssh_buffer_get(digest),
|
||||
ssh_buffer_get_len(digest));
|
||||
}
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
sig,
|
||||
msg->auth_request.pubkey,
|
||||
ssh_buffer_get(digest),
|
||||
ssh_buffer_get_len(digest));
|
||||
}
|
||||
ssh_string_free(sig_blob);
|
||||
ssh_buffer_free(digest);
|
||||
@@ -897,7 +852,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
if (rc < 0) {
|
||||
SSH_LOG(
|
||||
SSH_LOG_PACKET,
|
||||
"Received an invalid signature from peer");
|
||||
"Received an invalid signature from peer");
|
||||
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
|
||||
goto error;
|
||||
}
|
||||
@@ -954,7 +909,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
/* bypass the message queue thing */
|
||||
SAFE_FREE(service);
|
||||
SAFE_FREE(method);
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
ssh_message_free(msg);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
@@ -967,7 +922,7 @@ error:
|
||||
SAFE_FREE(service);
|
||||
SAFE_FREE(method);
|
||||
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
ssh_message_free(msg);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
end:
|
||||
@@ -1110,7 +1065,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
|
||||
return SSH_PACKET_USED;
|
||||
|
||||
error:
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
ssh_message_free(msg);
|
||||
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
@@ -1209,7 +1164,8 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open){
|
||||
goto end;
|
||||
|
||||
error:
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
ssh_message_free(msg);
|
||||
msg=NULL;
|
||||
end:
|
||||
SAFE_FREE(type_c);
|
||||
if(msg != NULL)
|
||||
@@ -1218,17 +1174,6 @@ end:
|
||||
return SSH_PACKET_USED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief This function accepts a channel open request for the specified channel.
|
||||
*
|
||||
* @param[in] msg The message.
|
||||
*
|
||||
* @param[in] chan The channel the request is made on.
|
||||
*
|
||||
* @returns SSH_OK on success, SSH_ERROR if an error occured.
|
||||
*/
|
||||
int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_channel chan) {
|
||||
ssh_session session;
|
||||
int rc;
|
||||
@@ -1269,17 +1214,7 @@ int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_c
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief This function accepts a channel open request.
|
||||
*
|
||||
* @param[in] msg The message.
|
||||
*
|
||||
* @returns a valid ssh_channel handle if the request is to be allowed
|
||||
*
|
||||
* @returns NULL in case of error
|
||||
*/
|
||||
|
||||
ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) {
|
||||
ssh_channel chan;
|
||||
int rc;
|
||||
@@ -1427,7 +1362,7 @@ end:
|
||||
|
||||
return SSH_OK;
|
||||
error:
|
||||
SSH_MESSAGE_FREE(msg);
|
||||
ssh_message_free(msg);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -1491,18 +1426,12 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
msg->type = SSH_REQUEST_GLOBAL;
|
||||
|
||||
if (strcmp(request, "tcpip-forward") == 0) {
|
||||
|
||||
/* According to RFC4254, the client SHOULD reject this message */
|
||||
if (session->client) {
|
||||
goto reply_with_failure;
|
||||
}
|
||||
|
||||
r = ssh_buffer_unpack(packet, "sd",
|
||||
&msg->global_request.bind_address,
|
||||
&msg->global_request.bind_port
|
||||
);
|
||||
if (r != SSH_OK){
|
||||
goto reply_with_failure;
|
||||
goto error;
|
||||
}
|
||||
msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
|
||||
msg->global_request.want_reply = want_reply;
|
||||
@@ -1522,17 +1451,11 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
return rc;
|
||||
}
|
||||
} else if (strcmp(request, "cancel-tcpip-forward") == 0) {
|
||||
|
||||
/* According to RFC4254, the client SHOULD reject this message */
|
||||
if (session->client) {
|
||||
goto reply_with_failure;
|
||||
}
|
||||
|
||||
r = ssh_buffer_unpack(packet, "sd",
|
||||
&msg->global_request.bind_address,
|
||||
&msg->global_request.bind_port);
|
||||
if (r != SSH_OK){
|
||||
goto reply_with_failure;
|
||||
goto error;
|
||||
}
|
||||
msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
|
||||
msg->global_request.want_reply = want_reply;
|
||||
@@ -1558,41 +1481,18 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
|
||||
ssh_message_global_request_reply_success(msg, 0);
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s, "
|
||||
"want_reply = %d", request, want_reply);
|
||||
goto reply_with_failure;
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply);
|
||||
rc = SSH_PACKET_NOT_USED;
|
||||
}
|
||||
|
||||
SAFE_FREE(msg);
|
||||
SAFE_FREE(request);
|
||||
return rc;
|
||||
|
||||
reply_with_failure:
|
||||
/* Only report the failure if requested */
|
||||
if (want_reply) {
|
||||
r = ssh_buffer_add_u8(session->out_buffer,
|
||||
SSH2_MSG_REQUEST_FAILURE);
|
||||
if (r < 0) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = ssh_packet_send(session);
|
||||
if (r != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"The requester doesn't want to know the request failed!");
|
||||
}
|
||||
|
||||
/* Consume the message to avoid sending UNIMPLEMENTED later */
|
||||
rc = SSH_PACKET_USED;
|
||||
error:
|
||||
SAFE_FREE(msg);
|
||||
SAFE_FREE(request);
|
||||
SSH_LOG(SSH_LOG_WARNING, "Invalid SSH_MSG_GLOBAL_REQUEST packet");
|
||||
return rc;
|
||||
return SSH_PACKET_NOT_USED;
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user