Compare commits

..

80 Commits

Author SHA1 Message Date
Andreas Schneider
c20b360c96 Bump version to 0.7.6
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2018-10-16 12:45:32 +02:00
Andreas Schneider
5e061962c5 cpack: Fix ignore files
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2018-10-16 12:45:32 +02:00
Anderson Toshiyuki Sasaki
f1d57223db CVE-2018-10933: Add tests for packet filtering
Created the test torture_packet_filter.c which tests if packets are
being correctly filtered.

Fixes T101

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2018-10-09 11:45:59 +02:00
Anderson Toshiyuki Sasaki
b9033ad56a CVE-2018-10933: Introduced packet filtering
The packet filter checks required states for the incoming packets and
reject them if they arrived in the wrong state.

Fixes T101

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2018-10-09 11:45:59 +02:00
Anderson Toshiyuki Sasaki
e5ff7aa410 CVE-2018-10933: Check channel state when OPEN_FAILURE arrives
When a SSH2_MSG_OPEN_FAILURE arrives, the channel state is checked
to be in SSH_CHANNEL_STATE_OPENING.

Fixes T101

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2018-10-09 11:45:59 +02:00
Anderson Toshiyuki Sasaki
3837a0547f CVE-2018-10933: Check channel state when OPEN_CONFIRMATION arrives
When a SSH2_MSG_OPEN_CONFIRMATION arrives, the channel state is checked
to be in SSH_CHANNEL_STATE_OPENING.

Fixes T101

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2018-10-09 11:45:58 +02:00
Anderson Toshiyuki Sasaki
7985acb768 CVE-2018-10933: Set correct state after sending MIC
After sending the client token, the auth state is set as
SSH_AUTH_STATE_GSSAPI_MIC_SENT.  Then this can be expected to be the
state when a USERAUTH_FAILURE or USERAUTH_SUCCESS arrives.

Fixes T101

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2018-10-09 11:45:58 +02:00
Anderson Toshiyuki Sasaki
acd6a1ca8a CVE-2018-10933: Introduce SSH_AUTH_STATE_AUTH_NONE_SENT
The introduced auth state allows to identify when a request without
authentication information was sent.

Fixes T101

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2018-10-09 11:45:58 +02:00
Anderson Toshiyuki Sasaki
ddea46f890 CVE-2018-10933: Introduce SSH_AUTH_STATE_PASSWORD_AUTH_SENT
The introduced auth state allows to identify when authentication using
password was tried.

Fixes T101

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2018-10-09 11:45:58 +02:00
Anderson Toshiyuki Sasaki
e5f0e711b0 CVE-2018-10933: Introduced new auth states
Introduced the states SSH_AUTH_STATE_PUBKEY_OFFER_SENT and
SSH_AUTH_STATE_PUBKEY_AUTH_SENT to know when SSH2_MSG_USERAUTH_PK_OK and
SSH2_MSG_USERAUTH_SUCCESS should be expected.

Fixes T101

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2018-10-09 11:45:58 +02:00
Andreas Schneider
e765c1400a dh: Use ssh_get_fingerprint_hash() in ssh_print_hash()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 92aa2cf496)
2018-10-09 10:16:30 +02:00
Andreas Schneider
7a7c0a54bc dh: Add ssh_get_fingerprint_hash()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit bbed139eca)
2018-10-09 10:16:27 +02:00
Jan-Niklas Burfeind
9c62d6dfcd dh: Add ssh_print_hash() function which can deal with sha256
Signed-off-by: Jan-Niklas Burfeind <libssh@aiyionpri.me>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit f32cb70675)
2018-10-09 10:16:20 +02:00
Jan-Niklas Burfeind
f3f140e65f dh: Add SSH_PUBLICKEY_HASH_SHA256 to ssh_get_publickey_hash()
Signed-off-by: Jan-Niklas Burfeind <libssh@aiyionpri.me>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 1499b38aef)
2018-10-09 10:16:14 +02:00
Jakub Jelen
c977a97093 Assorted changes to make the proxycommand test pass
Cherry-picked from the following commit:
e4653b82bd
2018-10-05 12:09:45 +02:00
Jakub Jelen
743a34ad9f Assorted changes to make the sftp_read test working
CHerry-picked from the following commit:
571f547556
2018-10-05 12:09:45 +02:00
Jakub Jelen
0f9e6598ef Assorted changes to make the sftp_dir test working
Cherry-picked from the following commit:
af3de262b6
2018-10-05 12:09:45 +02:00
Jakub Jelen
f8007d7147 Assorted changes to make the torture_forward test pass
Cherry-picked from the following commit:
be25b58380
2018-10-05 12:09:45 +02:00
Jakub Jelen
3d70d4f08d Assorted changes to make torture_request_env pass
Cherry-picked from the following commit:
4bc6af6c17
2018-10-05 12:09:45 +02:00
Andreas Schneider
bade29d3d5 torture: Fix torture_ssh_session() for cwrap testing
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 66f51df9)
2018-10-05 12:09:45 +02:00
Andreas Schneider
399ff6bbde tests: Add public keys for bob
This also allows bob to auth as alice.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry-picked from commit ee866441)
2018-10-05 12:09:45 +02:00
Jakub Jelen
c0d9aeda18 Assorted changes to make knownhosts test work
Cherry-picked from the following commit:
b65dcb3a35
2018-10-05 12:09:45 +02:00
Andreas Schneider
82b2d31c29 tortrue: Add ed25519 hostkey to sshd
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 250bf37a)
2018-10-05 12:09:45 +02:00
Jakub Jelen
74102dfd7a Assorted changes from master to make torture_algorithms test working
Cherry-picked from the following commits:
cbd75c3e35
3014e3c458
2018-10-05 12:09:45 +02:00
Andreas Schneider
d678f6a9ea torture: Fix building on Windows
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit b74a1841)
2018-10-05 12:09:45 +02:00
Jakub Jelen
00b8e6d1f0 tests: UsePrivilegeSeparation has no effect since OpenSSH 7.5
Additionally, we can already work around the privilege separation.

http://www.openssh.com/txt/release-7.5

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 56317caa)
2018-10-05 12:09:45 +02:00
Jakub Jelen
aeb859e130 tests: Do not trace sshd
OpenSSH's sshd does not work well under valgrind so lets avoid tracing it.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit ca4fb9c6)
2018-10-05 12:09:45 +02:00
Jakub Jelen
b393f7e5e9 tests: Temporarily build chroot_wrapper
(cherry-picked from commit 094aa5eb)
2018-10-05 12:09:45 +02:00
Andreas Schneider
2004617fd0 tests: Always start tests as root so we can switch to a user
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 1729d4a1)
2018-10-05 12:09:45 +02:00
Jakub Jelen
c5fe7c5a72 tests: Do not generate pcap file by default
pcap file is generated by the processes writing to the sockets,
which is not allowed for privilege-separated process in new
OpenSSH servers (confined by seccomp filter).

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 5d3ab421)
2018-10-05 12:09:45 +02:00
Jakub Jelen
fec4dc4eff tests: Give server more time to start
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit f8f7989c)
2018-10-05 12:09:45 +02:00
Jakub Jelen
3d0c9cc6b5 tests: Do not test blowfish ciphers with OpenSSH 7.6 and newer
(cherry-picked from commit b92c4996)
2018-10-05 12:09:45 +02:00
Andreas Schneider
4d6048ef88 torture: Add support to specify verbosity level via env variable
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 2a9c3966)
2018-10-05 12:09:45 +02:00
Andreas Schneider
3d2d777e26 torture: Fix a warning
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 2bd65015)
2018-10-05 12:09:45 +02:00
Aris Adamantiadis
8520adf609 osx: fix compilation
(cherry-picked from commit 886fdc8b)
2018-10-05 12:09:45 +02:00
Justus Winter
c0be59f876 tests: Make test suite work out of the box on Debian
* tests/torture.c (torture_setup_create_sshd_config): Rework how the
location of the sftp server is discovered, and add the Debian-specific
location.

Signed-off-by: Justus Winter <justus@g10code.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit e37fd832)
2018-10-05 12:09:45 +02:00
Andreas Schneider
2983b21996 torture: Fix ssh version detection
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit de309c51)
2018-10-05 12:09:45 +02:00
Andreas Schneider
88ae595583 torture: Set sshd debug level to DEBUG3
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 06343074)
2018-10-05 12:09:45 +02:00
Andreas Schneider
a228c3f728 torture: Also write stderr to a file
This allows to capture debug information of the wrappers.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit c365ff3d)
2018-10-05 12:09:45 +02:00
Andreas Schneider
53ed121a9c torture: Add additional sftp-server path for BSD
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 1bbfe058)
2018-10-05 12:09:45 +02:00
Andreas Schneider
5a1ebdec9d tests: Wait for sshd to start before connecting
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit a3557b81)
2018-10-05 12:09:45 +02:00
Andreas Schneider
bf2a33b21e tests: Turn on PAM support in sshd with pam_wrapper
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 7aa84318)
2018-10-05 12:09:45 +02:00
Andreas Schneider
130194aa0e torture: Improve process termination function
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 0e98f121)
2018-10-05 12:09:45 +02:00
Andreas Schneider
1ebfd3834a tests: Support other openssh versions ...
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 6e7eae96)
2018-10-05 12:09:45 +02:00
Andreas Schneider
1eeeace975 cmake: Configure nss_wrapper and uid_wrapper
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 21b0d29e)
2018-10-02 16:35:28 +02:00
Andreas Schneider
73ebcb3ab8 torture: Start sshd as root
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit a30d16c4)
2018-10-02 16:35:08 +02:00
Andreas Schneider
bd7b509278 torture: Enable old host key algos for testing
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit c1fb9483)
2018-10-02 16:34:49 +02:00
Andreas Schneider
652acbeb21 torture: Enable old cipher and kex algos in sshd
We need to test them, so enable them in the sshd.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit dd0d04ae)
2018-10-02 16:34:23 +02:00
Andreas Schneider
96e04d4691 torture: Create a torture_terminate_process() function
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit ae89b6c0)
2018-10-02 16:34:02 +02:00
Andreas Schneider
7113074ae4 torture: Add torture_teardown_sshd_server().
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 14f1ce2e)
2018-10-02 16:33:40 +02:00
Andreas Schneider
2db325eb74 torture: Restrict files to we write to our user.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 62b0f58d)
2018-10-02 16:33:18 +02:00
Andreas Schneider
9937d0b552 torture: Add function to setup sshd server
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit c3f963e7)
2018-10-02 16:32:45 +02:00
Andreas Schneider
ae3e2a19c8 torture: Add torture_teardown_socket_dir().
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit fd09c4cb)
2018-10-02 16:32:04 +02:00
Andreas Schneider
3567524fb2 torture: Add torture_setup_socket_dir().
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 13f68fc2)
2018-10-02 16:31:32 +02:00
Andreas Schneider
4814c188eb tests: Add ssh host keys for test environment.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit c2d63627)
2018-10-02 16:31:16 +02:00
Andreas Schneider
a317188cb7 cmake: Search for cwrap and sshd.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>

(cherry-picked from commit 6596d27e)
2018-10-02 16:29:17 +02:00
Andreas Schneider
1d4151e51f libcrypt: Add missing header for compat
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-30 14:10:32 +02:00
Andreas Schneider
c228fa7631 pki: Fix duplicating ed25519 public keys
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 816234350d)
2018-06-29 17:18:12 +02:00
Andreas Schneider
9658d36087 kex1: Add missing NULL check in make_rsa1_string()
CID 1388445

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c705fb6e3b)
2018-06-29 17:17:27 +02:00
Nikos Mavrogiannopoulos
bbaa3dc869 kex1: Use libcrypto-compat.h for RSA_get0_key with OpenSSL
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit a95bc8a016)
2018-06-29 17:17:03 +02:00
Andreas Schneider
4f10d6cd57 kex1: Fix building with OpenSSL 1.1+
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8d65edb41f)
2018-06-29 17:16:49 +02:00
Meng Tan
2209fcace3 Set channel as bound when accepting channel open request
Signed-off-by: Meng Tan <mtan@wallix.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit f19158cadf)
2018-06-29 17:16:06 +02:00
Andreas Schneider
a1847660a3 pki: Fix random memory corruption
Fixes T78

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 1444ae5add)
2018-06-29 17:12:46 +02:00
Jon Simons
e2b48dc662 libcrypto: fix resource leak in hmac_final
Fix a resource leak in `hmac_final`: say `HMAC_CTX_free` instead
of `HMAC_CTX_reset`.  This matches the error handling as done in
`hmac_init`.  Introduced with cf1e808e2f.

The problem is reproducible running the `pkd_hello` test with:

    valgrind --leak-check=full ./pkd_hello -i1 -t torture_pkd_openssh_dsa_rsa_default

Resolves https://red.libssh.org/issues/252.

Cherry-picked from a64ddff3fe

Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Jon Simons
1a5b6ac472 libcrypto-compat: fix HMAC_CTX_free for OpenSSL < 1.1.0
On older OpenSSL versions, the EVP_MD_CTX fields within an HMAC_CTX
structure are contained inlined (change here [1]): be sure to not
try to free those fields on those builds.

Found running the `pkd_hello` test with:

    valgrind ./pkd_hello -i1 -t torture_pkd_openssh_dsa_rsa_default

^ valgrind will cite "Invalid free() ..." errors which are present
before this fix and absent after, when building with OpenSSL 1.0.1.

[1] 6e59a892db

Cherry-picked from 25384e9558

Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Andreas Schneider
0dd7a963a9 cmake: Only build libcrypto and libcrypto-compat when needed
This also fixes the gcrypt build.

Cherry-picked from 2f6a866373

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Andreas Schneider
1642cec280 cmake: Use configure check for CRYPTO_ctr128_encrypt
Cherry-picked from 3daf1760a1

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Jakub Jelen
2f1c6668e7 pki_crypto: Use getters and setters for opaque keys and signatures
This is for OpenSSL 1.1.0 support.

Cherry-picked from 3341f49a49

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Jakub Jelen
fbeecf388c libcrypto: Use a pointer for EVP_MD_CTX
This is for OpenSSL 1.1.0 support.

Cherry-picked from 607c671f67

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Jakub Jelen
7933756b5a libcrypto: Use newer API for HMAC
This is for OpenSSL 1.1.0 support.

Cherry-picked from cf1e808e2f

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Jakub Jelen
837e367d2d libcrypto: Introduce a libcrypto compat file
This is for OpenSSL 1.1.0 support.

Cherry-picked from b6cfde8987

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Jakub Jelen
f81c3ada9c libcrypto: Remove AES_ctr128_encrypt()
This is for OpenSSL 1.1.0.

Cherry-picked from d73f665edd

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2018-06-29 17:08:54 +02:00
Artyom V. Poptsov
83663895f4 config: Bugfix: Don't skip unseen opcodes
libssh fails to read the configuration from a config file due to a
wrong check in 'ssh_config_parse_line' procedure in 'config.c'; it's
effectively skipping every opcode (and therefore every option) from
the file.  The change fixes that behaviour.

Signed-off-by: Artyom V. Poptsov <poptsov.artyom@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 5333be5988)
2018-06-29 17:08:54 +02:00
Andreas Schneider
239d0f75b5 messages: Do not leak memory of previously allocated answers
Found by ozz-fuzz

BUG: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1222

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 7c79b5c154)
2017-04-25 16:21:11 +02:00
Andreas Schneider
d88cc720fb messages: Do not leak memory if answeres had been allocated previously
Found by ozz-fuzz

BUG: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1222

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 5eb41492c4)
2017-04-24 13:28:17 +02:00
Andreas Schneider
ee13becf9c messages: Do not leak memory if answered had been allocated previously
BUG: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1184

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c78c6c6542)
2017-04-21 11:14:51 +02:00
Andreas Schneider
95b2dbbeca misc: Validate integers converted from the SSH banner
BUG: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1181

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit d5d8349224)
2017-04-21 11:14:46 +02:00
Andreas Schneider
02c0a3b99b messages: Fix memory leaks in the ssh_packet_global_request callback
BUG: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1208

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 67a2ba6f99)
2017-04-21 11:14:42 +02:00
Andreas Schneider
419731a189 auth: Use calloc in ssh_userauth_agent_pubkey()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 79437fa0c9)
2017-04-21 11:14:39 +02:00
Peter Volpe
2ac987bce9 session: Free session->kbdint in ssh_free()
Makes sure we free pending keyboard auth prompts
so prompts that have not be replied to do not leak.

Signed-off-by: Peter Volpe <pvolpe@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 76ba2b0055)
2017-04-20 17:04:54 +02:00
57 changed files with 2970 additions and 289 deletions

View File

@@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
set(APPLICATION_VERSION_MAJOR "0")
set(APPLICATION_VERSION_MINOR "7")
set(APPLICATION_VERSION_PATCH "5")
set(APPLICATION_VERSION_PATCH "6")
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
@@ -19,7 +19,7 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO
# Increment AGE. Set REVISION to 0
# If the source code was changed, but there were no interface changes:
# Increment REVISION.
set(LIBRARY_VERSION "4.4.2")
set(LIBRARY_VERSION "4.4.3")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked

View File

@@ -19,7 +19,7 @@ set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSIO
### source generator
set(CPACK_SOURCE_GENERATOR "TXZ")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;/obj*/;tags;cscope.*")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;.gitignore;/build*;/obj*;tags;cscope.*")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
if (WIN32)

View File

@@ -1,6 +1,13 @@
ChangeLog
==========
version 0.7.6 (released 2018-10-16)
* Fixed CVE-2018-10933
* Added support for OpenSSL 1.1
* Added SHA256 support for ssh_get_publickey_hash()
* Fixed config parsing
* Fixed random memory corruption when importing pubkeys
version 0.7.5 (released 2017-04-13)
* Fixed a memory allocation issue with buffers
* Fixed PKI on Windows

View File

@@ -91,6 +91,10 @@ if (OPENSSL_FOUND)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(CRYPTO_ctr128_encrypt HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT)
endif()
if (CMAKE_HAVE_PTHREAD_H)

View File

@@ -76,6 +76,9 @@
/*************************** FUNCTIONS ***************************/
/* Define to 1 if you have the `CRYPTO_ctr128_encrypt' function. */
#cmakedefine HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT 1
/* Define to 1 if you have the `snprintf' function. */
#cmakedefine HAVE_SNPRINTF 1

View File

@@ -90,6 +90,14 @@ enum ssh_auth_state_e {
SSH_AUTH_STATE_GSSAPI_TOKEN,
/** We have sent the MIC and expecting to be authenticated */
SSH_AUTH_STATE_GSSAPI_MIC_SENT,
/** We have offered a pubkey to check if it is supported */
SSH_AUTH_STATE_PUBKEY_OFFER_SENT,
/** We have sent pubkey and signature expecting to be authenticated */
SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
/** We have sent a password expecting to be authenticated */
SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
/** We have sent a request without auth information (method 'none') */
SSH_AUTH_STATE_AUTH_NONE_SENT,
};
/** @internal

View File

@@ -79,7 +79,7 @@
/* libssh version */
#define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 7
#define LIBSSH_VERSION_MICRO 5
#define LIBSSH_VERSION_MICRO 6
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
LIBSSH_VERSION_MINOR, \
@@ -444,7 +444,8 @@ LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key);
enum ssh_publickey_hash_type {
SSH_PUBLICKEY_HASH_SHA1,
SSH_PUBLICKEY_HASH_MD5
SSH_PUBLICKEY_HASH_MD5,
SSH_PUBLICKEY_HASH_SHA256
};
LIBSSH_API int ssh_get_publickey_hash(const ssh_key key,
enum ssh_publickey_hash_type type,
@@ -563,6 +564,10 @@ LIBSSH_API int ssh_pki_export_pubkey_file(const ssh_key key,
LIBSSH_API const char *ssh_pki_key_ecdsa_name(const ssh_key key);
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);

View File

@@ -43,6 +43,12 @@ enum ssh_packet_state_e {
PACKET_STATE_PROCESSING
};
enum ssh_packet_filter_result_e {
SSH_PACKET_UNKNOWN,
SSH_PACKET_ALLOWED,
SSH_PACKET_DENIED
};
int packet_send(ssh_session session);
#ifdef WITH_SSH1

View File

@@ -124,7 +124,6 @@ set(libssh_SRCS
kex.c
known_hosts.c
legacy.c
libcrypto.c
log.c
match.c
messages.c
@@ -163,7 +162,11 @@ else (WITH_GCRYPT)
set(libssh_SRCS
${libssh_SRCS}
pki_crypto.c
libcrypto.c
)
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
endif()
endif (WITH_GCRYPT)
if (WITH_SFTP)

View File

@@ -85,6 +85,10 @@ static int ssh_auth_response_termination(void *user){
case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
case SSH_AUTH_STATE_GSSAPI_TOKEN:
case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
case SSH_AUTH_STATE_AUTH_NONE_SENT:
return 0;
default:
return 1;
@@ -137,6 +141,10 @@ static int ssh_userauth_get_response(ssh_session session) {
case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT:
case SSH_AUTH_STATE_GSSAPI_TOKEN:
case SSH_AUTH_STATE_GSSAPI_MIC_SENT:
case SSH_AUTH_STATE_PUBKEY_OFFER_SENT:
case SSH_AUTH_STATE_PUBKEY_AUTH_SENT:
case SSH_AUTH_STATE_PASSWORD_AUTH_SENT:
case SSH_AUTH_STATE_AUTH_NONE_SENT:
case SSH_AUTH_STATE_NONE:
/* not reached */
rc = SSH_AUTH_ERROR;
@@ -275,21 +283,27 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok){
int rc;
SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
SSH_LOG(SSH_LOG_TRACE,
"Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE");
if(session->auth_state==SSH_AUTH_STATE_KBDINT_SENT){
if (session->auth_state == SSH_AUTH_STATE_KBDINT_SENT) {
/* Assuming we are in keyboard-interactive context */
SSH_LOG(SSH_LOG_TRACE,
"keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST");
rc=ssh_packet_userauth_info_request(session,type,packet,user);
"keyboard-interactive context, "
"assuming SSH_USERAUTH_INFO_REQUEST");
rc = ssh_packet_userauth_info_request(session, type, packet, user);
#ifdef WITH_GSSAPI
} else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT){
} else if (session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) {
rc = ssh_packet_userauth_gssapi_response(session, type, packet, user);
#endif
} else if (session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT) {
session->auth_state = SSH_AUTH_STATE_PK_OK;
SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
rc = SSH_PACKET_USED;
} else {
session->auth_state=SSH_AUTH_STATE_PK_OK;
SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK");
rc=SSH_PACKET_USED;
session->auth_state = SSH_AUTH_STATE_ERROR;
SSH_LOG(SSH_LOG_TRACE, "SSH_USERAUTH_PK_OK received in wrong state");
rc = SSH_PACKET_USED;
}
return rc;
@@ -389,7 +403,7 @@ int ssh_userauth_none(ssh_session session, const char *username) {
goto fail;
}
session->auth_state = SSH_AUTH_STATE_NONE;
session->auth_state = SSH_AUTH_STATE_AUTH_NONE_SENT;
session->pending_call_state = SSH_PENDING_CALL_AUTH_NONE;
rc = packet_send(session);
if (rc == SSH_ERROR) {
@@ -501,7 +515,7 @@ int ssh_userauth_try_publickey(ssh_session session,
ssh_string_free(pubkey_s);
session->auth_state = SSH_AUTH_STATE_NONE;
session->auth_state = SSH_AUTH_STATE_PUBKEY_OFFER_SENT;
session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
rc = packet_send(session);
if (rc == SSH_ERROR) {
@@ -622,7 +636,7 @@ int ssh_userauth_publickey(ssh_session session,
goto fail;
}
session->auth_state = SSH_AUTH_STATE_NONE;
session->auth_state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY;
rc = packet_send(session);
if (rc == SSH_ERROR) {
@@ -706,7 +720,7 @@ static int ssh_userauth_agent_publickey(ssh_session session,
goto fail;
}
session->auth_state = SSH_AUTH_STATE_NONE;
session->auth_state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT;
session->pending_call_state = SSH_PENDING_CALL_AUTH_AGENT;
rc = packet_send(session);
if (rc == SSH_ERROR) {
@@ -1163,7 +1177,7 @@ int ssh_userauth_password(ssh_session session,
goto fail;
}
session->auth_state = SSH_AUTH_STATE_NONE;
session->auth_state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT;
session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY;
rc = packet_send(session);
if (rc == SSH_ERROR) {
@@ -1217,11 +1231,10 @@ int ssh_userauth_agent_pubkey(ssh_session session,
ssh_kbdint ssh_kbdint_new(void) {
ssh_kbdint kbd;
kbd = malloc(sizeof(struct ssh_kbdint_struct));
kbd = calloc(1, sizeof(struct ssh_kbdint_struct));
if (kbd == NULL) {
return NULL;
}
ZERO_STRUCTP(kbd);
return kbd;
}

View File

@@ -170,6 +170,15 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
"Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d",
channel->local_channel,
channel->remote_channel);
if (channel->state != SSH_CHANNEL_STATE_OPENING) {
SSH_LOG(SSH_LOG_RARE,
"SSH2_MSG_CHANNEL_OPEN_CONFIRMATION received in incorrect "
"channel state %d",
channel->state);
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL,
"Remote window : %lu, maxpacket : %lu",
(long unsigned int) channel->remote_window,
@@ -210,6 +219,14 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
return SSH_PACKET_USED;
}
if (channel->state != SSH_CHANNEL_STATE_OPENING) {
SSH_LOG(SSH_LOG_RARE,
"SSH2_MSG_CHANNEL_OPEN_FAILURE received in incorrect channel "
"state %d",
channel->state);
goto error;
}
ssh_set_error(session, SSH_REQUEST_DENIED,
"Channel opening failure: channel %u error (%lu) %s",
channel->local_channel,
@@ -217,6 +234,9 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){
error);
SAFE_FREE(error);
channel->state=SSH_CHANNEL_STATE_OPEN_DENIED;
error:
ssh_set_error(session, SSH_FATAL, "Invalid packet");
return SSH_PACKET_USED;
}

View File

@@ -219,7 +219,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
opcode = ssh_config_get_opcode(keyword);
if (*parsing == 1 && opcode != SOC_HOST) {
if (seen[opcode] == 0) {
if (seen[opcode] != 0) {
return 0;
}
seen[opcode] = 1;

159
src/dh.c
View File

@@ -1039,6 +1039,29 @@ int ssh_get_publickey_hash(const ssh_key key,
*hlen = SHA_DIGEST_LEN;
}
break;
case SSH_PUBLICKEY_HASH_SHA256:
{
SHA256CTX ctx;
h = malloc(SHA256_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
ctx = sha256_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
sha256_final(h, ctx);
*hlen = SHA256_DIGEST_LEN;
}
break;
case SSH_PUBLICKEY_HASH_MD5:
{
MD5CTX ctx;
@@ -1074,6 +1097,38 @@ out:
return rc;
}
/**
* @internal
*
* @brief Convert a buffer into an unpadded base64 string.
* The caller has to free the memory.
*
* @param hash What should be converted to a base64 string.
*
* @param len Length of the buffer to convert.
*
* @return The base64 string or NULL on error.
*
* @see ssh_string_free_char()
*/
static char *ssh_get_b64_unpadded(const unsigned char *hash, size_t len)
{
char *b64_padded = NULL;
char *b64_unpadded = NULL;
size_t k;
b64_padded = (char *)bin_to_base64(hash, (int)len);
if (b64_padded == NULL) {
return NULL;
}
for (k = strlen(b64_padded); k != 0 && b64_padded[k-1] == '='; k--);
b64_unpadded = strndup(b64_padded, k);
SAFE_FREE(b64_padded);
return b64_unpadded;
}
/**
* @brief Convert a buffer into a colon separated hex string.
* The caller has to free the memory.
@@ -1111,6 +1166,110 @@ char *ssh_get_hexa(const unsigned char *what, size_t len) {
return hexa;
}
/**
* @brief Get a hash as a human-readable hex- or base64-string.
*
* This gets an allocated fingerprint hash. It is a hex strings if the given
* hash is a md5 sum. If it is a SHA sum, it will return an unpadded base64
* strings. Either way, the output is prepended by the hash-type.
*
* @param type Which sort of hash is given.
*
* @param hash What should be converted to a base64 string.
*
* @param len Length of the buffer to convert.
*
* @return Returns the allocated fingerprint hash or NULL on error.
*
* @see ssh_string_free_char()
*/
char *ssh_get_fingerprint_hash(enum ssh_publickey_hash_type type,
unsigned char *hash,
size_t len)
{
const char *prefix = "UNKNOWN";
char *fingerprint = NULL;
char *str = NULL;
size_t str_len;
int rc;
switch (type) {
case SSH_PUBLICKEY_HASH_SHA1:
case SSH_PUBLICKEY_HASH_SHA256:
fingerprint = ssh_get_b64_unpadded(hash, len);
break;
case SSH_PUBLICKEY_HASH_MD5:
fingerprint = ssh_get_hexa(hash, len);
break;
}
if (fingerprint == NULL) {
return NULL;
}
switch (type) {
case SSH_PUBLICKEY_HASH_MD5:
prefix = "MD5";
break;
case SSH_PUBLICKEY_HASH_SHA1:
prefix = "SHA1";
break;
case SSH_PUBLICKEY_HASH_SHA256:
prefix = "SHA256";
break;
}
str_len = strlen(prefix);
if (str_len + 1 + strlen(fingerprint) + 1 < str_len) {
SAFE_FREE(fingerprint);
return NULL;
}
str_len += 1 + strlen(fingerprint) + 1;
str = malloc(str_len);
if (str == NULL) {
SAFE_FREE(fingerprint);
return NULL;
}
rc = snprintf(str, str_len, "%s:%s", prefix, fingerprint);
SAFE_FREE(fingerprint);
if (rc < 0 || rc < (int)(str_len - 1)) {
SAFE_FREE(str);
}
return str;
}
/**
* @brief Print a hash as a human-readable hex- or base64-string.
*
* This function prints hex strings if the given hash is a md5 sum.
* But prints unpadded base64 strings for sha sums.
* Either way, the output is prepended by the hash-type.
*
* @param type Which sort of hash is given.
*
* @param hash What should be converted to a base64 string.
*
* @param len Length of the buffer to convert.
*/
void ssh_print_hash(enum ssh_publickey_hash_type type,
unsigned char *hash,
size_t len)
{
char *fingerprint = NULL;
fingerprint = ssh_get_fingerprint_hash(type,
hash,
len);
if (fingerprint == NULL) {
return;
}
fprintf(stderr, "%s\n", fingerprint);
SAFE_FREE(fingerprint);
}
/**
* @brief Print a buffer as colon separated hex string.
*

View File

@@ -943,8 +943,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
packet_send(session);
}
if(maj_stat == GSS_S_COMPLETE){
session->auth_state = SSH_AUTH_STATE_NONE;
ssh_gssapi_send_mic(session);
session->auth_state = SSH_AUTH_STATE_GSSAPI_MIC_SENT;
}
return SSH_PACKET_USED;
}

View File

@@ -36,6 +36,10 @@
#include "libssh/ssh1.h"
#include "libssh/wrapper.h"
#if defined(HAVE_LIBCRYPTO)
#include "libcrypto-compat.h"
#endif
/* SSHv1 functions */
/* makes a STRING contating 3 strings : ssh-rsa1,e and n */
@@ -46,6 +50,10 @@ static ssh_string make_rsa1_string(ssh_string e, ssh_string n){
ssh_string ret = NULL;
buffer = ssh_buffer_new();
if (buffer == NULL) {
goto error;
}
rsa = ssh_string_from_char("ssh-rsa1");
if (rsa == NULL) {
goto error;
@@ -119,8 +127,8 @@ static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){
n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG);
gcry_sexp_release(sexp);
#elif defined HAVE_LIBCRYPTO
n1=k1->rsa_pub->n;
n2=k2->rsa_pub->n;
RSA_get0_key(k1->rsa_pub, (const BIGNUM **)&n1, NULL, NULL);
RSA_get0_key(k2->rsa_pub, (const BIGNUM **)&n2, NULL, NULL);
#endif
if(bignum_cmp(n1,n2)<0)
res=1;

318
src/libcrypto-compat.c Normal file
View File

@@ -0,0 +1,318 @@
/*
* Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <string.h>
#include <openssl/engine.h>
#include "libcrypto-compat.h"
static void *OPENSSL_zalloc(size_t num)
{
void *ret = OPENSSL_malloc(num);
if (ret != NULL)
memset(ret, 0, num);
return ret;
}
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
/* If the fields n and e in r are NULL, the corresponding input
* parameters MUST be non-NULL for n and e. d may be
* left NULL (in case only the public key is used).
*/
if ((r->n == NULL && n == NULL)
|| (r->e == NULL && e == NULL))
return 0;
if (n != NULL) {
BN_free(r->n);
r->n = n;
}
if (e != NULL) {
BN_free(r->e);
r->e = e;
}
if (d != NULL) {
BN_free(r->d);
r->d = d;
}
return 1;
}
int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
{
/* If the fields p and q in r are NULL, the corresponding input
* parameters MUST be non-NULL.
*/
if ((r->p == NULL && p == NULL)
|| (r->q == NULL && q == NULL))
return 0;
if (p != NULL) {
BN_free(r->p);
r->p = p;
}
if (q != NULL) {
BN_free(r->q);
r->q = q;
}
return 1;
}
int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
{
/* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
* parameters MUST be non-NULL.
*/
if ((r->dmp1 == NULL && dmp1 == NULL)
|| (r->dmq1 == NULL && dmq1 == NULL)
|| (r->iqmp == NULL && iqmp == NULL))
return 0;
if (dmp1 != NULL) {
BN_free(r->dmp1);
r->dmp1 = dmp1;
}
if (dmq1 != NULL) {
BN_free(r->dmq1);
r->dmq1 = dmq1;
}
if (iqmp != NULL) {
BN_free(r->iqmp);
r->iqmp = iqmp;
}
return 1;
}
void RSA_get0_key(const RSA *r,
const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{
if (n != NULL)
*n = r->n;
if (e != NULL)
*e = r->e;
if (d != NULL)
*d = r->d;
}
void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
{
if (p != NULL)
*p = r->p;
if (q != NULL)
*q = r->q;
}
void RSA_get0_crt_params(const RSA *r,
const BIGNUM **dmp1, const BIGNUM **dmq1,
const BIGNUM **iqmp)
{
if (dmp1 != NULL)
*dmp1 = r->dmp1;
if (dmq1 != NULL)
*dmq1 = r->dmq1;
if (iqmp != NULL)
*iqmp = r->iqmp;
}
void DSA_get0_pqg(const DSA *d,
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
{
if (p != NULL)
*p = d->p;
if (q != NULL)
*q = d->q;
if (g != NULL)
*g = d->g;
}
int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
/* If the fields p, q and g in d are NULL, the corresponding input
* parameters MUST be non-NULL.
*/
if ((d->p == NULL && p == NULL)
|| (d->q == NULL && q == NULL)
|| (d->g == NULL && g == NULL))
return 0;
if (p != NULL) {
BN_free(d->p);
d->p = p;
}
if (q != NULL) {
BN_free(d->q);
d->q = q;
}
if (g != NULL) {
BN_free(d->g);
d->g = g;
}
return 1;
}
void DSA_get0_key(const DSA *d,
const BIGNUM **pub_key, const BIGNUM **priv_key)
{
if (pub_key != NULL)
*pub_key = d->pub_key;
if (priv_key != NULL)
*priv_key = d->priv_key;
}
int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{
/* If the field pub_key in d is NULL, the corresponding input
* parameters MUST be non-NULL. The priv_key field may
* be left NULL.
*/
if (d->pub_key == NULL && pub_key == NULL)
return 0;
if (pub_key != NULL) {
BN_free(d->pub_key);
d->pub_key = pub_key;
}
if (priv_key != NULL) {
BN_free(d->priv_key);
d->priv_key = priv_key;
}
return 1;
}
void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{
if (pr != NULL)
*pr = sig->r;
if (ps != NULL)
*ps = sig->s;
}
int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
if (r == NULL || s == NULL)
return 0;
BN_clear_free(sig->r);
BN_clear_free(sig->s);
sig->r = r;
sig->s = s;
return 1;
}
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{
if (pr != NULL)
*pr = sig->r;
if (ps != NULL)
*ps = sig->s;
}
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
if (r == NULL || s == NULL)
return 0;
BN_clear_free(sig->r);
BN_clear_free(sig->s);
sig->r = r;
sig->s = s;
return 1;
}
EVP_MD_CTX *EVP_MD_CTX_new(void)
{
return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
}
static void OPENSSL_clear_free(void *str, size_t num)
{
if (str == NULL)
return;
if (num)
OPENSSL_cleanse(str, num);
OPENSSL_free(str);
}
/* This call frees resources associated with the context */
int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
{
if (ctx == NULL)
return 1;
/*
* Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because
* sometimes only copies of the context are ever finalised.
*/
if (ctx->digest && ctx->digest->cleanup
&& !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
ctx->digest->cleanup(ctx);
if (ctx->digest && ctx->digest->ctx_size && ctx->md_data
&& !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
}
EVP_PKEY_CTX_free(ctx->pctx);
#ifndef OPENSSL_NO_ENGINE
ENGINE_finish(ctx->engine);
#endif
OPENSSL_cleanse(ctx, sizeof(*ctx));
return 1;
}
void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
{
EVP_MD_CTX_reset(ctx);
OPENSSL_free(ctx);
}
HMAC_CTX *HMAC_CTX_new(void)
{
HMAC_CTX *ctx = OPENSSL_zalloc(sizeof(HMAC_CTX));
if (ctx != NULL) {
if (!HMAC_CTX_reset(ctx)) {
HMAC_CTX_free(ctx);
return NULL;
}
}
return ctx;
}
static void hmac_ctx_cleanup(HMAC_CTX *ctx)
{
EVP_MD_CTX_reset(&ctx->i_ctx);
EVP_MD_CTX_reset(&ctx->o_ctx);
EVP_MD_CTX_reset(&ctx->md_ctx);
ctx->md = NULL;
ctx->key_length = 0;
OPENSSL_cleanse(ctx->key, sizeof(ctx->key));
}
void HMAC_CTX_free(HMAC_CTX *ctx)
{
if (ctx != NULL) {
hmac_ctx_cleanup(ctx);
#if OPENSSL_VERSION_NUMBER > 0x10100000L
EVP_MD_CTX_free(&ctx->i_ctx);
EVP_MD_CTX_free(&ctx->o_ctx);
EVP_MD_CTX_free(&ctx->md_ctx);
#endif
OPENSSL_free(ctx);
}
}
int HMAC_CTX_reset(HMAC_CTX *ctx)
{
HMAC_CTX_init(ctx);
return 1;
}

42
src/libcrypto-compat.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef LIBCRYPTO_COMPAT_H
#define LIBCRYPTO_COMPAT_H
#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/ecdsa.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key);
int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
int EVP_MD_CTX_reset(EVP_MD_CTX *ctx);
EVP_MD_CTX *EVP_MD_CTX_new(void);
void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
HMAC_CTX *HMAC_CTX_new(void);
int HMAC_CTX_reset(HMAC_CTX *ctx);
void HMAC_CTX_free(HMAC_CTX *ctx);
#endif /* OPENSSL_VERSION_NUMBER */
#endif /* LIBCRYPTO_COMPAT_H */

View File

@@ -43,6 +43,8 @@
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
#include <openssl/rand.h>
#include <openssl/modes.h>
#include "libcrypto-compat.h"
#ifdef HAVE_OPENSSL_AES_H
#define HAS_AES
@@ -133,18 +135,19 @@ static const EVP_MD *nid_to_evpmd(int nid)
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen)
{
const EVP_MD *evp_md = nid_to_evpmd(nid);
EVP_MD_CTX md;
EVP_MD_CTX *md = EVP_MD_CTX_new();
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, digest, len);
EVP_DigestFinal(&md, hash, hlen);
EVP_DigestInit(md, evp_md);
EVP_DigestUpdate(md, digest, len);
EVP_DigestFinal(md, hash, hlen);
EVP_MD_CTX_free(md);
}
EVPCTX evp_init(int nid)
{
const EVP_MD *evp_md = nid_to_evpmd(nid);
EVPCTX ctx = malloc(sizeof(EVP_MD_CTX));
EVPCTX ctx = EVP_MD_CTX_new();
if (ctx == NULL) {
return NULL;
}
@@ -322,32 +325,33 @@ void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) {
HMACCTX hmac_init(const void *key, int len, enum ssh_hmac_e type) {
HMACCTX ctx = NULL;
ctx = malloc(sizeof(*ctx));
ctx = HMAC_CTX_new();
if (ctx == NULL) {
return NULL;
}
#ifndef OLD_CRYPTO
HMAC_CTX_init(ctx); // openssl 0.9.7 requires it.
HMAC_CTX_reset(ctx); // openssl 0.9.7 requires it.
#endif
switch(type) {
case SSH_HMAC_SHA1:
HMAC_Init(ctx, key, len, EVP_sha1());
HMAC_Init_ex(ctx, key, len, EVP_sha1(), NULL);
break;
case SSH_HMAC_SHA256:
HMAC_Init(ctx, key, len, EVP_sha256());
HMAC_Init_ex(ctx, key, len, EVP_sha256(), NULL);
break;
case SSH_HMAC_SHA384:
HMAC_Init(ctx, key, len, EVP_sha384());
HMAC_Init_ex(ctx, key, len, EVP_sha384(), NULL);
break;
case SSH_HMAC_SHA512:
HMAC_Init(ctx, key, len, EVP_sha512());
HMAC_Init_ex(ctx, key, len, EVP_sha512(), NULL);
break;
case SSH_HMAC_MD5:
HMAC_Init(ctx, key, len, EVP_md5());
HMAC_Init_ex(ctx, key, len, EVP_md5(), NULL);
break;
default:
HMAC_CTX_free(ctx);
SAFE_FREE(ctx);
ctx = NULL;
}
@@ -363,7 +367,8 @@ void hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, unsigned int *len) {
HMAC_Final(ctx,hashmacbuf,len);
#ifndef OLD_CRYPTO
HMAC_CTX_cleanup(ctx);
HMAC_CTX_free(ctx);
ctx = NULL;
#else
HMAC_cleanup(ctx);
#endif
@@ -455,7 +460,12 @@ static void aes_ctr128_encrypt(struct ssh_cipher_struct *cipher, void *in, void
* Same for num, which is being used to store the current offset in blocksize in CTR
* function.
*/
#ifdef HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT
CRYPTO_ctr128_encrypt(in, out, len, cipher->key, cipher->IV, tmp_buffer,
&num, (block128_f)AES_encrypt);
# else
AES_ctr128_encrypt(in, out, len, cipher->key, cipher->IV, tmp_buffer, &num);
#endif /* HAVE_OPENSSL_CRYPTO_CTR128_ENCRYPT */
}
#endif /* BROKEN_AES_CTR */
#endif /* HAS_AES */

View File

@@ -923,6 +923,15 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
goto error;
}
} else if (session->kbdint->nanswers > 0) {
uint32_t n;
for (n = 0; n < session->kbdint->nanswers; n++) {
BURN_STRING(session->kbdint->answers[n]);
SAFE_FREE(session->kbdint->answers[n]);
}
SAFE_FREE(session->kbdint->answers);
session->kbdint->nanswers = 0;
}
SSH_LOG(SSH_LOG_PACKET,"kbdint: %d answers",nanswers);
@@ -942,7 +951,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
" mismatch: p=%u a=%u", session->kbdint->nprompts, nanswers);
}
session->kbdint->nanswers = nanswers;
session->kbdint->answers = malloc(nanswers * sizeof(char *));
session->kbdint->answers = calloc(1, nanswers * sizeof(char *));
if (session->kbdint->answers == NULL) {
session->kbdint->nanswers = 0;
ssh_set_error_oom(session);
@@ -951,7 +961,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){
goto error;
}
memset(session->kbdint->answers, 0, nanswers * sizeof(char *));
for (i = 0; i < nanswers; i++) {
tmp = buffer_get_ssh_string(packet);
@@ -1101,6 +1110,7 @@ int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_c
chan->remote_maxpacket = msg->channel_request_open.packet_size;
chan->remote_window = msg->channel_request_open.window;
chan->state = SSH_CHANNEL_STATE_OPEN;
chan->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
rc = ssh_buffer_pack(session->out_buffer,
"bdddd",
@@ -1355,6 +1365,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
msg->global_request.bind_port);
session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
} else {
SAFE_FREE(request);
ssh_message_queue(session, msg);
return rc;
}
@@ -1375,6 +1386,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) {
session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata);
} else {
SAFE_FREE(request);
ssh_message_queue(session, msg);
return rc;
}

View File

@@ -846,7 +846,7 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
openssh = strstr(banner, "OpenSSH");
if (openssh != NULL) {
int major, minor;
unsigned int major, minor;
/*
* The banner is typical:
@@ -854,8 +854,22 @@ int ssh_analyze_banner(ssh_session session, int server, int *ssh1, int *ssh2) {
* 012345678901234567890
*/
if (strlen(openssh) > 9) {
major = strtol(openssh + 8, (char **) NULL, 10);
major = strtoul(openssh + 8, (char **) NULL, 10);
if (major < 1 || major > 100) {
ssh_set_error(session,
SSH_FATAL,
"Invalid major version number: %s",
banner);
return -1;
}
minor = strtol(openssh + 10, (char **) NULL, 10);
if (minor > 100) {
ssh_set_error(session,
SSH_FATAL,
"Invalid minor version number: %s",
banner);
return -1;
}
session->openssh = SSH_VERSION_INT(major, minor, 0);
SSH_LOG(SSH_LOG_RARE,
"We are talking to an OpenSSH client version: %d.%d (%x)",

View File

@@ -127,6 +127,775 @@ static ssh_packet_callback default_packet_handlers[]= {
ssh_packet_channel_failure, // SSH2_MSG_CHANNEL_FAILURE 100
};
/** @internal
* @brief check if the received packet is allowed for the current session state
* @param session current ssh_session
* @returns SSH_PACKET_ALLOWED if the packet is allowed; SSH_PACKET_DENIED
* if the packet arrived in wrong state; SSH_PACKET_UNKNOWN if the packet type
* is unknown
*/
static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session session)
{
enum ssh_packet_filter_result_e rc;
#ifdef DEBUG_PACKET
SSH_LOG(SSH_LOG_PACKET, "Filtering packet type %d",
session->in_packet.type);
#endif
switch(session->in_packet.type) {
case SSH2_MSG_DISCONNECT: // 1
/*
* States required:
* - None
*
* Transitions:
* - session->socket->state = SSH_SOCKET_CLOSED
* - session->session_state = SSH_SESSION_STATE_ERROR
* */
/* Always allowed */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_IGNORE: // 2
/*
* States required:
* - None
*
* Transitions:
* - None
* */
/* Always allowed */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_UNIMPLEMENTED: // 3
/*
* States required:
* - None
*
* Transitions:
* - None
* */
/* Always allowed */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_DEBUG: // 4
/*
* States required:
* - None
*
* Transitions:
* - None
* */
/* Always allowed */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_SERVICE_REQUEST: // 5
/* Server only */
/*
* States required:
* - session->session_state == SSH_SESSION_STATE_AUTHENTICATING
* or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
* - session->dh_handshake_state == DH_STATE_FINISHED
*
* Transitions:
* - None
* */
/* If this is a client, reject the message */
if (session->client) {
rc = SSH_PACKET_DENIED;
break;
}
if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
(session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
{
rc = SSH_PACKET_DENIED;
break;
}
if (session->dh_handshake_state != DH_STATE_FINISHED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_SERVICE_ACCEPT: // 6
/*
* States required:
* - session->session_state == SSH_SESSION_STATE_AUTHENTICATING
* or session->session_state == SSH_SESSION_STATE_AUTHENTICATED
* - session->dh_handshake_state == DH_STATE_FINISHED
* - session->auth_service_state == SSH_AUTH_SERVICE_SENT
*
* Transitions:
* - auth_service_state = SSH_AUTH_SERVICE_ACCEPTED
* */
if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) &&
(session->session_state != SSH_SESSION_STATE_AUTHENTICATED))
{
rc = SSH_PACKET_DENIED;
break;
}
if (session->dh_handshake_state != DH_STATE_FINISHED) {
rc = SSH_PACKET_DENIED;
break;
}
/* TODO check if only auth service can be requested */
if (session->auth_service_state != SSH_AUTH_SERVICE_SENT) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_KEXINIT: // 20
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
* or session_state == SSH_SESSION_STATE_INITIAL_KEX
* - dh_handshake_state == DH_STATE_INIT
* or dh_handshake_state == DH_STATE_FINISHED (re-exchange)
*
* Transitions:
* - session->dh_handshake_state = DH_STATE_INIT
* - session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED
*
* On server:
* - session->session_state = SSH_SESSION_STATE_DH
* */
if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATED) &&
(session->session_state != SSH_SESSION_STATE_INITIAL_KEX))
{
rc = SSH_PACKET_DENIED;
break;
}
if ((session->dh_handshake_state != DH_STATE_INIT) &&
(session->dh_handshake_state != DH_STATE_FINISHED))
{
rc = SSH_PACKET_DENIED;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_NEWKEYS: // 21
/*
* States required:
* - session_state == SSH_SESSION_STATE_DH
* - dh_handshake_state == DH_STATE_NEWKEYS_SENT
*
* Transitions:
* - session->dh_handshake_state = DH_STATE_FINISHED
* - session->session_state = SSH_SESSION_STATE_AUTHENTICATING
* if session->flags & SSH_SESSION_FLAG_AUTHENTICATED
* - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
* */
/* If DH has not been started, reject message */
if (session->session_state != SSH_SESSION_STATE_DH) {
rc = SSH_PACKET_DENIED;
break;
}
/* Only allowed if dh_handshake_state is in NEWKEYS_SENT state */
if (session->dh_handshake_state != DH_STATE_NEWKEYS_SENT) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_KEXDH_INIT: // 30
// SSH2_MSG_KEX_ECDH_INIT: // 30
// SSH2_MSG_ECMQV_INIT: // 30
// SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: // 30
/* Server only */
/*
* States required:
* - session_state == SSH_SESSION_STATE_DH
* - dh_handshake_state == DH_STATE_INIT
*
* Transitions:
* - session->dh_handshake_state = DH_STATE_INIT_SENT
* then calls dh_handshake_server which triggers:
* - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
* */
if (session->session_state != SSH_SESSION_STATE_DH) {
rc = SSH_PACKET_DENIED;
break;
}
/* Only allowed if dh_handshake_state is in initial state */
if (session->dh_handshake_state != DH_STATE_INIT) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_KEXDH_REPLY: // 31
// SSH2_MSG_KEX_ECDH_REPLY: // 31
// SSH2_MSG_ECMQV_REPLY: // 31
// SSH2_MSG_KEX_DH_GEX_GROUP: // 31
/*
* States required:
* - session_state == SSH_SESSION_STATE_DH
* - dh_handshake_state == DH_STATE_INIT_SENT
*
* Transitions:
* - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
* */
if (session->session_state != SSH_SESSION_STATE_DH) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->dh_handshake_state != DH_STATE_INIT_SENT) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_KEX_DH_GEX_INIT: // 32
/* TODO Not filtered */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_KEX_DH_GEX_REPLY: // 33
/* TODO Not filtered */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_KEX_DH_GEX_REQUEST: // 34
/* TODO Not filtered */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_REQUEST: // 50
/* Server only */
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
* - dh_hanshake_state == DH_STATE_FINISHED
*
* Transitions:
* - if authentication was successful:
* - session_state = SSH_SESSION_STATE_AUTHENTICATED
* */
/* If this is a client, reject the message */
if (session->client) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->dh_handshake_state != DH_STATE_FINISHED) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_FAILURE: // 51
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
* - dh_hanshake_state == DH_STATE_FINISHED
* - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
* or session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
* or session->auth_state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT
* or session->auth_state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT
* or session->auth_state == SSH_AUTH_STATE_GSSAPI_MIC_SENT
*
* Transitions:
* - if unpacking failed:
* - session->auth_state = SSH_AUTH_ERROR
* - if failure was partial:
* - session->auth_state = SSH_AUTH_PARTIAL
* - else:
* - session->auth_state = SSH_AUTH_STATE_FAILED
* */
/* If this is a server, reject the message */
if (session->server) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->dh_handshake_state != DH_STATE_FINISHED) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_SUCCESS: // 52
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
* - dh_hanshake_state == DH_STATE_FINISHED
* - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
* or session->auth_state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT
* or session->auth_state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT
* or session->auth_state == SSH_AUTH_STATE_GSSAPI_MIC_SENT
* or session->auth_state == SSH_AUTH_STATE_AUTH_NONE_SENT
*
* Transitions:
* - session->auth_state = SSH_AUTH_STATE_SUCCESS
* - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
* - session->flags |= SSH_SESSION_FLAG_AUTHENTICATED
* - sessions->auth.current_method = SSH_AUTH_METHOD_UNKNOWN
* */
/* If this is a server, reject the message */
if (session->server) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->dh_handshake_state != DH_STATE_FINISHED) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
rc = SSH_PACKET_DENIED;
break;
}
if ((session->auth_state != SSH_AUTH_STATE_KBDINT_SENT) &&
(session->auth_state != SSH_AUTH_STATE_PUBKEY_AUTH_SENT) &&
(session->auth_state != SSH_AUTH_STATE_PASSWORD_AUTH_SENT) &&
(session->auth_state != SSH_AUTH_STATE_GSSAPI_MIC_SENT) &&
(session->auth_state != SSH_AUTH_STATE_AUTH_NONE_SENT))
{
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_BANNER: // 53
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
*
* Transitions:
* - None
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_PK_OK: // 60
// SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // 60
// SSH2_MSG_USERAUTH_INFO_REQUEST: // 60
// SSH2_MSG_USERAUTH_GSSAPI_RESPONSE: // 60
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
* - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
* or
* session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT
* or
* session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
*
* Transitions:
* Depending on the current state, the message is treated
* differently:
* - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT
* - session->auth_state = SSH_AUTH_STATE_INFO
* - session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT
* - session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN
* - session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT
* - session->auth_state = SSH_AUTH_STATE_PK_OK
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
rc = SSH_PACKET_DENIED;
break;
}
if ((session->auth_state != SSH_AUTH_STATE_KBDINT_SENT) &&
(session->auth_state != SSH_AUTH_STATE_PUBKEY_OFFER_SENT) &&
(session->auth_state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT))
{
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_INFO_RESPONSE: // 61
// SSH2_MSG_USERAUTH_GSSAPI_TOKEN: // 61
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
* - session_state->auth_state == SSH_SESSION_STATE_GSSAPI_TOKEN
* or
* session_state->auth_state == SSH_SESSION_STATE_INFO
*
* Transitions:
* - None
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
rc = SSH_PACKET_DENIED;
break;
}
if ((session->auth_state != SSH_AUTH_STATE_INFO) &&
(session->auth_state != SSH_AUTH_STATE_GSSAPI_TOKEN))
{
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE: // 63
/* TODO Not filtered */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_GSSAPI_ERROR: // 64
/* TODO Not filtered */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_GSSAPI_ERRTOK: // 65
/* TODO Not filtered */
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_USERAUTH_GSSAPI_MIC: // 66
/* Server only */
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATING
* - session->gssapi->state == SSH_GSSAPI_STATE_RCV_MIC
*
* Transitions:
* Depending on the result of the verification, the states are
* changed:
* - SSH_AUTH_SUCCESS:
* - session->session_state = SSH_SESSION_STATE_AUTHENTICATED
* - session->flags != SSH_SESSION_FLAG_AUTHENTICATED
* - SSH_AUTH_PARTIAL:
* - None
* - any other case:
* - None
* */
/* If this is a client, reject the message */
if (session->client) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->dh_handshake_state != DH_STATE_FINISHED) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_GLOBAL_REQUEST: // 80
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - None
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_REQUEST_SUCCESS: // 81
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
* - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
*
* Transitions:
* - session->global_req_state == SSH_CHANNEL_REQ_STATE_ACCEPTED
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_REQUEST_FAILURE: // 82
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
* - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING
*
* Transitions:
* - session->global_req_state == SSH_CHANNEL_REQ_STATE_DENIED
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_OPEN: // 90
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - None
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: // 91
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - channel->state = SSH_CHANNEL_STATE_OPEN
* - channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_OPEN_FAILURE: // 92
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - channel->state = SSH_CHANNEL_STATE_OPEN_DENIED
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_WINDOW_ADJUST: // 93
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - None
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_DATA: // 94
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - None
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_EXTENDED_DATA: // 95
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - None
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_EOF: // 96
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - None
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_CLOSE: // 97
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - channel->state = SSH_CHANNEL_STATE_CLOSED
* - channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_REQUEST: // 98
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
*
* Transitions:
* - Depends on the request
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_SUCCESS: // 99
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
* - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING
*
* Transitions:
* - channel->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
case SSH2_MSG_CHANNEL_FAILURE: // 100
/*
* States required:
* - session_state == SSH_SESSION_STATE_AUTHENTICATED
* - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING
*
* Transitions:
* - channel->request_state = SSH_CHANNEL_REQ_STATE_DENIED
* */
if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
rc = SSH_PACKET_DENIED;
break;
}
rc = SSH_PACKET_ALLOWED;
break;
default:
/* Unknown message, do not filter */
rc = SSH_PACKET_UNKNOWN;
goto end;
}
end:
#ifdef DEBUG_PACKET
if (rc == SSH_PACKET_DENIED) {
SSH_LOG(SSH_LOG_PACKET, "REJECTED packet type %d: ",
session->in_packet.type);
}
if (rc == SSH_PACKET_UNKNOWN) {
SSH_LOG(SSH_LOG_PACKET, "UNKNOWN packet type %d",
session->in_packet.type);
}
#endif
return rc;
}
/* in nonblocking mode, socket_read will read as much as it can, and return */
/* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */
/* in blocking mode, it will read at least len bytes and will block until it's ok. */
@@ -153,6 +922,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
uint32_t len, compsize, payloadsize;
uint8_t padding;
size_t processed = 0; /* number of byte processed from the callback */
enum ssh_packet_filter_result_e filter_result;
if(session->current_crypto != NULL) {
current_macsize = hmac_digest_len(session->current_crypto->in_hmac);
@@ -328,8 +1098,21 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
"packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
session->in_packet.type, len, padding, compsize, payloadsize);
/* Execute callbacks */
ssh_packet_process(session, session->in_packet.type);
/* Check if the packet is expected */
filter_result = ssh_packet_incoming_filter(session);
switch(filter_result) {
case SSH_PACKET_ALLOWED:
/* Execute callbacks */
ssh_packet_process(session, session->in_packet.type);
break;
case SSH_PACKET_DENIED:
goto error;
case SSH_PACKET_UNKNOWN:
ssh_packet_send_unimplemented(session, session->recv_seq - 1);
break;
}
session->packet_state = PACKET_STATE_INIT;
if (processed < receivedlen) {
/* Handle a potential packet left in socket buffer */

View File

@@ -999,7 +999,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
key_buf[size] = '\0';
q = p = key_buf;
while (!isspace((int)*p)) p++;
while (*p != '\0' && !isspace((int)*p)) p++;
*p = '\0';
type = ssh_key_type_from_name(q);
@@ -1008,7 +1008,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
return SSH_ERROR;
}
q = ++p;
while (!isspace((int)*p)) p++;
while (*p != '\0' && !isspace((int)*p)) p++;
*p = '\0';
rc = ssh_pki_import_pubkey_base64(q, type, pkey);

View File

@@ -31,6 +31,7 @@
#include <openssl/dsa.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include "libcrypto-compat.h"
#ifdef HAVE_OPENSSL_EC_H
#include <openssl/ec.h>
@@ -230,7 +231,10 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
}
switch (key->type) {
case SSH_KEYTYPE_DSS:
case SSH_KEYTYPE_DSS: {
const BIGNUM *p = NULL, *q = NULL, *g = NULL,
*pub_key = NULL, *priv_key = NULL;
BIGNUM *np, *nq, *ng, *npub_key, *npriv_key;
new->dsa = DSA_new();
if (new->dsa == NULL) {
goto fail;
@@ -243,36 +247,54 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
* pub_key = public key y = g^x
* priv_key = private key x
*/
new->dsa->p = BN_dup(key->dsa->p);
if (new->dsa->p == NULL) {
DSA_get0_pqg(key->dsa, &p, &q, &g);
np = BN_dup(p);
nq = BN_dup(q);
ng = BN_dup(g);
if (np == NULL || nq == NULL || ng == NULL) {
BN_free(np);
BN_free(nq);
BN_free(ng);
goto fail;
}
new->dsa->q = BN_dup(key->dsa->q);
if (new->dsa->q == NULL) {
rc = DSA_set0_pqg(new->dsa, np, nq, ng);
if (rc == 0) {
BN_free(np);
BN_free(nq);
BN_free(ng);
goto fail;
}
new->dsa->g = BN_dup(key->dsa->g);
if (new->dsa->g == NULL) {
DSA_get0_key(key->dsa, &pub_key, &priv_key);
npub_key = BN_dup(pub_key);
if (npub_key == NULL) {
goto fail;
}
new->dsa->pub_key = BN_dup(key->dsa->pub_key);
if (new->dsa->pub_key == NULL) {
rc = DSA_set0_key(new->dsa, npub_key, NULL);
if (rc == 0) {
goto fail;
}
if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
new->dsa->priv_key = BN_dup(key->dsa->priv_key);
if (new->dsa->priv_key == NULL) {
npriv_key = BN_dup(priv_key);
if (npriv_key == NULL) {
goto fail;
}
rc = DSA_set0_key(new->dsa, NULL, npriv_key);
if (rc == 0) {
goto fail;
}
}
break;
}
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_RSA1: {
const BIGNUM *n = NULL, *e = NULL, *d = NULL;
BIGNUM *nn, *ne, *nd;
new->rsa = RSA_new();
if (new->rsa == NULL) {
goto fail;
@@ -288,62 +310,82 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
* dmq1 = d mod (q-1)
* iqmp = q^-1 mod p
*/
new->rsa->n = BN_dup(key->rsa->n);
if (new->rsa->n == NULL) {
RSA_get0_key(key->rsa, &n, &e, &d);
nn = BN_dup(n);
ne = BN_dup(e);
if (nn == NULL || ne == NULL) {
BN_free(nn);
BN_free(ne);
goto fail;
}
new->rsa->e = BN_dup(key->rsa->e);
if (new->rsa->e == NULL) {
rc = RSA_set0_key(new->rsa, nn, ne, NULL);
if (rc == 0) {
BN_free(nn);
BN_free(ne);
goto fail;
}
if (!demote && (key->flags & SSH_KEY_FLAG_PRIVATE)) {
new->rsa->d = BN_dup(key->rsa->d);
if (new->rsa->d == NULL) {
const BIGNUM *p = NULL, *q = NULL, *dmp1 = NULL,
*dmq1 = NULL, *iqmp = NULL;
BIGNUM *np, *nq, *ndmp1, *ndmq1, *niqmp;
nd = BN_dup(d);
if (nd == NULL) {
goto fail;
}
rc = RSA_set0_key(new->rsa, NULL, NULL, nd);
if (rc == 0) {
goto fail;
}
/* p, q, dmp1, dmq1 and iqmp may be NULL in private keys, but the
* RSA operations are much faster when these values are available.
*/
if (key->rsa->p != NULL) {
new->rsa->p = BN_dup(key->rsa->p);
if (new->rsa->p == NULL) {
RSA_get0_factors(key->rsa, &p, &q);
if (p != NULL && q != NULL) { /* need to set both of them */
np = BN_dup(p);
nq = BN_dup(q);
if (np == NULL || nq == NULL) {
BN_free(np);
BN_free(nq);
goto fail;
}
rc = RSA_set0_factors(new->rsa, np, nq);
if (rc == 0) {
BN_free(np);
BN_free(nq);
goto fail;
}
}
if (key->rsa->q != NULL) {
new->rsa->q = BN_dup(key->rsa->q);
if (new->rsa->q == NULL) {
RSA_get0_crt_params(key->rsa, &dmp1, &dmq1, &iqmp);
if (dmp1 != NULL || dmq1 != NULL || iqmp != NULL) {
ndmp1 = BN_dup(dmp1);
ndmq1 = BN_dup(dmq1);
niqmp = BN_dup(iqmp);
if (ndmp1 == NULL || ndmq1 == NULL || niqmp == NULL) {
BN_free(ndmp1);
BN_free(ndmq1);
BN_free(niqmp);
goto fail;
}
}
if (key->rsa->dmp1 != NULL) {
new->rsa->dmp1 = BN_dup(key->rsa->dmp1);
if (new->rsa->dmp1 == NULL) {
goto fail;
}
}
if (key->rsa->dmq1 != NULL) {
new->rsa->dmq1 = BN_dup(key->rsa->dmq1);
if (new->rsa->dmq1 == NULL) {
goto fail;
}
}
if (key->rsa->iqmp != NULL) {
new->rsa->iqmp = BN_dup(key->rsa->iqmp);
if (new->rsa->iqmp == NULL) {
rc = RSA_set0_crt_params(new->rsa, ndmp1, ndmq1, niqmp);
if (rc == 0) {
BN_free(ndmp1);
BN_free(ndmq1);
BN_free(niqmp);
goto fail;
}
}
}
break;
}
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_OPENSSL_ECC
new->ecdsa_nid = key->ecdsa_nid;
@@ -466,51 +508,64 @@ int pki_key_compare(const ssh_key k1,
enum ssh_keycmp_e what)
{
switch (k1->type) {
case SSH_KEYTYPE_DSS:
case SSH_KEYTYPE_DSS: {
const BIGNUM *p1, *p2, *q1, *q2, *g1, *g2,
*pub_key1, *pub_key2, *priv_key1, *priv_key2;
if (DSA_size(k1->dsa) != DSA_size(k2->dsa)) {
return 1;
}
if (bignum_cmp(k1->dsa->p, k2->dsa->p) != 0) {
DSA_get0_pqg(k1->dsa, &p1, &q1, &g1);
DSA_get0_pqg(k2->dsa, &p2, &q2, &g2);
if (bignum_cmp(p1, p2) != 0) {
return 1;
}
if (bignum_cmp(k1->dsa->q, k2->dsa->q) != 0) {
if (bignum_cmp(q1, q2) != 0) {
return 1;
}
if (bignum_cmp(k1->dsa->g, k2->dsa->g) != 0) {
if (bignum_cmp(g1, g2) != 0) {
return 1;
}
if (bignum_cmp(k1->dsa->pub_key, k2->dsa->pub_key) != 0) {
DSA_get0_key(k1->dsa, &pub_key1, &priv_key1);
DSA_get0_key(k2->dsa, &pub_key2, &priv_key2);
if (bignum_cmp(pub_key1, pub_key2) != 0) {
return 1;
}
if (what == SSH_KEY_CMP_PRIVATE) {
if (bignum_cmp(k1->dsa->priv_key, k2->dsa->priv_key) != 0) {
if (bignum_cmp(priv_key1, priv_key2) != 0) {
return 1;
}
}
break;
}
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_RSA1: {
const BIGNUM *e1, *e2, *n1, *n2, *p1, *p2, *q1, *q2;
if (RSA_size(k1->rsa) != RSA_size(k2->rsa)) {
return 1;
}
if (bignum_cmp(k1->rsa->e, k2->rsa->e) != 0) {
RSA_get0_key(k1->rsa, &n1, &e1, NULL);
RSA_get0_key(k2->rsa, &n2, &e2, NULL);
if (bignum_cmp(e1, e2) != 0) {
return 1;
}
if (bignum_cmp(k1->rsa->n, k2->rsa->n) != 0) {
if (bignum_cmp(n1, n2) != 0) {
return 1;
}
if (what == SSH_KEY_CMP_PRIVATE) {
if (bignum_cmp(k1->rsa->p, k2->rsa->p) != 0) {
RSA_get0_factors(k1->rsa, &p1, &q1);
RSA_get0_factors(k2->rsa, &p2, &q2);
if (bignum_cmp(p1, p2) != 0) {
return 1;
}
if (bignum_cmp(k1->rsa->q, k2->rsa->q) != 0) {
if (bignum_cmp(q1, q2) != 0) {
return 1;
}
}
break;
}
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_OPENSSL_ECC
{
@@ -819,19 +874,32 @@ int pki_pubkey_build_dss(ssh_key key,
ssh_string q,
ssh_string g,
ssh_string pubkey) {
int rc;
BIGNUM *bp, *bq, *bg, *bpub_key;
key->dsa = DSA_new();
if (key->dsa == NULL) {
return SSH_ERROR;
}
key->dsa->p = make_string_bn(p);
key->dsa->q = make_string_bn(q);
key->dsa->g = make_string_bn(g);
key->dsa->pub_key = make_string_bn(pubkey);
if (key->dsa->p == NULL ||
key->dsa->q == NULL ||
key->dsa->g == NULL ||
key->dsa->pub_key == NULL) {
bp = make_string_bn(p);
bq = make_string_bn(q);
bg = make_string_bn(g);
bpub_key = make_string_bn(pubkey);
if (bp == NULL || bq == NULL ||
bg == NULL || bpub_key == NULL) {
DSA_free(key->dsa);
return SSH_ERROR;
}
rc = DSA_set0_pqg(key->dsa, bp, bq, bg);
if (rc == 0) {
DSA_free(key->dsa);
return SSH_ERROR;
}
rc = DSA_set0_key(key->dsa, bpub_key, NULL);
if (rc == 0) {
DSA_free(key->dsa);
return SSH_ERROR;
}
@@ -842,15 +910,23 @@ int pki_pubkey_build_dss(ssh_key key,
int pki_pubkey_build_rsa(ssh_key key,
ssh_string e,
ssh_string n) {
int rc;
BIGNUM *be, *bn;
key->rsa = RSA_new();
if (key->rsa == NULL) {
return SSH_ERROR;
}
key->rsa->e = make_string_bn(e);
key->rsa->n = make_string_bn(n);
if (key->rsa->e == NULL ||
key->rsa->n == NULL) {
be = make_string_bn(e);
bn = make_string_bn(n);
if (be == NULL || bn == NULL) {
RSA_free(key->rsa);
return SSH_ERROR;
}
rc = RSA_set0_key(key->rsa, bn, be, NULL);
if (rc == 0) {
RSA_free(key->rsa);
return SSH_ERROR;
}
@@ -889,23 +965,26 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
}
switch (key->type) {
case SSH_KEYTYPE_DSS:
p = make_bignum_string(key->dsa->p);
case SSH_KEYTYPE_DSS: {
const BIGNUM *bp, *bq, *bg, *bpub_key;
DSA_get0_pqg(key->dsa, &bp, &bq, &bg);
p = make_bignum_string((BIGNUM *)bp);
if (p == NULL) {
goto fail;
}
q = make_bignum_string(key->dsa->q);
q = make_bignum_string((BIGNUM *)bq);
if (q == NULL) {
goto fail;
}
g = make_bignum_string(key->dsa->g);
g = make_bignum_string((BIGNUM *)bg);
if (g == NULL) {
goto fail;
}
n = make_bignum_string(key->dsa->pub_key);
DSA_get0_key(key->dsa, &bpub_key, NULL);
n = make_bignum_string((BIGNUM *)bpub_key);
if (n == NULL) {
goto fail;
}
@@ -937,14 +1016,17 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
n = NULL;
break;
}
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
e = make_bignum_string(key->rsa->e);
case SSH_KEYTYPE_RSA1: {
const BIGNUM *be, *bn;
RSA_get0_key(key->rsa, &bn, &be, NULL);
e = make_bignum_string((BIGNUM *)be);
if (e == NULL) {
goto fail;
}
n = make_bignum_string(key->rsa->n);
n = make_bignum_string((BIGNUM *)bn);
if (n == NULL) {
goto fail;
}
@@ -964,6 +1046,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
n = NULL;
break;
}
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_OPENSSL_ECC
rc = ssh_buffer_reinit(buffer);
@@ -1065,13 +1148,15 @@ int pki_export_pubkey_rsa1(const ssh_key key,
char *e;
char *n;
int rsa_size = RSA_size(key->rsa);
const BIGNUM *be, *bn;
e = bignum_bn2dec(key->rsa->e);
RSA_get0_key(key->rsa, &bn, &be, NULL);
e = bignum_bn2dec(be);
if (e == NULL) {
return SSH_ERROR;
}
n = bignum_bn2dec(key->rsa->n);
n = bignum_bn2dec(bn);
if (n == NULL) {
OPENSSL_free(e);
return SSH_ERROR;
@@ -1136,6 +1221,7 @@ static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
{
char buffer[40] = { 0 };
ssh_string sig_blob = NULL;
const BIGNUM *pr, *ps;
ssh_string r;
int r_len, r_offset_in, r_offset_out;
@@ -1143,12 +1229,13 @@ static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
ssh_string s;
int s_len, s_offset_in, s_offset_out;
r = make_bignum_string(sig->dsa_sig->r);
DSA_SIG_get0(sig->dsa_sig, &pr, &ps);
r = make_bignum_string((BIGNUM *)pr);
if (r == NULL) {
return NULL;
}
s = make_bignum_string(sig->dsa_sig->s);
s = make_bignum_string((BIGNUM *)ps);
if (s == NULL) {
ssh_string_free(r);
return NULL;
@@ -1201,13 +1288,15 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
ssh_string s;
ssh_buffer b;
int rc;
const BIGNUM *pr, *ps;
b = ssh_buffer_new();
if (b == NULL) {
return NULL;
}
r = make_bignum_string(sig->ecdsa_sig->r);
ECDSA_SIG_get0(sig->ecdsa_sig, &pr, &ps);
r = make_bignum_string((BIGNUM *)pr);
if (r == NULL) {
ssh_buffer_free(b);
return NULL;
@@ -1219,7 +1308,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
return NULL;
}
s = make_bignum_string(sig->ecdsa_sig->s);
s = make_bignum_string((BIGNUM *)ps);
if (s == NULL) {
ssh_buffer_free(b);
return NULL;
@@ -1324,6 +1413,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
ssh_string s;
size_t len;
int rc;
BIGNUM *pr = NULL, *ps = NULL;
sig = ssh_signature_new();
if (sig == NULL) {
@@ -1363,9 +1453,9 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
ssh_string_fill(r, ssh_string_data(sig_blob), 20);
sig->dsa_sig->r = make_string_bn(r);
pr = make_string_bn(r);
ssh_string_free(r);
if (sig->dsa_sig->r == NULL) {
if (pr == NULL) {
ssh_signature_free(sig);
return NULL;
}
@@ -1377,9 +1467,15 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
ssh_string_fill(s, (char *)ssh_string_data(sig_blob) + 20, 20);
sig->dsa_sig->s = make_string_bn(s);
ps = make_string_bn(s);
ssh_string_free(s);
if (sig->dsa_sig->s == NULL) {
if (ps == NULL) {
ssh_signature_free(sig);
return NULL;
}
rc = DSA_SIG_set0(sig->dsa_sig, pr, ps);
if (rc == 0) {
ssh_signature_free(sig);
return NULL;
}
@@ -1427,10 +1523,10 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
#endif
make_string_bn_inplace(r, sig->ecdsa_sig->r);
pr = make_string_bn(r);
ssh_string_burn(r);
ssh_string_free(r);
if (sig->ecdsa_sig->r == NULL) {
if (pr == NULL) {
ssh_buffer_free(b);
ssh_signature_free(sig);
return NULL;
@@ -1448,10 +1544,16 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
#endif
make_string_bn_inplace(s, sig->ecdsa_sig->s);
ps = make_string_bn(s);
ssh_string_burn(s);
ssh_string_free(s);
if (sig->ecdsa_sig->s == NULL) {
if (ps == NULL) {
ssh_signature_free(sig);
return NULL;
}
rc = ECDSA_SIG_set0(sig->ecdsa_sig, pr, ps);
if (rc == 0) {
ssh_signature_free(sig);
return NULL;
}
@@ -1578,8 +1680,12 @@ ssh_signature pki_do_sign(const ssh_key privkey,
}
#ifdef DEBUG_CRYPTO
ssh_print_bignum("r", sig->dsa_sig->r);
ssh_print_bignum("s", sig->dsa_sig->s);
{
const BIGNUM *pr, *ps;
DSA_SIG_get0(sig->dsa_sig, &pr, &ps);
ssh_print_bignum("r", (BIGNUM *) pr);
ssh_print_bignum("s", (BIGNUM *) ps);
}
#endif
break;
@@ -1601,8 +1707,12 @@ ssh_signature pki_do_sign(const ssh_key privkey,
}
# ifdef DEBUG_CRYPTO
ssh_print_bignum("r", sig->ecdsa_sig->r);
ssh_print_bignum("s", sig->ecdsa_sig->s);
{
const BIGNUM *pr, *ps;
ECDSA_SIG_get0(sig->ecdsa_sig, &pr, &ps);
ssh_print_bignum("r", (BIGNUM *) pr);
ssh_print_bignum("s", (BIGNUM *) ps);
}
# endif /* DEBUG_CRYPTO */
break;

View File

@@ -199,24 +199,27 @@ int pki_ed25519_key_cmp(const ssh_key k1,
*/
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
{
if (key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL) {
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
new->ed25519_privkey = malloc(ED25519_SK_LEN);
if (new->ed25519_privkey == NULL) {
return SSH_ERROR;
if (key->ed25519_privkey != NULL) {
new->ed25519_privkey = malloc(ED25519_SK_LEN);
if (new->ed25519_privkey == NULL) {
return SSH_ERROR;
}
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN);
}
new->ed25519_pubkey = malloc(ED25519_PK_LEN);
if (new->ed25519_privkey == NULL || new->ed25519_pubkey == NULL){
SAFE_FREE(new->ed25519_privkey);
return SSH_ERROR;
if (key->ed25519_pubkey != NULL) {
new->ed25519_pubkey = malloc(ED25519_PK_LEN);
if (new->ed25519_pubkey == NULL) {
SAFE_FREE(new->ed25519_privkey);
return SSH_ERROR;
}
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN);
}
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN);
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN);
return SSH_OK;
}

View File

@@ -257,6 +257,10 @@ void ssh_free(ssh_session session) {
ssh_list_free(session->ssh_message_list);
}
if (session->kbdint != NULL) {
ssh_kbdint_free(session->kbdint);
}
if (session->packet_callbacks) {
ssh_list_free(session->packet_callbacks);
}

View File

@@ -44,6 +44,68 @@ set(TEST_TARGET_LIBRARIES
add_subdirectory(unittests)
if (WITH_CLIENT_TESTING)
find_package(socket_wrapper 1.1.5 REQUIRED)
find_package(nss_wrapper 1.1.2 REQUIRED)
find_package(uid_wrapper 1.2.0 REQUIRED)
find_package(pam_wrapper 1.0.0 REQUIRED)
find_program(SSHD_EXECUTABLE
NAME
sshd
PATHS
/sbin
/usr/sbin
/usr/local/sbin)
if (NOT SSHD_EXECUTABLE)
message(SEND_ERROR "Could not find sshd which is required for client testing")
endif()
find_program(SSH_EXECUTABLE NAMES ssh)
if (SSH_EXECUTABLE)
execute_process(COMMAND ${SSH_EXECUTABLE} -V ERROR_VARIABLE OPENSSH_VERSION_STR)
string(REGEX REPLACE "^OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
string(REGEX REPLACE "^OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
add_definitions(-DOPENSSH_VERSION_MAJOR=${OPENSSH_VERSION_MAJOR} -DOPENSSH_VERSION_MINOR=${OPENSSH_VERSION_MINOR})
endif()
# chroot_wrapper
add_library(chroot_wrapper SHARED chroot_wrapper.c)
set(CHROOT_WRAPPER_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}chroot_wrapper${CMAKE_SHARED_LIBRARY_SUFFIX})
set(TEST_TARGET_LIBRARIES
${TEST_TARGET_LIBRARIES}
chroot_wrapper
)
# homedir will be used in passwd
set(HOMEDIR ${CMAKE_CURRENT_BINARY_DIR}/home)
### Setup nss_wrapper
configure_file(etc/passwd.in ${CMAKE_CURRENT_BINARY_DIR}/etc/passwd @ONLY)
configure_file(etc/shadow.in ${CMAKE_CURRENT_BINARY_DIR}/etc/shadow @ONLY)
configure_file(etc/group.in ${CMAKE_CURRENT_BINARY_DIR}/etc/group @ONLY)
configure_file(etc/hosts.in ${CMAKE_CURRENT_BINARY_DIR}/etc/hosts @ONLY)
### Setup pam_wrapper
configure_file(etc/pam_matrix_passdb.in ${CMAKE_CURRENT_BINARY_DIR}/etc/pam_matrix_passdb @ONLY)
configure_file(etc/pam.d/sshd.in ${CMAKE_CURRENT_BINARY_DIR}/etc/pam.d/sshd @ONLY)
set(TORTURE_ENVIRONMENT "LD_PRELOAD=${SOCKET_WRAPPER_LIBRARY}:${NSS_WRAPPER_LIBRARY}:${UID_WRAPPER_LIBRARY}:${PAM_WRAPPER_LIBRARY}:${CHROOT_WRAPPER_LIBRARY}")
list(APPEND TORTURE_ENVIRONMENT UID_WRAPPER=1 UID_WRAPPER_ROOT=1)
list(APPEND TORTURE_ENVIRONMENT NSS_WRAPPER_PASSWD=${CMAKE_CURRENT_BINARY_DIR}/etc/passwd)
list(APPEND TORTURE_ENVIRONMENT NSS_WRAPPER_SHADOW=${CMAKE_CURRENT_BINARY_DIR}/etc/shadow)
list(APPEND TORTURE_ENVIRONMENT NSS_WRAPPER_GROUP=${CMAKE_CURRENT_BINARY_DIR}/etc/group)
list(APPEND TORTURE_ENVIRONMENT PAM_WRAPPER_SERVICE_DIR=${CMAKE_CURRENT_BINARY_DIR}/etc/pam.d)
# Give bob some keys
file(COPY keys/id_rsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
# Allow to auth with bob his public keys on alice account
configure_file(keys/id_rsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys @ONLY)
message(STATUS "TORTURE_ENVIRONMENT=${TORTURE_ENVIRONMENT}")
add_subdirectory(client)
endif (WITH_CLIENT_TESTING)

8
tests/chroot_wrapper.c Normal file
View File

@@ -0,0 +1,8 @@
/* silent gcc */
int chroot(const char *);
int chroot(const char *path)
{
(void)path;
return 0;
}

View File

@@ -1,15 +1,41 @@
project(clienttests C)
add_cmocka_test(torture_algorithms torture_algorithms.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_auth torture_auth.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_connect torture_connect.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_knownhosts torture_knownhosts.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_proxycommand torture_proxycommand.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_session torture_session.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_forward torture_forward.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_request_env torture_request_env.c ${TORTURE_LIBRARY})
if (WITH_SFTP)
add_cmocka_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_sftp_read torture_sftp_read.c ${TORTURE_LIBRARY})
endif (WITH_SFTP)
set(LIBSSH_CLIENT_TESTS
torture_algorithms
torture_knownhosts
torture_request_env
torture_forward
torture_proxycommand)
if (WITH_SFTP)
set(LIBSSH_CLIENT_TESTS
${LIBSSH_CLIENT_TESTS}
torture_sftp_dir
torture_sftp_read)
endif (WITH_SFTP)
foreach(_CLI_TEST ${LIBSSH_CLIENT_TESTS})
add_cmocka_test(${_CLI_TEST} ${_CLI_TEST}.c ${TORTURE_LIBRARY})
if (OSX)
set_property(
TEST
${_CLI_TEST}
PROPERTY
ENVIRONMENT DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${SOCKET_WRAPPER_LIBRARY})
else ()
set_property(
TEST
${_CLI_TEST}
PROPERTY
ENVIRONMENT ${TORTURE_ENVIRONMENT})
endif()
endforeach()

View File

@@ -25,11 +25,37 @@
#include "libssh/libssh.h"
#include "libssh/priv.h"
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
static int sshd_setup(void **state)
{
torture_setup_sshd_server(state);
return 0;
}
static int sshd_teardown(void **state) {
torture_teardown_sshd_server(state);
return 0;
}
static void setup(void **state) {
int verbosity=torture_libssh_verbosity();
ssh_session session = ssh_new();
struct passwd *pwd;
int rc;
pwd = getpwnam("bob");
assert_non_null(pwd);
rc = setuid(pwd->pw_uid);
assert_return_code(rc, errno);
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
*state = session;
}
@@ -40,9 +66,6 @@ static void teardown(void **state) {
static void test_algorithm(ssh_session session, const char *algo, const char *hmac) {
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, algo);
assert_true(rc == SSH_OK);
@@ -151,6 +174,7 @@ static void torture_algorithms_3des_cbc_hmac_sha2_512(void **state) {
test_algorithm(*state, "3des-cbc", "hmac-sha2-512");
}
#if ((OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) || OPENSSH_VERSION_MAJOR <= 6)
static void torture_algorithms_blowfish_cbc_hmac_sha1(void **state) {
test_algorithm(*state, "blowfish-cbc", "hmac-sha1");
}
@@ -162,14 +186,12 @@ static void torture_algorithms_blowfish_cbc_hmac_sha2_256(void **state) {
static void torture_algorithms_blowfish_cbc_hmac_sha2_512(void **state) {
test_algorithm(*state, "blowfish-cbc", "hmac-sha2-512");
}
#endif
static void torture_algorithms_zlib(void **state) {
ssh_session session = *state;
int rc;
rc = ssh_options_set(session,SSH_OPTIONS_HOST,"localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib");
#ifdef WITH_ZLIB
assert_true(rc == SSH_OK);
@@ -207,9 +229,6 @@ static void torture_algorithms_zlib_openssh(void **state) {
ssh_session session = *state;
int rc;
rc = ssh_options_set(session,SSH_OPTIONS_HOST,"localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib@openssh.com");
#ifdef WITH_ZLIB
assert_true(rc == SSH_OK);
@@ -249,9 +268,6 @@ static void torture_algorithms_ecdh_sha2_nistp256(void **state) {
ssh_session session = *state;
int rc;
rc = ssh_options_set(session,SSH_OPTIONS_HOST,"localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, "ecdh-sha2-nistp256");
assert_true(rc == SSH_OK);
@@ -271,9 +287,6 @@ static void torture_algorithms_dh_group1(void **state) {
ssh_session session = *state;
int rc;
rc = ssh_options_set(session,SSH_OPTIONS_HOST,"localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, "diffie-hellman-group1-sha1");
assert_true(rc == SSH_OK);
@@ -289,6 +302,7 @@ static void torture_algorithms_dh_group1(void **state) {
}
int torture_run_tests(void) {
int rc;
struct torture_state *s = NULL;
UnitTest tests[] = {
unit_test_setup_teardown(torture_algorithms_aes128_cbc_hmac_sha1, setup, teardown),
unit_test_setup_teardown(torture_algorithms_aes128_cbc_hmac_sha2_256, setup, teardown),
@@ -311,9 +325,11 @@ int torture_run_tests(void) {
unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha1, setup, teardown),
unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha2_256, setup, teardown),
unit_test_setup_teardown(torture_algorithms_3des_cbc_hmac_sha2_512, setup, teardown),
#if ((OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6) || OPENSSH_VERSION_MAJOR <= 6)
unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha1, setup, teardown),
unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha2_256, setup, teardown),
unit_test_setup_teardown(torture_algorithms_blowfish_cbc_hmac_sha2_512, setup, teardown),
#endif
unit_test_setup_teardown(torture_algorithms_zlib, setup, teardown),
unit_test_setup_teardown(torture_algorithms_zlib_openssh, setup, teardown),
unit_test_setup_teardown(torture_algorithms_dh_group1,setup,teardown),
@@ -324,7 +340,9 @@ int torture_run_tests(void) {
ssh_init();
torture_filter_tests(tests);
sshd_setup((void **)&s);
rc = run_tests(tests);
sshd_teardown((void **)&s);
ssh_finalize();
return rc;

View File

@@ -24,24 +24,42 @@
#include "torture.h"
#include <libssh/libssh.h>
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
static int sshd_setup(void **state)
{
torture_setup_sshd_server(state);
return 0;
}
static int sshd_teardown(void **state) {
torture_teardown_sshd_server(state);
return 0;
}
static void setup(void **state)
{
ssh_session session;
const char *host;
const char *user;
const char *password;
struct passwd *pwd;
int rc;
host = getenv("TORTURE_HOST");
if (host == NULL) {
host = "localhost";
}
pwd = getpwnam("bob");
assert_non_null(pwd);
user = getenv("TORTURE_USER");
password = getenv("TORTURE_PASSWORD");
rc = setuid(pwd->pw_uid);
assert_return_code(rc, errno);
session = torture_ssh_session(host, NULL, user, password);
session = torture_ssh_session(TORTURE_SSH_SERVER,
NULL,
TORTURE_SSH_USER_ALICE,
NULL);
assert_non_null(session);
*state = session;
}
@@ -60,26 +78,25 @@ static void teardown(void **state)
static void torture_ssh_forward(void **state)
{
ssh_session session = (ssh_session) *state;
#if 0
ssh_channel c;
#endif
int dport;
int bound_port;
int rc;
rc = ssh_channel_listen_forward(session, "127.0.0.1", 8080, &bound_port);
rc = ssh_channel_listen_forward(session, "127.0.0.21", 8080, &bound_port);
assert_int_equal(rc, SSH_OK);
#if 0
c = ssh_forward_accept(session, 60000);
assert_non_null(c);
c = ssh_channel_accept_forward(session, 10, &dport);
/* We do not get a listener and run into the timeout here */
assert_null(c);
ssh_channel_send_eof(c);
ssh_channel_close(c);
#endif
}
int torture_run_tests(void) {
int rc;
struct torture_state *s = NULL;
UnitTest tests[] = {
unit_test_setup_teardown(torture_ssh_forward, setup, teardown),
@@ -88,7 +105,9 @@ int torture_run_tests(void) {
ssh_init();
torture_filter_tests(tests);
sshd_setup((void **)&s);
rc = run_tests(tests);
sshd_teardown((void **)&s);
ssh_finalize();
return rc;

View File

@@ -25,6 +25,9 @@
#include "session.c"
#include "known_hosts.c"
#include <sys/types.h>
#include <pwd.h>
#define KNOWNHOSTFILES "libssh_torture_knownhosts"
#define BADRSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQChm5" \
"a6Av65O8cKtx5YXOnui3wJnYE6A6J/I4kZSAibbn14Jcl+34VJQwv96f25AxNmo" \
@@ -44,11 +47,31 @@
"h0dSi8VJXI1wes5HTyLsv9VBmU1uCXUUvufoQKfF/OcSH0ufcCpnd62g1/adZcy2" \
"WJg=="
static int sshd_setup(void **state)
{
torture_setup_sshd_server(state);
return 0;
}
static int sshd_teardown(void **state) {
torture_teardown_sshd_server(state);
return 0;
}
static void setup(void **state) {
int verbosity=torture_libssh_verbosity();
ssh_session session = ssh_new();
struct passwd *pwd;
pwd = getpwnam("bob");
assert_non_null(pwd);
setuid(pwd->pw_uid);
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
*state = session;
}
@@ -73,8 +96,6 @@ static void torture_knownhosts_port(void **state) {
* the known hosts file. Then check that the entry written is
* [localhost]:1234
*/
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
assert_true(rc == SSH_OK);
@@ -92,7 +113,7 @@ static void torture_knownhosts_port(void **state) {
assert_false(p == NULL);
fclose(file);
buffer[sizeof(buffer) - 1] = '\0';
assert_true(strstr(buffer,"[localhost]:1234 ") != NULL);
assert_true(strstr(buffer,"[127.0.0.10]:1234 ") != NULL);
ssh_disconnect(session);
ssh_free(session);
@@ -100,7 +121,7 @@ static void torture_knownhosts_port(void **state) {
/* Now, connect back to the ssh server and verify the known host line */
*state = session = ssh_new();
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
rc = ssh_connect(session);
@@ -116,9 +137,6 @@ static void torture_knownhosts_fail(void **state) {
FILE *file;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
assert_true(rc == SSH_OK);
@@ -127,7 +145,7 @@ static void torture_knownhosts_fail(void **state) {
file = fopen(KNOWNHOSTFILES, "w");
assert_true(file != NULL);
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
fprintf(file, TORTURE_SSH_SERVER " ssh-rsa %s\n", BADRSA);
fclose(file);
rc = ssh_connect(session);
@@ -142,9 +160,6 @@ static void torture_knownhosts_other(void **state) {
FILE *file;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
assert_true(rc == SSH_OK);
@@ -153,7 +168,7 @@ static void torture_knownhosts_other(void **state) {
file = fopen(KNOWNHOSTFILES, "w");
assert_true(file != NULL);
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
fprintf(file, TORTURE_SSH_SERVER " ssh-rsa %s\n", BADRSA);
fclose(file);
rc = ssh_connect(session);
@@ -167,9 +182,6 @@ static void torture_knownhosts_other_auto(void **state) {
ssh_session session = *state;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
assert_true(rc == SSH_OK);
@@ -191,7 +203,7 @@ static void torture_knownhosts_other_auto(void **state) {
/* connect again and check host key */
*state = session = ssh_new();
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
@@ -210,9 +222,6 @@ static void torture_knownhosts_conflict(void **state) {
FILE *file;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
assert_true(rc == SSH_OK);
@@ -221,8 +230,8 @@ static void torture_knownhosts_conflict(void **state) {
file = fopen(KNOWNHOSTFILES, "w");
assert_true(file != NULL);
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
fprintf(file, "localhost ssh-dss %s\n", BADDSA);
fprintf(file, TORTURE_SSH_SERVER " ssh-rsa %s\n", BADRSA);
fprintf(file, TORTURE_SSH_SERVER " ssh-dss %s\n", BADDSA);
fclose(file);
rc = ssh_connect(session);
@@ -240,7 +249,7 @@ static void torture_knownhosts_conflict(void **state) {
/* connect again and check host key */
*state = session = ssh_new();
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-rsa");
assert_true(rc == SSH_OK);
@@ -258,16 +267,13 @@ static void torture_knownhosts_precheck(void **state) {
int rc;
char **kex;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == SSH_OK);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, KNOWNHOSTFILES);
assert_true(rc == SSH_OK);
file = fopen(KNOWNHOSTFILES, "w");
assert_true(file != NULL);
fprintf(file, "localhost ssh-rsa %s\n", BADRSA);
fprintf(file, "localhost ssh-dss %s\n", BADDSA);
fprintf(file, TORTURE_SSH_SERVER " ssh-rsa %s\n", BADRSA);
fprintf(file, TORTURE_SSH_SERVER " ssh-dss %s\n", BADDSA);
fclose(file);
kex = ssh_knownhosts_algorithms(session);
@@ -282,6 +288,7 @@ static void torture_knownhosts_precheck(void **state) {
int torture_run_tests(void) {
int rc;
struct torture_state *s = NULL;
UnitTest tests[] = {
unit_test_setup_teardown(torture_knownhosts_port, setup, teardown),
unit_test_setup_teardown(torture_knownhosts_fail, setup, teardown),
@@ -294,7 +301,9 @@ int torture_run_tests(void) {
ssh_init();
torture_filter_tests(tests);
sshd_setup((void **)&s);
rc = run_tests(tests);
sshd_teardown((void **)&s);
ssh_finalize();
return rc;

View File

@@ -4,8 +4,39 @@
#include <libssh/libssh.h>
#include "libssh/priv.h"
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
static int sshd_setup(void **state)
{
torture_setup_sshd_server(state);
return 0;
}
static int sshd_teardown(void **state) {
torture_teardown_sshd_server(state);
return 0;
}
static void setup(void **state) {
ssh_session session = ssh_new();
int verbosity = torture_libssh_verbosity();
struct passwd *pwd;
int rc;
pwd = getpwnam("bob");
assert_non_null(pwd);
rc = setuid(pwd->pw_uid);
assert_return_code(rc, errno);
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
*state = session;
}
@@ -18,10 +49,7 @@ static void torture_options_set_proxycommand(void **state) {
ssh_session session = *state;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == 0);
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "nc localhost 22");
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "nc 127.0.0.10 22");
assert_true(rc == 0);
rc = ssh_connect(session);
assert_true(rc == SSH_OK);
@@ -31,9 +59,6 @@ static void torture_options_set_proxycommand_notexist(void **state) {
ssh_session session = *state;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
assert_true(rc == 0);
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, "this_command_does_not_exist");
assert_true(rc == SSH_OK);
rc = ssh_connect(session);
@@ -42,6 +67,7 @@ static void torture_options_set_proxycommand_notexist(void **state) {
int torture_run_tests(void) {
int rc;
struct torture_state *s = NULL;
UnitTest tests[] = {
unit_test_setup_teardown(torture_options_set_proxycommand, setup, teardown),
unit_test_setup_teardown(torture_options_set_proxycommand_notexist, setup, teardown),
@@ -51,7 +77,9 @@ int torture_run_tests(void) {
ssh_init();
torture_filter_tests(tests);
sshd_setup((void **)&s);
rc = run_tests(tests);
sshd_teardown((void **)&s);
ssh_finalize();
return rc;

View File

@@ -24,22 +24,36 @@
#include "torture.h"
#include <libssh/libssh.h>
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
static int sshd_setup(void **state)
{
torture_setup_sshd_server(state);
return 0;
}
static int sshd_teardown(void **state) {
torture_teardown_sshd_server(state);
return 0;
}
static void setup(void **state)
{
ssh_session session;
const char *host;
const char *user;
const char *password;
struct passwd *pwd;
host = getenv("TORTURE_HOST");
if (host == NULL) {
host = "localhost";
}
pwd = getpwnam("bob");
assert_non_null(pwd);
setuid(pwd->pw_uid);
user = getenv("TORTURE_USER");
password = getenv("TORTURE_PASSWORD");
session = torture_ssh_session(host, NULL, user, password);
session = torture_ssh_session(TORTURE_SSH_SERVER,
NULL,
TORTURE_SSH_USER_ALICE,
NULL);
assert_false(session == NULL);
*state = session;
@@ -99,6 +113,7 @@ static void torture_request_env(void **state)
int torture_run_tests(void) {
int rc;
struct torture_state *s = NULL;
UnitTest tests[] = {
unit_test_setup_teardown(torture_request_env, setup, teardown),
@@ -107,7 +122,9 @@ int torture_run_tests(void) {
ssh_init();
torture_filter_tests(tests);
sshd_setup((void **)&s);
rc = run_tests(tests);
sshd_teardown((void **)&s);
ssh_finalize();
return rc;

View File

@@ -92,7 +92,12 @@ static void torture_channel_read_error(void **state) {
if (rc == SSH_ERROR)
break;
}
assert_true(rc == SSH_ERROR);
#if OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 7
/* With openssh 6.7 this doesn't produce and error anymore */
assert_int_equal(rc, SSH_OK);
#else
assert_int_equal(rc, SSH_ERROR);
#endif
ssh_channel_free(channel);
}

View File

@@ -3,22 +3,36 @@
#include "torture.h"
#include "sftp.c"
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
static int sshd_setup(void **state)
{
torture_setup_sshd_server(state);
return 0;
}
static int sshd_teardown(void **state) {
torture_teardown_sshd_server(state);
return 0;
}
static void setup(void **state) {
ssh_session session;
struct torture_sftp *t;
const char *host;
const char *user;
const char *password;
struct passwd *pwd;
host = getenv("TORTURE_HOST");
if (host == NULL) {
host = "localhost";
}
pwd = getpwnam("bob");
assert_non_null(pwd);
setuid(pwd->pw_uid);
user = getenv("TORTURE_USER");
password = getenv("TORTURE_PASSWORD");
session = torture_ssh_session(host, NULL, user, password);
session = torture_ssh_session(TORTURE_SSH_SERVER,
NULL,
TORTURE_SSH_USER_ALICE,
NULL);
assert_false(session == NULL);
t = torture_sftp_session(session);
assert_false(t == NULL);
@@ -61,6 +75,7 @@ static void torture_sftp_mkdir(void **state) {
int torture_run_tests(void) {
int rc;
struct torture_state *s = NULL;
UnitTest tests[] = {
unit_test_setup_teardown(torture_sftp_mkdir, setup, teardown)
};
@@ -68,7 +83,9 @@ int torture_run_tests(void) {
ssh_init();
torture_filter_tests(tests);
sshd_setup((void **)&s);
rc = run_tests(tests);
sshd_teardown((void **)&s);
ssh_finalize();
return rc;

View File

@@ -3,24 +3,40 @@
#include "torture.h"
#include "sftp.c"
#include <sys/types.h>
#include <pwd.h>
#define MAX_XFER_BUF_SIZE 16384
static int sshd_setup(void **state)
{
torture_setup_sshd_server(state);
return 0;
}
static int sshd_teardown(void **state) {
torture_teardown_sshd_server(state);
return 0;
}
static void setup(void **state) {
ssh_session session;
struct torture_sftp *t;
const char *host;
const char *user;
const char *password;
struct passwd *pwd;
int rc;
host = getenv("TORTURE_HOST");
if (host == NULL) {
host = "localhost";
}
pwd = getpwnam("bob");
assert_non_null(pwd);
user = getenv("TORTURE_USER");
password = getenv("TORTURE_PASSWORD");
rc = setuid(pwd->pw_uid);
assert_return_code(rc, errno);
session = torture_ssh_session(host, NULL, user, password);
session = torture_ssh_session(TORTURE_SSH_SERVER,
NULL,
TORTURE_SSH_USER_ALICE,
NULL);
assert_false(session == NULL);
t = torture_sftp_session(session);
assert_false(t == NULL);
@@ -72,6 +88,7 @@ static void torture_sftp_read_blocking(void **state) {
int torture_run_tests(void) {
int rc;
struct torture_state *s = NULL;
UnitTest tests[] = {
unit_test_setup_teardown(torture_sftp_read_blocking, setup, teardown)
};
@@ -79,7 +96,9 @@ int torture_run_tests(void) {
ssh_init();
torture_filter_tests(tests);
sshd_setup((void **)&s);
rc = run_tests(tests);
sshd_teardown((void **)&s);
ssh_finalize();
return rc;

View File

@@ -39,6 +39,7 @@ set(CTEST_SOURCE_DIRECTORY "${CTEST_DIRECTORY}/${CTEST_BUILD_NAME}/source")
set(CTEST_BINARY_DIRECTORY "${CTEST_DIRECTORY}/${CTEST_BUILD_NAME}/build")
set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE ${CMAKE_SOURCE_DIR}/tests/valgrind.supp)
set(CTEST_MEMORYCHECK_COMMAND_OPTIONS " --trace-children-skip=sshd")
find_program(CTEST_GIT_COMMAND NAMES git)
find_program(CTEST_COVERAGE_COMMAND NAMES gcov)

5
tests/etc/group.in Normal file
View File

@@ -0,0 +1,5 @@
users:x:1000:
sshd:x:65531:
nobody:x:65533:
nogroup:x:65534:nobody
root:x:65532:

2
tests/etc/hosts.in Normal file
View File

@@ -0,0 +1,2 @@
127.0.0.10 server.libssh.site
127.0.0.21 client.libssh.site

4
tests/etc/pam.d/sshd.in Normal file
View File

@@ -0,0 +1,4 @@
auth required @PAM_WRAPPER_MODULE_DIR@/pam_matrix.so passdb=@CMAKE_CURRENT_BINARY_DIR@/etc/pam_matrix_passdb
account required @PAM_WRAPPER_MODULE_DIR@/pam_matrix.so passdb=@CMAKE_CURRENT_BINARY_DIR@/etc/pam_matrix_passdb
password required @PAM_WRAPPER_MODULE_DIR@/pam_matrix.so passdb=@CMAKE_CURRENT_BINARY_DIR@/etc/pam_matrix_passdb
session required @PAM_WRAPPER_MODULE_DIR@/pam_matrix.so passdb=@CMAKE_CURRENT_BINARY_DIR@/etc/pam_matrix_passdb

View File

@@ -0,0 +1,2 @@
bob:secret:sshd
alice:secret:sshd

5
tests/etc/passwd.in Normal file
View File

@@ -0,0 +1,5 @@
bob:x:1000:1000:bob gecos:@HOMEDIR@/bob:/bin/false
alice:x:1001:1000:alice gecos:@HOMEDIR@/alice:/bin/bash
sshd:x:65530:65531:sshd:@HOMEDIR@:/sbin/nologin
nobody:x:65533:65534:nobody gecos:@HOMEDIR@:/bin/false
root:x:65534:65532:root gecos:@HOMEDIR@:/bin/false

2
tests/etc/shadow.in Normal file
View File

@@ -0,0 +1,2 @@
alice:$6$0jWkA8VP$MvBUvtGy38jWCZ5KtqnZEKQWXvvImDkDhDQII1kTqtAp3/xH31b71c.AjGkBFle.2QwCJQH7OzB/NXiMprusr/::0:::::
bob:$6$0jWkA8VP$MvBUvtGy38jWCZ5KtqnZEKQWXvvImDkDhDQII1kTqtAp3/xH31b71c.AjGkBFle.2QwCJQH7OzB/NXiMprusr/::0:::::

27
tests/keys/id_rsa Normal file
View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAs/fIz+Gy89XjUhXebNq2rs1K0RJEZXDbfcofb13ESDJ9fSbd
+RlCUM6i+foEVV23xWdands2Bkn72tGinJadIgOWU+koxp+gRmtJLE/ONiAKJQqR
K3eOJNBH6At96NMqJ4Gwv56G4W68uPgDwUVQwVIc6Ec6Rypiz7DE+S++gSvBQIVU
Qt7XkPcXOyN5zuj5qDhZM4l6V7Og9LWj4/2IF5acvKjfIMpeqmnp9z6BTYZQtuQU
6b1VuEYhXyvM6LkMwndsVGh46kDKMmRQhyA8A6qvLAliMMq88k5gR4AeJeTnqDR/
Q120I6PMqYNl6TLTk8/KonOOPDR/XXGb3iF67wIDAQABAoIBAAVoL2dXf5nl1jOU
Jp+cnpp33oSTiOyHTIDl/rXI2mnU4oJNFaQzRxPIcYsTIOgzrZ7HsShG+sOLm36C
h+EugUARXYXd3nTBPP6AoK0tJKPpqIReYegtal7exxpIphrFpWGUeuv25lSFkDP6
d5pp67gzMF0mLrEOq/NTe0eFULLuwa6+IKXU7deiU90pzi4jrjcIWNoGHSw1YYAZ
TC8KAxA/tYH9myya5krRCjA9B345DJ9Wd71wX+RZNgbSkIri/6dDTtvsYvqcQKo0
OZ3MUDJnKmkfPLP84qZPRoEwUI1gts1WUdoNK6LK7yOJmPL5FMyTwZx3XtDw3gAv
TVhI7ikCgYEA5Ay0TCySPQAaC14WtjgIAmTa19mAtOFpbRxToi40WjXk3R6mMqyp
biAcNecdZRC6zzgAUp8g1O3Yc1d9fG/3FpM5eUbIer7mMLTRuQQysoJY2Ayw9OEA
qPHS/K6LPOD09aZo14fRUqVO8rwMbHtq2yhH8p3FM8WZRe5ms8zpyLUCgYEAygZ3
RTMWbgcGdNoaPa5Ms9KRqAxKJLin2fE99KowZeJfvZN24sXExawQdy4BKVYT0H6e
MNEIPiEBVA4a1GDk/tyOrEt684IsidROngJaGbqb+SYm6feQAioYu0wkG/I2hS12
/Z/aK6wFz5hWzBv/YvJqC7xD1YwZm1QXDyAiL5MCgYAXz8fHqGPAoNEXXMSsVB9p
+JPtM9W/jUXP0cRdy8tFnBkAiaG66tJqIEoxyqcEFYIb/vHxrpHkCc2vBXSh2KMJ
JWg75IssXeB1N3wqgGi2wOt7659SgmfqPA3WunbpbWfGepC56IGPypj6uW3mqeBX
b9ZLW/PqWviNF757iarjfQKBgGxKBPqRxM8bcumF0xUG7dRh5XN3ivKeDFL1Tels
pF6odftPJSWvLqdqcLUBctvuaNaUWEUAdvOei3C70sPOYFEAdnWCTBhkyWzj4XQu
/I7YCS0Gt0soSQfv+qvCx4Q3U+QVF7ghTDemkMLS/IuR4lXubMt3kcDQxRUOgQG5
jrmDAoGALauF7ZyzEnQgsgMVzfm9znl5I2aIsLgdsAv3lINVrvtTKhddp7cdd+2j
dwZlaMnLET/3MY/Cvf13vEsS+bdNXjsdQidqBL8pe5PXY/pafBhtduQuvGzlHJA5
CEBnwB0SdtsXbzSpOAPZqea4Nz9MkQ8LMsINdPpxCuFhjeYa9Ow=
-----END RSA PRIVATE KEY-----

1
tests/keys/id_rsa.pub Normal file
View File

@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCz98jP4bLz1eNSFd5s2rauzUrREkRlcNt9yh9vXcRIMn19Jt35GUJQzqL5+gRVXbfFZ1qd2zYGSfva0aKclp0iA5ZT6SjGn6BGa0ksT842IAolCpErd44k0EfoC33o0yongbC/nobhbry4+APBRVDBUhzoRzpHKmLPsMT5L76BK8FAhVRC3teQ9xc7I3nO6PmoOFkziXpXs6D0taPj/YgXlpy8qN8gyl6qaen3PoFNhlC25BTpvVW4RiFfK8zouQzCd2xUaHjqQMoyZFCHIDwDqq8sCWIwyrzyTmBHgB4l5OeoNH9DXbQjo8ypg2XpMtOTz8qic448NH9dcZveIXrv asn@krikkit.cryptomilk.site

View File

@@ -0,0 +1,12 @@
-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQD7vBS+d/eJP6wK2VQw+8AIfgCw9IR50utLRkkrWbfDdiM7V+fp
tJYKCyqZT9j9ANhqicB2tuqAI6WJBZMaGekxWfI30JxPkHZrrwbdFzlRbjav07lg
IKqWgcz81iVPmfn5savEoobiSFjJNMmYcizjKZgGmyNUzlJjzF7u5qD08wIVAPFp
6VKuv8VxNjENciUZCdEDRW/lAoGBAN/BFSBRSP9frsHID6e2NeKHqs8JDUWhCTE9
/WQKqUUbxO2UU98CfHuf1mNlaSsrOxaBdvTeURcZZc1svhyGr1VG+NbNTDDlzTgA
UlrzNML61TYcFXQVxgifUy+Tmh8FRGCa6Ko/EsX4ZWLTto5w1u5cPpgzSbLMco9T
AeeNLgYNAoGAJRuawWN3+NezI7+bBe42Kjg4gVUlpS+8TTlYFbwrM1Esab7gvxHB
/b2apbk9xIAkkqsnb+EPrXTLUdE2Y7XkEuGLLSTus2UlZKobBGBX/Ioysg5W9Fk/
2MhI4YssRb2alar8d+gmAHPaT+D+NDd90PBfY3HqcXFEK+eDTWo1JNICFBLdsuoO
6pObeFSOYbr38kJzZ0xG
-----END DSA PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAPu8FL5394k/rArZVDD7wAh+ALD0hHnS60tGSStZt8N2IztX5+m0lgoLKplP2P0A2GqJwHa26oAjpYkFkxoZ6TFZ8jfQnE+QdmuvBt0XOVFuNq/TuWAgqpaBzPzWJU+Z+fmxq8SihuJIWMk0yZhyLOMpmAabI1TOUmPMXu7moPTzAAAAFQDxaelSrr/FcTYxDXIlGQnRA0Vv5QAAAIEA38EVIFFI/1+uwcgPp7Y14oeqzwkNRaEJMT39ZAqpRRvE7ZRT3wJ8e5/WY2VpKys7FoF29N5RFxllzWy+HIavVUb41s1MMOXNOABSWvM0wvrVNhwVdBXGCJ9TL5OaHwVEYJroqj8SxfhlYtO2jnDW7lw+mDNJssxyj1MB540uBg0AAACAJRuawWN3+NezI7+bBe42Kjg4gVUlpS+8TTlYFbwrM1Esab7gvxHB/b2apbk9xIAkkqsnb+EPrXTLUdE2Y7XkEuGLLSTus2UlZKobBGBX/Ioysg5W9Fk/2MhI4YssRb2alar8d+gmAHPaT+D+NDd90PBfY3HqcXFEK+eDTWo1JNI= asn@magrathea

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIB9v2n1oaXvBECf0gDPxTibeUPvvkI1anNWDAIkNjs5JoAoGCCqGSM49
AwEHoUQDQgAEqkTqNu7gRegPJRy0WiseJz9NAdBimzyNSzNwI5eAkEqv9D6Y95KL
7DBEnDQ2p08iOLw+vN1PKHsCM7b/ONbYVg==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKpE6jbu4EXoDyUctForHic/TQHQYps8jUszcCOXgJBKr/Q+mPeSi+wwRJw0NqdPIji8PrzdTyh7AjO2/zjW2FY= asn@magrathea

BIN
tests/keys/ssh_host_key Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
2048 65537 25221975523736997039149017470335977198642717886559395625730372192276493838727011206749822289920387480933533054627057418868711378045090730895752530916661328094497437687453813456961487210492465678475508526337829331199296553120728607984859224949182503917312492825658971738208505685553964707412720244524969161284321098487507924676797222812771309962906894332072854924265623785469343453142982185436565166155021228521252914913227554455102103918367844210755391318078654400527927267478149210805219779896806429660492177158822689909493046725157917529664436252598971135251689616517266344945600782273453037452082373553352939812279 asn@magrathea

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAqzabeU0oKbHDwdlqindABvtzgWCvXdHJ+d2Ew6te2LXjkwju
y7u6B7y63NZRy57ccrE4YSeWItVoZn+DWN+guU354Ss/tzQ9/thUmLrvtKNvJwuF
F5Ch7Q4BsrXGsb2GSv+7W5tpx3yAqH1TvKQj/MmQVX+/9KtXEnh7/vpiCqoOXQAR
zvIIQxoo1aUQBHAkRW7Yw0Ds7AjC9uV1ns4xdBXPQmDk23pWvCq7E+7rOEbKRrjj
lApS4lJYy0oEXsFdqUPd+PtT1gG0nIElHFQtsTgUvwYQmJEzrBxv41odwRvxbMjg
THPr4SLRRRSuPwICWyvxqPpa7EsfMBnbPEIUzQIDAQABAoIBAEUO15MLvgFjRDQy
P7jt9JNcZPBwUQukjLUN1nkd7Dm407wAxGDErXplc3GTuJZK01wngzgcwX/3WA7P
q+jy+l8DxqA904tPtRnPo/+elwTjTvgOu3YPzmBRX/n3O9eBPGOP1sBSZU4jN7m+
I0JZanKR0nfJ+WD0o0A9/LWRxG3MFIntBamtT6pgee8sAu44IvW0o7tHJabMq02J
Z/ndrJmox34wq6SMFANax+N1x9sZa60bL7gEoDWQJNKOaMrbtOaIoTGFIc4hFqoA
SzjNqcGsHPWs44cw0mNkUGq37jEvaCwzAp+U80ma1skBhXuJL9sQOxl1v5qW91c/
Cnm5WYECgYEA4DPvqbLt+VdyTtmCQ370yiCk4OPPMPzbM65IVKgQL/rN6HdNShTO
uLF6P8XC8vNP2OSydJeFt+kMKd7E/4o5LfvEqUGXZJDkB7fLjrOjyZU3bxtIx95x
qYGWRcWbd3sHzlBJGuFVSE7GREE+lqhkSu4ry4l/GAKxSymAXgGd/9ECgYEAw37L
ppZIavcLE2rZgXHoqMiJzeGzsidJbkHss4k7ubLe8vyBMiv0HC2anxPa2+yNWuF2
+pEr84bllh149VKeild24UEBAR2w/P41ggWqiUP7PKllh+huWzG4+KNFbfUP4dd0
4LkVgfsCz32qD8qxXNCxJCZ8H2fmjKsYw/oCID0CgYAiuSh3GdUtdtOnTpyUI4d5
/pBKnD2skpzIZkehhN3s8GUPidqYjJxvkl0in1hQFErbhp/02rrE/vz5Rx0vjpLI
gmO06wmtc5s9bsPB+CR3xfpt5MXi3pqv6/gAGli3qoBM/bY0yY1Rw5GFZK1y2+Wc
jUKPJV5fs5sNzwGojYuQ4QKBgQCNNgqOo2Fd+mLCvNyt1wTy3iBEWfL+DcjJ3s7G
hKtioKTQqbn87qjercZRf/sH/t/ANLpHlhNETj2KaHGV6v7f+PvDC7xY/QR6SnmG
GOetTTCuCcJwIGGOd+UfnHgrS+gT/xjKtoalpBXMoP31eDkTTR+XeEESQm/TTkeO
UAm3FQKBgD8Y7CLHpyZZ+eOnxRSPU4m4AWAEp7JOwHDRWWQeUornrXDYgD87d2M9
iIAEuOzNggA56Nm3AzBOPRj4HkBh57ToVKPswHwB0oWvrtSjpLkkU6q8xRG3XuJD
2AskDaZONzIDoJGfZ3+W7YbKELK7DPtFXL15sOfBmpoEkI9RA5vM
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrNpt5TSgpscPB2WqKd0AG+3OBYK9d0cn53YTDq17YteOTCO7Lu7oHvLrc1lHLntxysThhJ5Yi1Whmf4NY36C5TfnhKz+3ND3+2FSYuu+0o28nC4UXkKHtDgGytcaxvYZK/7tbm2nHfICofVO8pCP8yZBVf7/0q1cSeHv++mIKqg5dABHO8ghDGijVpRAEcCRFbtjDQOzsCML25XWezjF0Fc9CYOTbela8KrsT7us4RspGuOOUClLiUljLSgRewV2pQ934+1PWAbScgSUcVC2xOBS/BhCYkTOsHG/jWh3BG/FsyOBMc+vhItFFFK4/AgJbK/Go+lrsSx8wGds8QhTN asn@magrathea

View File

@@ -28,6 +28,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#ifndef _WIN32
# include <dirent.h>
@@ -219,10 +220,16 @@ static const char torture_ed25519_testkey_pp[]=
"Y3GsmYTDstmicanQ==\n"
"-----END OPENSSH PRIVATE KEY-----\n";
#define TORTURE_SOCKET_DIR "/tmp/test_socket_wrapper_XXXXXX"
#define TORTURE_SSHD_PIDFILE "sshd/sshd.pid"
#define TORTURE_SSHD_CONFIG "sshd/sshd_config"
#define TORTURE_PCAP_FILE "socket_trace.pcap"
static int verbosity = 0;
static const char *pattern = NULL;
#ifndef _WIN32
static int _torture_auth_kbdint(ssh_session session,
const char *password) {
const char *prompt;
@@ -338,6 +345,58 @@ int torture_isdir(const char *path) {
return 0;
}
int torture_terminate_process(const char *pidfile)
{
char buf[8] = {0};
long int tmp;
ssize_t rc;
pid_t pid;
int fd;
int is_running = 1;
int count;
/* read the pidfile */
fd = open(pidfile, O_RDONLY);
if (fd < 0) {
return -1;
}
rc = read(fd, buf, sizeof(buf));
close(fd);
if (rc <= 0) {
return -1;
}
buf[sizeof(buf) - 1] = '\0';
tmp = strtol(buf, NULL, 10);
if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) {
return -1;
}
pid = (pid_t)(tmp & 0xFFFF);
for (count = 0; count < 10; count++) {
/* Make sure the daemon goes away! */
kill(pid, SIGTERM);
usleep(10 * 1000);
rc = kill(pid, 0);
if (rc != 0) {
is_running = 0;
break;
}
}
if (is_running) {
fprintf(stderr,
"WARNING: The process server is still running!\n");
}
return 0;
}
ssh_session torture_ssh_session(const char *host,
const unsigned int *port,
const char *user,
@@ -355,11 +414,6 @@ ssh_session torture_ssh_session(const char *host,
return NULL;
}
rc = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, "/tmp");
if (rc < 0) {
goto failed;
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
goto failed;
}
@@ -397,10 +451,10 @@ ssh_session torture_ssh_session(const char *host,
}
if (password != NULL) {
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
rc = _torture_auth_kbdint(session, password);
} else if (method & SSH_AUTH_METHOD_PASSWORD) {
if (method & SSH_AUTH_METHOD_PASSWORD) {
rc = ssh_userauth_password(session, NULL, password);
} else if (method & SSH_AUTH_METHOD_INTERACTIVE) {
rc = _torture_auth_kbdint(session, password);
}
} else {
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
@@ -479,7 +533,7 @@ ssh_bind torture_ssh_bind(const char *addr,
return sshbind;
}
#endif
#endif /* WITH_SERVER */
#ifdef WITH_SFTP
@@ -541,37 +595,11 @@ void torture_sftp_close(struct torture_sftp *t) {
sftp_free(t->sftp);
}
if (t->ssh != NULL) {
if (ssh_is_connected(t->ssh)) {
ssh_disconnect(t->ssh);
}
ssh_free(t->ssh);
}
free(t->testdir);
free(t);
}
#endif /* WITH_SFTP */
#endif /* _WIN32 */
void torture_write_file(const char *filename, const char *data){
int fd;
int rc;
assert_non_null(filename);
assert_true(filename[0] != '\0');
assert_non_null(data);
fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0755);
assert_true(fd >= 0);
rc = write(fd, data, strlen(data));
assert_int_equal(rc, strlen(data));
close(fd);
}
static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
int bits,
int with_passphrase,
@@ -647,6 +675,251 @@ const char *torture_get_testkey_passphrase(void)
return TORTURE_TESTKEY_PASSWORD;
}
void torture_setup_socket_dir(void **state)
{
struct torture_state *s;
const char *p;
size_t len;
char *env = getenv("TORTURE_GENERATE_PCAP");
s = malloc(sizeof(struct torture_state));
assert_non_null(s);
s->socket_dir = strdup(TORTURE_SOCKET_DIR);
assert_non_null(s->socket_dir);
p = mkdtemp(s->socket_dir);
assert_non_null(p);
/* pcap file */
len = strlen(p) + 1 + strlen(TORTURE_PCAP_FILE) + 1;
s->pcap_file = malloc(len);
assert_non_null(s->pcap_file);
snprintf(s->pcap_file, len, "%s/%s", p, TORTURE_PCAP_FILE);
/* pid file */
len = strlen(p) + 1 + strlen(TORTURE_SSHD_PIDFILE) + 1;
s->srv_pidfile = malloc(len);
assert_non_null(s->srv_pidfile);
snprintf(s->srv_pidfile, len, "%s/%s", p, TORTURE_SSHD_PIDFILE);
/* config file */
len = strlen(p) + 1 + strlen(TORTURE_SSHD_CONFIG) + 1;
s->srv_config = malloc(len);
assert_non_null(s->srv_config);
snprintf(s->srv_config, len, "%s/%s", p, TORTURE_SSHD_CONFIG);
setenv("SOCKET_WRAPPER_DIR", p, 1);
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1);
if (env != NULL && env[0] == '1') {
setenv("SOCKET_WRAPPER_PCAP_FILE", s->pcap_file, 1);
}
*state = s;
}
static void torture_setup_create_sshd_config(void **state)
{
struct torture_state *s = *state;
char ed25519_hostkey[1024] = {0};
char dsa_hostkey[1024];
char rsa_hostkey[1024];
char ecdsa_hostkey[1024];
char sshd_config[2048];
char sshd_path[1024];
struct stat sb;
const char *sftp_server_locations[] = {
"/usr/lib/ssh/sftp-server",
"/usr/libexec/sftp-server",
"/usr/libexec/openssh/sftp-server",
"/usr/lib/openssh/sftp-server", /* Debian */
};
#ifndef OPENSSH_VERSION_MAJOR
#define OPENSSH_VERSION_MAJOR 7U
#define OPENSSH_VERSION_MINOR 0U
#endif /* OPENSSH_VERSION_MAJOR */
const char config_string[]=
"Port 22\n"
"ListenAddress 127.0.0.10\n"
"HostKey %s\n"
"HostKey %s\n"
"HostKey %s\n"
"HostKey %s\n"
"\n"
"LogLevel DEBUG3\n"
"Subsystem sftp %s -l DEBUG2\n"
"\n"
"PasswordAuthentication yes\n"
"KbdInteractiveAuthentication yes\n"
"PubkeyAuthentication yes\n"
"\n"
"StrictModes no\n"
"\n"
"UsePAM yes\n"
"\n"
#if (OPENSSH_VERSION_MAJOR == 6 && OPENSSH_VERSION_MINOR >= 7) || (OPENSSH_VERSION_MAJOR >= 7)
"HostKeyAlgorithms +ssh-dss\n"
# if (OPENSSH_VERSION_MAJOR == 7 && OPENSSH_VERSION_MINOR < 6)
"Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,blowfish-cbc\n"
# else /* OPENSSH_VERSION 7.0 - 7.5 */
"Ciphers +3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc\n"
# endif /* OPENSSH_VERSION 7.0 - 7.6 */
"KexAlgorithms +diffie-hellman-group1-sha1"
#else /* OPENSSH_VERSION >= 6.7 */
"Ciphers 3des-cbc,aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,"
"aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,"
"aes256-gcm@openssh.com,arcfour128,arcfour256,arcfour,"
"blowfish-cbc,cast128-cbc,chacha20-poly1305@openssh.com\n"
"KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp256,"
"ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
"diffie-hellman-group-exchange-sha256,"
"diffie-hellman-group-exchange-sha1,"
"diffie-hellman-group14-sha1,"
"diffie-hellman-group1-sha1\n"
#endif /* OPENSSH_VERSION >= 6.7 */
"\n"
"AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES\n"
"AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT\n"
"AcceptEnv LC_IDENTIFICATION LC_ALL LC_LIBSSH\n"
"\n"
"PidFile %s\n";
size_t sftp_sl_size = ARRAY_SIZE(sftp_server_locations);
const char *sftp_server;
size_t i;
int rc;
snprintf(sshd_path,
sizeof(sshd_path),
"%s/sshd",
s->socket_dir);
rc = mkdir(sshd_path, 0755);
assert_return_code(rc, errno);
snprintf(ed25519_hostkey,
sizeof(ed25519_hostkey),
"%s/sshd/ssh_host_ed25519_key",
s->socket_dir);
torture_write_file(ed25519_hostkey,
torture_get_testkey(SSH_KEYTYPE_ED25519, 0, 0));
snprintf(dsa_hostkey,
sizeof(dsa_hostkey),
"%s/sshd/ssh_host_dsa_key",
s->socket_dir);
torture_write_file(dsa_hostkey, torture_get_testkey(SSH_KEYTYPE_DSS, 0, 0));
snprintf(rsa_hostkey,
sizeof(rsa_hostkey),
"%s/sshd/ssh_host_rsa_key",
s->socket_dir);
torture_write_file(rsa_hostkey, torture_get_testkey(SSH_KEYTYPE_RSA, 0, 0));
snprintf(ecdsa_hostkey,
sizeof(ecdsa_hostkey),
"%s/sshd/ssh_host_ecdsa_key",
s->socket_dir);
torture_write_file(ecdsa_hostkey,
torture_get_testkey(SSH_KEYTYPE_ECDSA, 521, 0));
assert_non_null(s->socket_dir);
sftp_server = getenv("TORTURE_SFTP_SERVER");
if (sftp_server == NULL) {
for (i = 0; i < sftp_sl_size; i++) {
sftp_server = sftp_server_locations[i];
rc = lstat(sftp_server, &sb);
if (rc == 0) {
break;
}
}
}
assert_non_null(sftp_server);
snprintf(sshd_config, sizeof(sshd_config),
config_string,
ed25519_hostkey,
dsa_hostkey,
rsa_hostkey,
ecdsa_hostkey,
sftp_server,
s->srv_pidfile);
torture_write_file(s->srv_config, sshd_config);
}
void torture_setup_sshd_server(void **state)
{
struct torture_state *s;
char sshd_start_cmd[1024];
int rc;
torture_setup_socket_dir(state);
torture_setup_create_sshd_config(state);
/* Set the default interface for the server */
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
setenv("PAM_WRAPPER", "1", 1);
s = *state;
snprintf(sshd_start_cmd, sizeof(sshd_start_cmd),
"/usr/sbin/sshd -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log",
s->srv_config, s->socket_dir, s->socket_dir);
rc = system(sshd_start_cmd);
assert_return_code(rc, errno);
/* Give the process some time to start */
usleep(100 * 1000);
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1);
unsetenv("PAM_WRAPPER");
}
void torture_teardown_socket_dir(void **state)
{
struct torture_state *s = *state;
char *env = getenv("TORTURE_SKIP_CLEANUP");
int rc;
if (env != NULL && env[0] == '1') {
fprintf(stderr, "[ TORTURE ] >>> Skipping cleanup of %s\n", s->socket_dir);
} else {
rc = torture_rmdirs(s->socket_dir);
if (rc < 0) {
fprintf(stderr,
"torture_rmdirs(%s) failed: %s",
s->socket_dir,
strerror(errno));
}
}
free(s->socket_dir);
free(s->pcap_file);
free(s->srv_pidfile);
free(s);
}
void torture_teardown_sshd_server(void **state)
{
struct torture_state *s = *state;
int rc;
rc = torture_terminate_process(s->srv_pidfile);
if (rc != 0) {
fprintf(stderr, "XXXXXX Failed to terminate sshd\n");
}
torture_teardown_socket_dir(state);
}
int torture_libssh_verbosity(void){
return verbosity;
}
@@ -685,8 +958,29 @@ void _torture_filter_tests(UnitTest *tests, size_t ntests){
}
}
#endif /* _WIN32 */
void torture_write_file(const char *filename, const char *data){
int fd;
int rc;
assert_non_null(filename);
assert_true(filename[0] != '\0');
assert_non_null(data);
fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0600);
assert_true(fd >= 0);
rc = write(fd, data, strlen(data));
assert_int_equal(rc, strlen(data));
close(fd);
}
int main(int argc, char **argv) {
struct argument_s arguments;
char *env = getenv("LIBSSH_VERBOSITY");
arguments.verbose=0;
arguments.pattern=NULL;
@@ -694,6 +988,12 @@ int main(int argc, char **argv) {
verbosity=arguments.verbose;
pattern=arguments.pattern;
if (verbosity == 0 && env != NULL && env[0] != '\0') {
if (env[0] > '0' && env[0] < '9') {
verbosity = atoi(env);
}
}
return torture_run_tests();
}

View File

@@ -46,6 +46,10 @@
assert_true(code >= 0)
#endif /* assert_return_code */
#define TORTURE_SSH_SERVER "127.0.0.10"
#define TORTURE_SSH_USER_ALICE "alice"
#define TORTURE_TESTKEY_PASSWORD "libssh-rocks"
/* Used by main to communicate with parse_opt. */
@@ -60,11 +64,24 @@ struct torture_sftp {
char *testdir;
};
struct torture_state {
char *socket_dir;
char *pcap_file;
char *srv_pidfile;
char *srv_config;
};
#ifndef ZERO_STRUCT
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
#endif
void torture_cmdline_parse(int argc, char **argv, struct argument_s *arguments);
int torture_rmdirs(const char *path);
int torture_isdir(const char *path);
int torture_terminate_process(const char *pidfile);
/*
* Returns the verbosity level asked by user
*/
@@ -94,6 +111,12 @@ void torture_write_file(const char *filename, const char *data);
#define torture_filter_tests(tests) _torture_filter_tests(tests, sizeof(tests) / sizeof(tests)[0])
void _torture_filter_tests(UnitTest *tests, size_t ntests);
void torture_setup_socket_dir(void **state);
void torture_setup_sshd_server(void **state);
void torture_teardown_socket_dir(void **state);
void torture_teardown_sshd_server(void **state);
/*
* This function must be defined in every unit test file.
*/

View File

@@ -10,6 +10,7 @@ add_cmocka_test(torture_misc torture_misc.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_options torture_options.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_isipaddr torture_isipaddr.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_pki_ed25519 torture_pki_ed25519.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_packet_filter torture_packet_filter.c ${TORTURE_LIBRARY})
if (UNIX AND NOT WIN32)
# requires ssh-keygen
add_cmocka_test(torture_keyfiles torture_keyfiles.c ${TORTURE_LIBRARY})

View File

@@ -0,0 +1,500 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2018 by 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.
*/
/*
* This test checks if the messages accepted by the packet filter were intented
* to be accepted.
*
* The process consists in 2 steps:
* - Try the filter with a message type in an arbitrary state
* - If the message is accepted by the filter, check if the message is in the
* set of accepted states.
*
* Only the values selected by the flag (COMPARE_*) are considered.
* */
#include "config.h"
#define LIBSSH_STATIC
#include "torture.h"
#include "libssh/priv.h"
#include "libssh/libssh.h"
#include "libssh/session.h"
#include "libssh/auth.h"
#include "libssh/ssh2.h"
#include "libssh/packet.h"
#include "packet.c"
#define COMPARE_SESSION_STATE 1
#define COMPARE_ROLE (1 << 1)
#define COMPARE_DH_STATE (1 << 2)
#define COMPARE_AUTH_STATE (1 << 3)
#define COMPARE_GLOBAL_REQ_STATE (1 << 4)
#define SESSION_STATE_COUNT 11
#define DH_STATE_COUNT 4
#define AUTH_STATE_COUNT 14
#define GLOBAL_REQ_STATE_COUNT 5
#define MESSAGE_COUNT 100 // from 1 to 100
#define ROLE_CLIENT 0
#define ROLE_SERVER 1
/*
* This is the list of currently unfiltered message types.
* Only unrecognized types should be in this list.
* */
static uint8_t unfiltered[] = {
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
22, 23, 24, 25, 26, 27, 28, 29,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
54, 55, 56, 57, 58, 59,
62,
67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
83, 84, 85, 86, 87, 88, 89,
};
typedef struct global_state_st {
/* If the bit in this flag is zero, the corresponding state is not
* considered, working as a wildcard (meaning any value is accepted) */
uint32_t flags;
uint8_t role;
enum ssh_session_state_e session;
enum ssh_dh_state_e dh;
enum ssh_auth_state_e auth;
enum ssh_channel_request_state_e global_req;
} global_state;
static int cmp_state(const void *e1, const void *e2)
{
global_state *s1 = (global_state *) e1;
global_state *s2 = (global_state *) e2;
/* Compare role (client == 0 or server == 1)*/
if (s1->role < s2->role) {
return -1;
}
else if (s1->role > s2->role) {
return 1;
}
/* Compare session state */
if (s1->session < s2->session) {
return -1;
}
else if (s1->session > s2->session) {
return 1;
}
/* Compare DH state */
if (s1->dh < s2->dh) {
return -1;
}
else if (s1->dh > s2->dh) {
return 1;
}
/* Compare auth */
if (s1->auth < s2->auth) {
return -1;
}
else if (s1->auth > s2->auth) {
return 1;
}
/* Compare global_req */
if (s1->global_req < s2->global_req) {
return -1;
}
else if (s1->global_req > s2->global_req) {
return 1;
}
/* If all equal, they are equal */
return 0;
}
static int cmp_state_search(const void *key, const void *array_element)
{
global_state *s1 = (global_state *) key;
global_state *s2 = (global_state *) array_element;
int result = 0;
if (s2->flags & COMPARE_ROLE) {
/* Compare role (client == 0 or server == 1)*/
if (s1->role < s2->role) {
return -1;
}
else if (s1->role > s2->role) {
return 1;
}
}
if (s2->flags & COMPARE_SESSION_STATE) {
/* Compare session state */
if (s1->session < s2->session) {
result = -1;
goto end;
}
else if (s1->session > s2->session) {
result = 1;
goto end;
}
}
if (s2->flags & COMPARE_DH_STATE) {
/* Compare DH state */
if (s1->dh < s2->dh) {
result = -1;
goto end;
}
else if (s1->dh > s2->dh) {
result = 1;
goto end;
}
}
if (s2->flags & COMPARE_AUTH_STATE) {
/* Compare auth */
if (s1->auth < s2->auth) {
result = -1;
goto end;
}
else if (s1->auth > s2->auth) {
result = 1;
goto end;
}
}
if (s2->flags & COMPARE_GLOBAL_REQ_STATE) {
/* Compare global_req */
if (s1->global_req < s2->global_req) {
result = -1;
goto end;
}
else if (s1->global_req > s2->global_req) {
result = 1;
goto end;
}
}
end:
return result;
}
static int is_state_accepted(global_state *tested, global_state *accepted,
int accepted_len)
{
global_state *found = NULL;
found = bsearch(tested, accepted, accepted_len, sizeof(global_state),
cmp_state_search);
if (found != NULL) {
return 1;
}
return 0;
}
static int cmp_uint8(const void *i, const void *j)
{
uint8_t e1 = *((uint8_t *)i);
uint8_t e2 = *((uint8_t *)j);
if (e1 < e2) {
return -1;
}
else if (e1 > e2) {
return 1;
}
return 0;
}
static int check_unfiltered(uint8_t msg_type)
{
uint8_t *found;
found = bsearch(&msg_type, unfiltered, sizeof(unfiltered)/sizeof(uint8_t),
sizeof(uint8_t), cmp_uint8);
if (found != NULL) {
return 1;
}
return 0;
}
static void torture_packet_filter_check_unfiltered(void **state)
{
ssh_session session;
int role_c;
int auth_c;
int session_c;
int dh_c;
int global_req_c;
uint8_t msg_type;
enum ssh_packet_filter_result_e rc;
int in_unfiltered;
session = ssh_new();
for (msg_type = 1; msg_type <= MESSAGE_COUNT; msg_type++) {
session->in_packet.type = msg_type;
for (role_c = 0; role_c < 2; role_c++) {
session->server = role_c;
for (session_c = 0; session_c < SESSION_STATE_COUNT; session_c++) {
session->session_state = session_c;
for (dh_c = 0; dh_c < DH_STATE_COUNT; dh_c++) {
session->dh_handshake_state = dh_c;
for (auth_c = 0; auth_c < AUTH_STATE_COUNT; auth_c++) {
session->auth_state = auth_c;
for (global_req_c = 0;
global_req_c < GLOBAL_REQ_STATE_COUNT;
global_req_c++)
{
session->global_req_state = global_req_c;
rc = ssh_packet_incoming_filter(session);
if (rc == SSH_PACKET_UNKNOWN) {
in_unfiltered = check_unfiltered(msg_type);
if (!in_unfiltered) {
fprintf(stderr, "Message type %d UNFILTERED "
"in state: role %d, session %d, dh %d, auth %d\n",
msg_type, role_c, session_c, dh_c, auth_c);
}
assert_int_equal(in_unfiltered, 1);
}
else {
in_unfiltered = check_unfiltered(msg_type);
if (in_unfiltered) {
fprintf(stderr, "Message type %d NOT UNFILTERED "
"in state: role %d, session %d, dh %d, auth %d\n",
msg_type, role_c, session_c, dh_c, auth_c);
}
assert_int_equal(in_unfiltered, 0);
}
}
}
}
}
}
}
ssh_free(session);
}
static int check_message_in_all_states(global_state accepted[],
int accepted_count, uint8_t msg_type)
{
ssh_session session;
int role_c;
int auth_c;
int session_c;
int dh_c;
int global_req_c;
enum ssh_packet_filter_result_e rc;
int in_accepted;
global_state key;
session = ssh_new();
/* Sort the accepted array so that the elements can be searched using
* bsearch */
qsort(accepted, accepted_count, sizeof(global_state), cmp_state);
session->in_packet.type = msg_type;
for (role_c = 0; role_c < 2; role_c++) {
session->server = role_c;
key.role = role_c;
for (session_c = 0; session_c < SESSION_STATE_COUNT; session_c++) {
session->session_state = session_c;
key.session = session_c;
for (dh_c = 0; dh_c < DH_STATE_COUNT; dh_c++) {
session->dh_handshake_state = dh_c;
key.dh = dh_c;
for (auth_c = 0; auth_c < AUTH_STATE_COUNT; auth_c++) {
session->auth_state = auth_c;
key.auth = auth_c;
for (global_req_c = 0;
global_req_c < GLOBAL_REQ_STATE_COUNT;
global_req_c++)
{
session->global_req_state = global_req_c;
key.global_req = global_req_c;
rc = ssh_packet_incoming_filter(session);
if (rc == SSH_PACKET_ALLOWED) {
in_accepted = is_state_accepted(&key, accepted,
accepted_count);
if (!in_accepted) {
fprintf(stderr, "Message type %d ALLOWED "
"in state: role %d, session %d, dh %d, auth %d\n",
msg_type, role_c, session_c, dh_c, auth_c);
}
assert_int_equal(in_accepted, 1);
}
else if (rc == SSH_PACKET_DENIED) {
in_accepted = is_state_accepted(&key, accepted, accepted_count);
if (in_accepted) {
fprintf(stderr, "Message type %d DENIED "
"in state: role %d, session %d, dh %d, auth %d\n",
msg_type, role_c, session_c, dh_c, auth_c);
}
assert_int_equal(in_accepted, 0);
}
else {
fprintf(stderr, "Message type %d UNFILTERED "
"in state: role %d, session %d, dh %d, auth %d\n",
msg_type, role_c, session_c, dh_c, auth_c);
}
}
}
}
}
}
ssh_free(session);
return 0;
}
static void torture_packet_filter_check_auth_success(void **state)
{
int rc;
global_state accepted[] = {
{
.flags = (COMPARE_SESSION_STATE |
COMPARE_ROLE |
COMPARE_AUTH_STATE |
COMPARE_DH_STATE),
.role = ROLE_CLIENT,
.session = SSH_SESSION_STATE_AUTHENTICATING,
.dh = DH_STATE_FINISHED,
.auth = SSH_AUTH_STATE_PUBKEY_AUTH_SENT,
},
{
.flags = (COMPARE_SESSION_STATE |
COMPARE_ROLE |
COMPARE_AUTH_STATE |
COMPARE_DH_STATE),
.role = ROLE_CLIENT,
.session = SSH_SESSION_STATE_AUTHENTICATING,
.dh = DH_STATE_FINISHED,
.auth = SSH_AUTH_STATE_PASSWORD_AUTH_SENT,
},
{
.flags = (COMPARE_SESSION_STATE |
COMPARE_ROLE |
COMPARE_AUTH_STATE |
COMPARE_DH_STATE),
.role = ROLE_CLIENT,
.session = SSH_SESSION_STATE_AUTHENTICATING,
.dh = DH_STATE_FINISHED,
.auth = SSH_AUTH_STATE_GSSAPI_MIC_SENT,
},
{
.flags = (COMPARE_SESSION_STATE |
COMPARE_ROLE |
COMPARE_AUTH_STATE |
COMPARE_DH_STATE),
.role = ROLE_CLIENT,
.session = SSH_SESSION_STATE_AUTHENTICATING,
.dh = DH_STATE_FINISHED,
.auth = SSH_AUTH_STATE_KBDINT_SENT,
},
{
.flags = (COMPARE_SESSION_STATE |
COMPARE_ROLE |
COMPARE_AUTH_STATE |
COMPARE_DH_STATE),
.role = ROLE_CLIENT,
.session = SSH_SESSION_STATE_AUTHENTICATING,
.dh = DH_STATE_FINISHED,
.auth = SSH_AUTH_STATE_AUTH_NONE_SENT,
}
};
int accepted_count = 5;
/* Unused */
(void) state;
rc = check_message_in_all_states(accepted, accepted_count,
SSH2_MSG_USERAUTH_SUCCESS);
assert_int_equal(rc, 0);
}
static void torture_packet_filter_check_channel_open(void **state)
{
int rc;
/* The only condition to accept a CHANNEL_OPEN is to be authenticated */
global_state accepted[] = {
{
.flags = COMPARE_SESSION_STATE,
.session = SSH_SESSION_STATE_AUTHENTICATED,
}
};
int accepted_count = 1;
/* Unused */
(void) state;
rc = check_message_in_all_states(accepted, accepted_count,
SSH2_MSG_CHANNEL_OPEN);
assert_int_equal(rc, 0);
}
int torture_run_tests(void)
{
int rc;
UnitTest tests[] = {
unit_test(torture_packet_filter_check_auth_success),
unit_test(torture_packet_filter_check_channel_open),
unit_test(torture_packet_filter_check_unfiltered),
};
ssh_init();
torture_filter_tests(tests);
rc = run_tests(tests);
ssh_finalize();
return rc;
}