[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Missing signed-off for pkg chacha20 patches
[Thread Prev] | [Thread Next]
- Subject: Re: Missing signed-off for pkg chacha20 patches
- From: Jon Simons <jon@xxxxxxxxxxxxx>
- Reply-to: libssh@xxxxxxxxxx
- Date: Mon, 18 Jun 2018 16:58:00 -0700
- To: Andreas Schneider <asn@xxxxxxxxxxxxxx>, libssh@xxxxxxxxxx
Hi Andreas, Attached is another re-roll which now includes 3 more changes to get the pkd tests passing in more environments: * specify HostKeyAlgorithms for OpenSSH clients (in pkd tests) * specify PubkeyAcceptedTypes for OpenSSH clients (in pkd tests) * emit an error message for OpenSSH clients < 7.0 (in pkd tests) With these three additions I observe the pkd tests passing in full with a Fedora 26 environment. These introduce a requirement that the OpenSSH client be at least version 7.0 in order to pass. The patches should apply cleanly to current master: 0940b0f29b4fef86e56dffdd13d978f9692b78fc Please let me know if I can provide the patches in another format or make any other changes. Thanks, -Jon
From aa4ade54f781eec6362a6d57f66243d27c220dd4 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Thu, 24 May 2018 19:49:46 -0700 Subject: [PATCH 01/30] pkd: fix missing config.h #include Ensure to include config.h so that the `HAVE_DSA` value is properly set when building the pkd tests. Introduced with 778652460f7cceb3e760964a890ffd99ec8230e7, Testing done: with this change, the `pkd_hello` test is passing on an OpenSSL 1.1.0 build for me. Previously it would fail pubkey exchange early on for DSA- and ECDSA-type host keys. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/pkd_daemon.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pkd/pkd_daemon.h b/tests/pkd/pkd_daemon.h index 3107ed1..7bdf894 100644 --- a/tests/pkd/pkd_daemon.h +++ b/tests/pkd/pkd_daemon.h @@ -8,6 +8,8 @@ #ifndef __PKD_DAEMON_H__ #define __PKD_DAEMON_H__ +#include "config.h" + enum pkd_hostkey_type_e { PKD_RSA, #ifdef HAVE_DSA -- 2.1.4 From 50bf63f4286ae620b3f4a04208b390d143526875 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 25 May 2018 03:00:33 -0700 Subject: [PATCH 02/30] ecdh: fix SSH_MSG_KEXDH_REPLY for libcrypto Ensure to provide the `ssh_string` pubkey blob to the buffer packing routine when computing the SSH_MSG_KEXDH_REPLY message, rather than the new `ssh_key` type. Introduced with 16217454d576511f37f39c3169963629f9d5082f. Testing done: with this change, `pkd_hello` test is passing on an OpenSSL 1.1.0 build for me. Previously it would segfault during pubkey exchange with "ecdh-sha2-nistp256". Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- src/ecdh_crypto.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ecdh_crypto.c b/src/ecdh_crypto.c index 041e6c0..24f21c0 100644 --- a/src/ecdh_crypto.c +++ b/src/ecdh_crypto.c @@ -206,6 +206,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ /* SSH host keys (rsa,dsa,ecdsa) */ ssh_key privkey; ssh_string sig_blob = NULL; + ssh_string pubkey_blob = NULL; int curve; int len; int rc; @@ -289,14 +290,22 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ return SSH_ERROR; } + rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Could not export server public key"); + ssh_string_free(sig_blob); + return SSH_ERROR; + } + rc = ssh_buffer_pack(session->out_buffer, "bSSS", SSH2_MSG_KEXDH_REPLY, - session->next_crypto->server_pubkey, /* host's pubkey */ + pubkey_blob, /* host's pubkey */ q_s_string, /* ecdh public key */ sig_blob); /* signature blob */ ssh_string_free(sig_blob); + ssh_string_free(pubkey_blob); if (rc != SSH_OK) { ssh_set_error_oom(session); -- 2.1.4 From 41dba131d58e261e6477f183323222b980a8c95b Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 25 May 2018 03:29:06 -0700 Subject: [PATCH 03/30] ecdh: fix SSH_MSG_KEXDH_REPLY for libgcrypt Ensure to provide the `ssh_string` pubkey blob to the buffer packing routine when computing the SSH_MSG_KEXDH_REPLY message, rather than the new `ssh_key` type. Introduced with 16217454d576511f37f39c3169963629f9d5082f. Testing done: with this change, the `pkd_hello` test is passing on a libgcrypt build for me. Previously it would segfault during pubkey exchange with "ecdh-sha2-nistp256". Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- src/ecdh_gcrypt.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ecdh_gcrypt.c b/src/ecdh_gcrypt.c index e4b73dc..7bbccc2 100644 --- a/src/ecdh_gcrypt.c +++ b/src/ecdh_gcrypt.c @@ -268,6 +268,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) { /* SSH host keys (rsa,dsa,ecdsa) */ ssh_key privkey; ssh_string sig_blob = NULL; + ssh_string pubkey_blob = NULL; int rc = SSH_ERROR; const char *curve = NULL; @@ -333,14 +334,22 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) { goto out; } + rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Could not export server public key"); + ssh_string_free(sig_blob); + goto out; + } + rc = ssh_buffer_pack(session->out_buffer, "bSSS", SSH2_MSG_KEXDH_REPLY, - session->next_crypto->server_pubkey, /* host's pubkey */ + pubkey_blob, /* host's pubkey */ q_s_string, /* ecdh public key */ sig_blob); /* signature blob */ ssh_string_free(sig_blob); + ssh_string_free(pubkey_blob); if (rc != SSH_OK) { ssh_set_error_oom(session); -- 2.1.4 From b9661829539463f4ca1844d7f455927a8847a968 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 25 May 2018 03:39:21 -0700 Subject: [PATCH 04/30] ecdh: fix SSH_MSG_KEXDH_REPLY for mbedTLS Ensure to provide the `ssh_string` pubkey blob to the buffer packing routine when computing the SSH_MSG_KEXDH_REPLY message, rather than the new `ssh_key` type. Introduced with 16217454d576511f37f39c3169963629f9d5082f. Testing done: with this change, the `pkd_hello` test is passing on a mbedTLS build for me. Previously it would segfault during pubkey exchange with "ecdh-sha2-nistp256". Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- src/ecdh_mbedcrypto.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/ecdh_mbedcrypto.c b/src/ecdh_mbedcrypto.c index d4e7a77..aebc7ba 100644 --- a/src/ecdh_mbedcrypto.c +++ b/src/ecdh_mbedcrypto.c @@ -181,6 +181,7 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) mbedtls_ecp_group grp; ssh_key privkey = NULL; ssh_string sig_blob = NULL; + ssh_string pubkey_blob = NULL; int rc; mbedtls_ecp_group_id curve; @@ -256,12 +257,21 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet) goto out; } + rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Could not export server public key"); + ssh_string_free(sig_blob); + goto out; + } + rc = ssh_buffer_pack(session->out_buffer, "bSSS", - SSH2_MSG_KEXDH_REPLY, session->next_crypto->server_pubkey, - q_s_string, - sig_blob); + SSH2_MSG_KEXDH_REPLY, + pubkey_blob, /* host's pubkey */ + q_s_string, /* ecdh public key */ + sig_blob); /* signature blob */ ssh_string_free(sig_blob); + ssh_string_free(pubkey_blob); if (rc != SSH_OK) { ssh_set_error_oom(session); -- 2.1.4 From 87b468bf41dafb2dfffbf6d8291ce5cc6b2e05bb Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 25 May 2018 03:42:59 -0700 Subject: [PATCH 05/30] tests: fix -Wunused-function warning in torture_pki_ecdsa.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wrap some function definitions with `HAVE_LIBCRYPTO` ifdefs to match their usages in `torture_run_tests`. Fixes this warning I observe when building locally: torture_pki_ecdsa.c:341:13: warning: ‘torture_pki_ecdsa_write_privkey’ defined but not used [-Wunused-function] Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/unittests/torture_pki_ecdsa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unittests/torture_pki_ecdsa.c b/tests/unittests/torture_pki_ecdsa.c index 6587a60..e9939d5 100644 --- a/tests/unittests/torture_pki_ecdsa.c +++ b/tests/unittests/torture_pki_ecdsa.c @@ -338,6 +338,7 @@ static void torture_pki_generate_key_ecdsa(void **state) ssh_free(session); } +#ifdef HAVE_LIBCRYPTO static void torture_pki_ecdsa_write_privkey(void **state) { ssh_key origkey; @@ -412,6 +413,7 @@ static void torture_pki_ecdsa_write_privkey(void **state) ssh_key_free(origkey); ssh_key_free(privkey); } +#endif /* HAVE_LIBCRYPTO */ static void torture_pki_ecdsa_name(void **state, const char *expected_name) { -- 2.1.4 From c7b3cdda8f2d50c035b35a505abd29d50415c95d Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 25 May 2018 03:52:25 -0700 Subject: [PATCH 06/30] dh: fix `ssh_get_pubkey_hash` indentation Fix `ssh_get_pubkey_hash` indentation to use softabs with 4 spaces. No change in behavior. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- src/dh.c | 75 ++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/src/dh.c b/src/dh.c index d2ddfab..733c6e7 100644 --- a/src/dh.c +++ b/src/dh.c @@ -980,51 +980,50 @@ error: * @deprecated Use ssh_get_publickey_hash() */ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) { - ssh_key pubkey = NULL; - ssh_string pubkey_blob = NULL; - MD5CTX ctx; - unsigned char *h; - int rc; + ssh_key pubkey = NULL; + ssh_string pubkey_blob = NULL; + MD5CTX ctx; + unsigned char *h; + int rc; - if (session == NULL || hash == NULL) { - return SSH_ERROR; - } - *hash = NULL; - if (session->current_crypto == NULL || - session->current_crypto->server_pubkey == NULL){ - ssh_set_error(session,SSH_FATAL,"No current cryptographic context"); - return SSH_ERROR; - } + if (session == NULL || hash == NULL) { + return SSH_ERROR; + } + *hash = NULL; + if (session->current_crypto == NULL || + session->current_crypto->server_pubkey == NULL) { + ssh_set_error(session,SSH_FATAL,"No current cryptographic context"); + return SSH_ERROR; + } - h = calloc(MD5_DIGEST_LEN, sizeof(unsigned char)); - if (h == NULL) { - return SSH_ERROR; - } + h = calloc(MD5_DIGEST_LEN, sizeof(unsigned char)); + if (h == NULL) { + return SSH_ERROR; + } - ctx = md5_init(); - if (ctx == NULL) { - SAFE_FREE(h); - return SSH_ERROR; - } + ctx = md5_init(); + if (ctx == NULL) { + SAFE_FREE(h); + return SSH_ERROR; + } - rc = ssh_get_server_publickey(session, &pubkey); - if (rc != 0) { - SAFE_FREE(h); - return SSH_ERROR; - } + rc = ssh_get_server_publickey(session, &pubkey); + if (rc != 0) { + SAFE_FREE(h); + return SSH_ERROR; + } - rc = ssh_pki_export_pubkey_blob(pubkey, - &pubkey_blob); - ssh_key_free(pubkey); - if (rc != 0) { - } - md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob)); - ssh_string_free(pubkey_blob); - md5_final(h, ctx); + rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob); + ssh_key_free(pubkey); + if (rc != 0) { + } + md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob)); + ssh_string_free(pubkey_blob); + md5_final(h, ctx); - *hash = h; + *hash = h; - return MD5_DIGEST_LEN; + return MD5_DIGEST_LEN; } /** -- 2.1.4 From 518a683bfaeb350e334d22980b486e67411090a1 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 25 May 2018 03:56:54 -0700 Subject: [PATCH 07/30] dh: fix two leaks in `ssh_get_pubkey_hash` Fix two memory leaks in `ssh_get_pubkey_hash` for some error paths. The local `h` buffer and `ctx` MD5 context each must be free'd for the SSH_ERROR cases. Introduced with 16217454d576511f37f39c3169963629f9d5082f. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- src/dh.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/dh.c b/src/dh.c index 733c6e7..c3de5b9 100644 --- a/src/dh.c +++ b/src/dh.c @@ -1008,15 +1008,20 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) { } rc = ssh_get_server_publickey(session, &pubkey); - if (rc != 0) { + if (rc != SSH_OK) { + md5_final(h, ctx); SAFE_FREE(h); return SSH_ERROR; } rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob); ssh_key_free(pubkey); - if (rc != 0) { + if (rc != SSH_OK) { + md5_final(h, ctx); + SAFE_FREE(h); + return SSH_ERROR; } + md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob)); ssh_string_free(pubkey_blob); md5_final(h, ctx); -- 2.1.4 From 43a0d359fd558de656048ca5c4aad6fd08c6488a Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 25 May 2018 04:35:04 -0700 Subject: [PATCH 08/30] pkd: add_test pkd_hello_i1 for `make test` Add an entry for a `pkd_hello_i1` test which runs one iteration through each of the pkd algorithm combinations. Testing done: now `make test` will run `pkd_hello -i1` which completes in ~25 seconds on my local machine. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/pkd/CMakeLists.txt b/tests/pkd/CMakeLists.txt index 0738434..ff23ba9 100644 --- a/tests/pkd/CMakeLists.txt +++ b/tests/pkd/CMakeLists.txt @@ -32,4 +32,12 @@ set(pkd_libs add_executable(pkd_hello ${pkd_hello_src}) target_link_libraries(pkd_hello ${pkd_libs}) +# +# pkd_hello_i1 runs only one iteration per algorithm combination for +# sake of speeding up overall test run time. More iterations can be +# specified with `-i` and may be helpful for chasing down bugs that +# are not 100% reproducible. +# +add_test(pkd_hello_i1 ${CMAKE_CURRENT_BINARY_DIR}/pkd_hello -i1) + endif (WITH_SERVER AND UNIX AND NOT WIN32) -- 2.1.4 From fb0be6ee04b2e7724cb4b595666d7dd12d9f4a77 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 25 May 2018 06:09:03 -0700 Subject: [PATCH 09/30] pkd: run with SOCKET_WRAPPER_LIBRARY Use the socket_wrapper preload shim when running the `pkd_hello` test with `make test`. The end goal here is to get this test running alongside normal tests in regular CI. Changes to do this: * Configure PKD_ENVIRONMENT for the `pkd_hello_i1` test in the CMakeLists.txt file. * Add a `--socket-wrapper-dir|-w` flag that is used to opt-in to initializing a SOCKET_WRAPPER_DIR as expected by the socket_wrapper library. A runtime flag is used here to make it easy to run `pkd_hello` with the socket_wrapper library while avoiding a hard dependency. Testing done: observed socker_wrapper in effect with `strace`; running `make test` uses the wrapper correctly on my local machine. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/CMakeLists.txt | 14 +++++++- tests/pkd/pkd_daemon.h | 4 +++ tests/pkd/pkd_hello.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/tests/pkd/CMakeLists.txt b/tests/pkd/CMakeLists.txt index ff23ba9..a07021e 100644 --- a/tests/pkd/CMakeLists.txt +++ b/tests/pkd/CMakeLists.txt @@ -38,6 +38,18 @@ target_link_libraries(pkd_hello ${pkd_libs}) # specified with `-i` and may be helpful for chasing down bugs that # are not 100% reproducible. # -add_test(pkd_hello_i1 ${CMAKE_CURRENT_BINARY_DIR}/pkd_hello -i1) +add_test(pkd_hello_i1 ${CMAKE_CURRENT_BINARY_DIR}/pkd_hello -i1 -w /tmp/pkd_socket_wrapper_XXXXXX) + +# +# Configure environment for cwrap socket wrapper. +# +find_package(socket_wrapper 1.1.5 REQUIRED) +if (OSX) + set(PKD_ENVIRONMENT "DYLD_FORCE_FLAT_NAMESPACE=1;DYLD_INSERT_LIBRARIES=${SOCKET_WRAPPER_LIBRARY}") +else () + set(PKD_ENVIRONMENT "LD_PRELOAD=${SOCKET_WRAPPER_LIBRARY}") +endif () +message(STATUS "PKD_ENVIRONMENT=${PKD_ENVIRONMENT}") +set_property(TEST pkd_hello_i1 PROPERTY ENVIRONMENT ${PKD_ENVIRONMENT}) endif (WITH_SERVER AND UNIX AND NOT WIN32) diff --git a/tests/pkd/pkd_daemon.h b/tests/pkd/pkd_daemon.h index 7bdf894..abb07ac 100644 --- a/tests/pkd/pkd_daemon.h +++ b/tests/pkd/pkd_daemon.h @@ -32,6 +32,10 @@ struct pkd_daemon_args { const char *testname; const char *testmatch; unsigned int iterations; + + struct { + const char *mkdtemp_str; + } socket_wrapper; } opts; }; diff --git a/tests/pkd/pkd_hello.c b/tests/pkd/pkd_hello.c index e0c0cbf..951bd7b 100644 --- a/tests/pkd/pkd_hello.c +++ b/tests/pkd/pkd_hello.c @@ -1,13 +1,14 @@ /* * pkd_hello.c -- * - * (c) 2014, 2017 Jon Simons <jon@xxxxxxxxxxxxx> + * (c) 2014, 2017-2018 Jon Simons <jon@xxxxxxxxxxxxx> */ #include "config.h" #include <setjmp.h> // for cmocka #include <stdarg.h> // for cmocka #include <stdio.h> +#include <stdlib.h> #include <unistd.h> // for cmocka #include <cmocka.h> @@ -51,6 +52,8 @@ static struct argp_option options[] = { "Run each test for the given number of iterations (default is 10)", 0 }, { "match", 'm', "testmatch", 0, "Run all tests with the given string", 0 }, + { "socket-wrapper-dir", 'w', "<mkdtemp-template>", 0, + "Run in socket-wrapper mode using the given mkdtemp directory template", 0 }, { "stdout", 'o', NULL, 0, "Emit pkd stdout messages", 0 }, { "test", 't', "testname", 0, @@ -87,6 +90,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { case 'v': pkd_dargs.opts.libssh_log_level += 1; break; + case 'w': + pkd_dargs.opts.socket_wrapper.mkdtemp_str = arg; + break; default: return ARGP_ERR_UNKNOWN; } @@ -651,6 +657,75 @@ static int pkd_run_tests(void) { return rc; } +static int pkd_init_socket_wrapper(void) { + int rc = 0; + char *mkdtemp_str = NULL; + + if (pkd_dargs.opts.socket_wrapper.mkdtemp_str == NULL) { + goto out; + } + + mkdtemp_str = strdup(pkd_dargs.opts.socket_wrapper.mkdtemp_str); + if (mkdtemp_str == NULL) { + fprintf(stderr, "pkd_init_socket_wrapper strdup failed\n"); + goto errstrdup; + } + pkd_dargs.opts.socket_wrapper.mkdtemp_str = mkdtemp_str; + + if (mkdtemp(mkdtemp_str) == NULL) { + fprintf(stderr, "pkd_init_socket_wrapper mkdtemp '%s' failed\n", mkdtemp_str); + goto errmkdtemp; + } + + if (setenv("SOCKET_WRAPPER_DIR", mkdtemp_str, 1) != 0) { + fprintf(stderr, "pkd_init_socket_wrapper setenv failed\n"); + goto errsetenv; + } + + goto out; +errsetenv: +errmkdtemp: + free(mkdtemp_str); +errstrdup: + rc = -1; +out: + return rc; +} + +static int pkd_rmfiles(const char *path) { + char bin[1024] = { 0 }; + snprintf(&bin[0], sizeof(bin), "rm -f %s/*", path); + return system_checked(bin); +} + +static int pkd_cleanup_socket_wrapper(void) { + int rc = 0; + + if (pkd_dargs.opts.socket_wrapper.mkdtemp_str == NULL) { + goto out; + } + + /* clean up socket-wrapper unix domain sockets */ + if (pkd_rmfiles(pkd_dargs.opts.socket_wrapper.mkdtemp_str) != 0) { + fprintf(stderr, "pkd_cleanup_socket_wrapper pkd_rmfiles '%s' failed\n", + pkd_dargs.opts.socket_wrapper.mkdtemp_str); + goto errrmfiles; + } + + if (rmdir(pkd_dargs.opts.socket_wrapper.mkdtemp_str) != 0) { + fprintf(stderr, "pkd_cleanup_socket_wrapper rmdir '%s' failed\n", + pkd_dargs.opts.socket_wrapper.mkdtemp_str); + goto errrmdir; + } + + goto out; +errrmdir: +errrmfiles: + rc = -1; +out: + return rc; +} + int main(int argc, char **argv) { int i = 0; int rc = 0; @@ -670,6 +745,12 @@ int main(int argc, char **argv) { (void) argc; (void) argv; #endif /* HAVE_ARGP_H */ + rc = pkd_init_socket_wrapper(); + if (rc != 0) { + fprintf(stderr, "pkd_init_socket_wrapper failed: %d\n", rc); + goto out_finalize; + } + if (pkd_dargs.opts.list != 0) { while (testmap[i].testname != NULL) { printf("%s\n", testmap[i++].testname); @@ -681,6 +762,12 @@ int main(int argc, char **argv) { } } + rc = pkd_cleanup_socket_wrapper(); + if (rc != 0) { + fprintf(stderr, "pkd_cleanup_socket_wrapper failed: %d\n", rc); + } + +out_finalize: rc = ssh_finalize(); if (rc != 0) { fprintf(stderr, "ssh_finalize: %d\n", rc); -- 2.1.4 From 59360c0efa36ec882116612b6fab3d8221455d57 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis <aris@xxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:51 -0600 Subject: [PATCH 10/30] external: Add ChaCha and Poly1305 implementations from OpenSSH Signed-off-by: Aris Adamantiadis <aris@xxxxxxxxxxxx> Reviewed-by: Andreas Schneider <asn@xxxxxxxxx> --- ConfigureChecks.cmake | 1 + config.h.cmake | 3 + include/libssh/chacha.h | 32 +++++++ include/libssh/poly1305.h | 18 ++++ src/CMakeLists.txt | 2 + src/external/chacha.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++ src/external/poly1305.c | 156 +++++++++++++++++++++++++++++++++ 7 files changed, 430 insertions(+) create mode 100644 include/libssh/chacha.h create mode 100644 include/libssh/poly1305.h create mode 100644 src/external/chacha.c create mode 100644 src/external/poly1305.c diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 4f0ecf8..2e1348f 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -56,6 +56,7 @@ check_include_file(pty.h HAVE_PTY_H) check_include_file(utmp.h HAVE_UTMP_H) check_include_file(termios.h HAVE_TERMIOS_H) check_include_file(unistd.h HAVE_UNISTD_H) +check_include_file(stdint.h HAVE_STDINT_H) check_include_file(util.h HAVE_UTIL_H) check_include_file(libutil.h HAVE_LIBUTIL_H) check_include_file(sys/time.h HAVE_SYS_TIME_H) diff --git a/config.h.cmake b/config.h.cmake index 50a50ed..e8786b1 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -50,6 +50,9 @@ /* Define to 1 if you have the <unistd.h> header file. */ #cmakedefine HAVE_UNISTD_H 1 +/* Define to 1 if you have the <stdint.h> header file. */ +#cmakedefine HAVE_STDINT_H 1 + /* Define to 1 if you have the <openssl/aes.h> header file. */ #cmakedefine HAVE_OPENSSL_AES_H 1 diff --git a/include/libssh/chacha.h b/include/libssh/chacha.h new file mode 100644 index 0000000..84ff66a --- /dev/null +++ b/include/libssh/chacha.h @@ -0,0 +1,32 @@ +/* $OpenBSD: chacha.h,v 1.3 2014/05/02 03:27:54 djm Exp $ */ + +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#ifndef CHACHA_H +#define CHACHA_H + +struct chacha_ctx { + uint32_t input[16]; +}; + +#define CHACHA_MINKEYLEN 16 +#define CHACHA_NONCELEN 8 +#define CHACHA_CTRLEN 8 +#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN) +#define CHACHA_BLOCKLEN 64 + +void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); +void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); +void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, + uint8_t *c, uint32_t bytes) + __attribute__((__bounded__(__buffer__, 2, 4))) + __attribute__((__bounded__(__buffer__, 3, 4))); + +#endif /* CHACHA_H */ diff --git a/include/libssh/poly1305.h b/include/libssh/poly1305.h new file mode 100644 index 0000000..7126ecb --- /dev/null +++ b/include/libssh/poly1305.h @@ -0,0 +1,18 @@ +/* + * Public Domain poly1305 from Andrew Moon + * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + */ + +#ifndef POLY1305_H +#define POLY1305_H + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 + +void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, + const uint8_t key[POLY1305_KEYLEN]) + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) + __attribute__((__bounded__(__buffer__, 2, 3))) + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); + +#endif /* POLY1305_H */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ecee06..edbf352 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -158,9 +158,11 @@ set(libssh_SRCS wrapper.c external/bcrypt_pbkdf.c external/blowfish.c + external/chacha.c external/ed25519.c external/fe25519.c external/ge25519.c + external/poly1305.c external/sc25519.c ) diff --git a/src/external/chacha.c b/src/external/chacha.c new file mode 100644 index 0000000..062aafb --- /dev/null +++ b/src/external/chacha.c @@ -0,0 +1,218 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. + */ + +#include <stdint.h> +#include <unistd.h> +#include <sys/types.h> + +#include "libssh/chacha.h" + +typedef unsigned int uint32_t; + +typedef struct chacha_ctx chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((uint8_t)(v) & U8C(0xFF)) +#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((uint32_t)((p)[0]) ) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void +chacha_keysetup(chacha_ctx *x,const uint8_t *k,uint32_t kbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +void +chacha_ivsetup(chacha_ctx *x, const uint8_t *iv, const uint8_t *counter) +{ + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void +chacha_encrypt_bytes(chacha_ctx *x,const uint8_t *m,uint8_t *c,uint32_t bytes) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + uint8_t *ctarget = NULL; + uint8_t tmp[64]; + u_int i; + + if (!bytes) return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} diff --git a/src/external/poly1305.c b/src/external/poly1305.c new file mode 100644 index 0000000..916dd62 --- /dev/null +++ b/src/external/poly1305.c @@ -0,0 +1,156 @@ +/* + * Public Domain poly1305 from Andrew Moon + * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + */ + +#include "config.h" + +#include <stdint.h> +#include <sys/types.h> + +#include "libssh/poly1305.h" + +#define mul32x32_64(a,b) ((uint64_t)(a) * (b)) + +#define U8TO32_LE(p) \ + (((uint32_t)((p)[0])) | \ + ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | \ + ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LE(p, v) \ + do { \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); \ + } while (0) + +void +poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { + uint32_t t0,t1,t2,t3; + uint32_t h0,h1,h2,h3,h4; + uint32_t r0,r1,r2,r3,r4; + uint32_t s1,s2,s3,s4; + uint32_t b, nb; + size_t j; + uint64_t t[5]; + uint64_t f0,f1,f2,f3; + uint32_t g0,g1,g2,g3,g4; + uint64_t c; + unsigned char mp[16]; + + /* clamp key */ + t0 = U8TO32_LE(key+0); + t1 = U8TO32_LE(key+4); + t2 = U8TO32_LE(key+8); + t3 = U8TO32_LE(key+12); + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if (inlen < 16) goto poly1305_donna_atmost15bytes; +poly1305_donna_16bytes: + m += 16; + inlen -= 16; + + t0 = U8TO32_LE(m-16); + t1 = U8TO32_LE(m-12); + t2 = U8TO32_LE(m-8); + t3 = U8TO32_LE(m-4); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8) | (1 << 24); + + +poly1305_donna_mul: + t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1); + t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2); + t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3); + t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4); + t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0); + + h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26); + t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26); + t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26); + t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26); + t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26); + h0 += b * 5; + + if (inlen >= 16) goto poly1305_donna_16bytes; + + /* final bytes */ +poly1305_donna_atmost15bytes: + if (!inlen) goto poly1305_donna_finish; + + for (j = 0; j < inlen; j++) mp[j] = m[j]; + mp[j++] = 1; + for (; j < 16; j++) mp[j] = 0; + inlen = 0; + + t0 = U8TO32_LE(mp+0); + t1 = U8TO32_LE(mp+4); + t2 = U8TO32_LE(mp+8); + t3 = U8TO32_LE(mp+12); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; + + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0 ) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); + + U32TO8_LE(&out[ 0], f0); f1 += (f0 >> 32); + U32TO8_LE(&out[ 4], f1); f2 += (f1 >> 32); + U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); + U32TO8_LE(&out[12], f3); +} -- 2.1.4 From b59ec47b8672759490507194f29b33ae22ac5cd3 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis <aris@xxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:52 -0600 Subject: [PATCH 11/30] cmake: detect "bounded" compiler attribute Signed-off-by: Aris Adamantiadis <aris@xxxxxxxxxxxx> Reviewed-by: Andreas Schneider <asn@xxxxxxxxxxxxxx> --- ConfigureChecks.cmake | 5 +++++ config.h.cmake | 2 ++ include/libssh/chacha.h | 15 ++++++++++++--- include/libssh/poly1305.h | 5 ++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index 2e1348f..fd8ff13 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -327,6 +327,11 @@ int main(void) { }" HAVE_COMPILER__FUNCTION__) +check_c_source_compiles(" +void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); +int main(void) { return 0; }" HAVE_GCC_BOUNDED_ATTRIBUTE) + if (WITH_DEBUG_CRYPTO) set(DEBUG_CRYPTO 1) endif (WITH_DEBUG_CRYPTO) diff --git a/config.h.cmake b/config.h.cmake index e8786b1..61d20ac 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -199,6 +199,8 @@ #cmakedefine HAVE_COMPILER__FUNC__ 1 #cmakedefine HAVE_COMPILER__FUNCTION__ 1 +#cmakedefine HAVE_GCC_BOUNDED_ATTRIBUTE 1 + /* Define to 1 if you want to enable GSSAPI */ #cmakedefine WITH_GSSAPI 1 diff --git a/include/libssh/chacha.h b/include/libssh/chacha.h index 84ff66a..bac78c6 100644 --- a/include/libssh/chacha.h +++ b/include/libssh/chacha.h @@ -20,13 +20,22 @@ struct chacha_ctx { #define CHACHA_BLOCKLEN 64 void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits) - __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); +#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))) +#endif + ; void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr) +#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) - __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))) +#endif + ; void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, uint8_t *c, uint32_t bytes) +#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE __attribute__((__bounded__(__buffer__, 2, 4))) - __attribute__((__bounded__(__buffer__, 3, 4))); + __attribute__((__bounded__(__buffer__, 3, 4))) +#endif + ; #endif /* CHACHA_H */ diff --git a/include/libssh/poly1305.h b/include/libssh/poly1305.h index 7126ecb..9174bd1 100644 --- a/include/libssh/poly1305.h +++ b/include/libssh/poly1305.h @@ -11,8 +11,11 @@ void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, const uint8_t key[POLY1305_KEYLEN]) +#ifdef HAVE_GCC_BOUNDED_ATTRIBUTE __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) __attribute__((__bounded__(__buffer__, 2, 3))) - __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))) +#endif + ; #endif /* POLY1305_H */ -- 2.1.4 From 3241d735f9b948b50c4ce81435385141045283e0 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis <aris@xxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:53 -0600 Subject: [PATCH 12/30] chacha: packet encryption Signed-off-by: Aris Adamantiadis <aris@xxxxxxxxxxxx> --- include/libssh/crypto.h | 6 +++ include/libssh/libcrypto.h | 1 + include/libssh/wrapper.h | 3 +- src/CMakeLists.txt | 1 + src/chachapoly.c | 126 +++++++++++++++++++++++++++++++++++++++++++++ src/dh.c | 3 ++ src/kex.c | 4 +- src/libcrypto.c | 21 +++++++- src/packet.c | 43 +++++++++++----- src/packet_crypt.c | 46 ++++++++++------- src/wrapper.c | 96 ++++++++++++++++++++++++---------- 11 files changed, 288 insertions(+), 62 deletions(-) create mode 100644 src/chachapoly.c diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h index fab39ed..e6e5b8f 100644 --- a/include/libssh/crypto.h +++ b/include/libssh/crypto.h @@ -128,10 +128,12 @@ struct ssh_cipher_struct { const char *name; /* ssh name of the algorithm */ unsigned int blocksize; /* blocksize of the algo */ enum ssh_cipher_e ciphertype; + uint32_t lenfield_blocksize; /* blocksize of the packet length field */ #ifdef HAVE_LIBGCRYPT size_t keylen; /* length of the key structure */ gcry_cipher_hd_t *key; #elif defined HAVE_LIBCRYPTO + size_t keylen; /* length of the key structure */ struct ssh_3des_key_schedule *des3_key; struct ssh_aes_key_schedule *aes_key; const EVP_CIPHER *cipher; @@ -141,7 +143,9 @@ struct ssh_cipher_struct { mbedtls_cipher_context_t decrypt_ctx; mbedtls_cipher_type_t type; #endif + struct chacha20_poly1305_keysched *chacha20_schedule; unsigned int keysize; /* bytes of key used. != keylen */ + size_t tag_size; /* overhead required for tag */ /* sets the new key for immediate use */ int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV); int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV); @@ -149,6 +153,8 @@ struct ssh_cipher_struct { unsigned long len); void (*decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out, unsigned long len); + void (*aead_encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out, + size_t len, uint8_t *mac, uint64_t seq); void (*cleanup)(struct ssh_cipher_struct *cipher); }; diff --git a/include/libssh/libcrypto.h b/include/libssh/libcrypto.h index 6a08837..4b8e541 100644 --- a/include/libssh/libcrypto.h +++ b/include/libssh/libcrypto.h @@ -95,6 +95,7 @@ SHA512CTX sha512_init(void); void sha512_update(SHA512CTX c, const void *data, unsigned long len); void sha512_final(unsigned char *md, SHA512CTX c); +void libcrypto_init(void); struct ssh_cipher_struct *ssh_get_ciphertab(void); #endif /* HAVE_LIBCRYPTO */ diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h index 6b6cf0b..c23c906 100644 --- a/include/libssh/wrapper.h +++ b/include/libssh/wrapper.h @@ -39,7 +39,8 @@ enum ssh_hmac_e { SSH_HMAC_SHA256, SSH_HMAC_SHA384, SSH_HMAC_SHA512, - SSH_HMAC_MD5 + SSH_HMAC_MD5, + SSH_HMAC_AEAD_POLY1305 }; enum ssh_des_e { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index edbf352..90e4425 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -122,6 +122,7 @@ set(libssh_SRCS bignum.c buffer.c callbacks.c + chachapoly.c channels.c client.c config.c diff --git a/src/chachapoly.c b/src/chachapoly.c new file mode 100644 index 0000000..1603217 --- /dev/null +++ b/src/chachapoly.c @@ -0,0 +1,126 @@ +/* + * This file is part of the SSH Library + * + * Copyright (c) 2015 by Aris Adamantiadis + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libssh/libssh.h" +#include "libssh/crypto.h" +#include "libssh/chacha.h" +#include "libssh/poly1305.h" +#include "libssh/misc.h" + +/* size of the keys k1 and k2 as defined in specs */ +#define CHACHA20_KEYLEN 32 +struct chacha20_poly1305_keysched { + /* key used for encrypting the length field*/ + struct chacha_ctx k1; + /* key used for encrypting the packets */ + struct chacha_ctx k2; +}; + +#pragma pack(push, 1) +struct ssh_packet_header { + uint32_t length; + uint8_t payload[]; +}; +#pragma pack(pop) + +const uint8_t zero_block_counter[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +const uint8_t payload_block_counter[8] = {1, 0, 0, 0, 0, 0, 0, 0}; + +static int chacha20_set_encrypt_key(struct ssh_cipher_struct *cipher, + void *key, + void *IV) +{ + struct chacha20_poly1305_keysched *sched; + uint8_t *u8key = key; + (void)IV; + + if (cipher->chacha20_schedule == NULL) { + sched = malloc(sizeof *sched); + if (sched == NULL){ + return -1; + } + } else { + sched = cipher->chacha20_schedule; + } + + chacha_keysetup(&sched->k2, u8key, CHACHA20_KEYLEN * 8); + chacha_keysetup(&sched->k1, u8key + CHACHA20_KEYLEN, CHACHA20_KEYLEN * 8); + cipher->chacha20_schedule = sched; + + return 0; +} + +/** + * @internal + * + * @brief encrypts an outgoing packet with chacha20 and authenticate it + * with poly1305. + */ +static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher, + void *in, + void *out, + size_t len, + uint8_t *tag, + uint64_t seq) +{ + struct ssh_packet_header *in_packet = in, *out_packet = out; + uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0}; + struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule; + + seq = htonll(seq); + /* step 1, prepare the poly1305 key */ + chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter); + chacha_encrypt_bytes(&keys->k2, + poly1305_ctx, + poly1305_ctx, + POLY1305_KEYLEN); + + /* step 2, encrypt length field */ + chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter); + chacha_encrypt_bytes(&keys->k1, + (uint8_t *)&in_packet->length, + (uint8_t *)&out_packet->length, + sizeof(uint32_t)); + + /* step 3, encrypt packet payload */ + chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter); + chacha_encrypt_bytes(&keys->k2, + in_packet->payload, + out_packet->payload, + len - sizeof(uint32_t)); + + /* step 4, compute the MAC */ + poly1305_auth(tag, (uint8_t *)out_packet, len, poly1305_ctx); +} + +const struct ssh_cipher_struct chacha20poly1305_cipher = { + .name = "chacha20-poly1305@xxxxxxxxxxx", + .blocksize = 8, + .lenfield_blocksize = 4, + .keylen = sizeof(struct chacha20_poly1305_keysched), + .keysize = 512, + .tag_size = POLY1305_TAGLEN, + .set_encrypt_key = chacha20_set_encrypt_key, + .set_decrypt_key = chacha20_set_encrypt_key, + .aead_encrypt = chacha20_poly1305_aead_encrypt, +}; diff --git a/src/dh.c b/src/dh.c index c3de5b9..2bc0a9d 100644 --- a/src/dh.c +++ b/src/dh.c @@ -68,6 +68,7 @@ #include <openssl/rand.h> #include <openssl/evp.h> #include <openssl/err.h> +#include "libssh/libcrypto.h" #endif static unsigned char p_group1_value[] = { @@ -210,6 +211,8 @@ int ssh_crypto_init(void) { bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14); OpenSSL_add_all_algorithms(); + + libcrypto_init(); #elif defined HAVE_LIBMBEDCRYPTO p_group1 = bignum_new(); bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1); diff --git a/src/kex.c b/src/kex.c index b658ed4..20044c3 100644 --- a/src/kex.c +++ b/src/kex.c @@ -95,6 +95,8 @@ #define ECDH "" #endif +#define CHACHA20 "chacha20-poly1305@xxxxxxxxxxx," + #define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1" #define KEX_METHODS_SIZE 10 @@ -117,7 +119,7 @@ static const char *default_methods[] = { static const char *supported_methods[] = { KEY_EXCHANGE, HOSTKEYS, - AES BLOWFISH DES_SUPPORTED, + CHACHA20 AES BLOWFISH DES_SUPPORTED, AES BLOWFISH DES_SUPPORTED, "hmac-sha2-256,hmac-sha2-512,hmac-sha1", "hmac-sha2-256,hmac-sha2-512,hmac-sha1", diff --git a/src/libcrypto.c b/src/libcrypto.c index 6645366..982c9c8 100644 --- a/src/libcrypto.c +++ b/src/libcrypto.c @@ -60,6 +60,7 @@ #include "libssh/crypto.h" +extern const struct ssh_cipher_struct chacha20poly1305_cipher; struct ssh_mac_ctx_struct { enum ssh_mac_e mac_type; union { @@ -861,10 +862,29 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { }, #endif /* HAS_DES */ { + .name = "chacha20-poly1305@xxxxxxxxxxx" + }, + { .name = NULL } }; +void libcrypto_init(void) +{ + size_t i; + + for (i = 0; ssh_ciphertab[i].name != NULL; i++) { + int cmp; + + cmp = strcmp(ssh_ciphertab[i].name, "chacha20-poly1305@xxxxxxxxxxx"); + if (cmp == 0) { + memcpy(&ssh_ciphertab[i], + &chacha20poly1305_cipher, + sizeof(struct ssh_cipher_struct)); + break; + } + } +} struct ssh_cipher_struct *ssh_get_ciphertab(void) { @@ -872,4 +892,3 @@ struct ssh_cipher_struct *ssh_get_ciphertab(void) } #endif /* LIBCRYPTO */ - diff --git a/src/packet.c b/src/packet.c index b66e3d2..f6fb6bf 100644 --- a/src/packet.c +++ b/src/packet.c @@ -555,6 +555,8 @@ static int ssh_packet_write(ssh_session session) { static int packet_send2(ssh_session session) { unsigned int blocksize = (session->current_crypto ? session->current_crypto->out_cipher->blocksize : 8); + unsigned int lenfield_blocksize = (session->current_crypto ? + session->current_crypto->out_cipher->lenfield_blocksize : 0); enum ssh_hmac_e hmac_type = (session->current_crypto ? session->current_crypto->out_hmac : session->next_crypto->out_hmac); uint32_t currentlen = ssh_buffer_get_len(session->out_buffer); @@ -563,8 +565,7 @@ static int packet_send2(ssh_session session) { int rc = SSH_ERROR; uint32_t finallen,payloadsize,compsize; uint8_t padding; - - uint8_t header[sizeof(padding) + sizeof(finallen)] = { 0 }; + ssh_buffer header_buffer = ssh_buffer_new(); payloadsize = currentlen; #ifdef WITH_ZLIB @@ -578,20 +579,30 @@ static int packet_send2(ssh_session session) { } #endif /* WITH_ZLIB */ compsize = currentlen; - padding = (blocksize - ((currentlen +5) % blocksize)); + /* compressed payload + packet len (4) + padding len (1) */ + /* totallen - lenfield_blocksize must be equal to 0 (mod blocksize) */ + padding = (blocksize - ((blocksize - lenfield_blocksize + currentlen + 5) % blocksize)); if(padding < 4) { padding += blocksize; } - if (session->current_crypto) { + if (session->current_crypto != NULL) { ssh_get_random(padstring, padding, 0); } - finallen = htonl(currentlen + padding + 1); + if (header_buffer == NULL){ + ssh_set_error_oom(session); + goto error; + } + finallen = currentlen + padding + 1; + rc = ssh_buffer_pack(header_buffer, "db", finallen, padding); + if (rc == SSH_ERROR){ + goto error; + } - memcpy(&header[0], &finallen, sizeof(finallen)); - header[sizeof(finallen)] = padding; - rc = ssh_buffer_prepend_data(session->out_buffer, &header, sizeof(header)); + rc = ssh_buffer_prepend_data(session->out_buffer, + ssh_buffer_get(header_buffer), + ssh_buffer_get_len(header_buffer)); if (rc < 0) { goto error; } @@ -600,10 +611,12 @@ static int packet_send2(ssh_session session) { goto error; } #ifdef WITH_PCAP - if(session->pcap_ctx){ - ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT, - ssh_buffer_get(session->out_buffer),ssh_buffer_get_len(session->out_buffer) - ,ssh_buffer_get_len(session->out_buffer)); + if (session->pcap_ctx) { + ssh_pcap_context_write(session->pcap_ctx, + SSH_PCAP_DIR_OUT, + ssh_buffer_get(session->out_buffer), + ssh_buffer_get_len(session->out_buffer), + ssh_buffer_get_len(session->out_buffer)); } #endif hmac = ssh_packet_encrypt(session, ssh_buffer_get(session->out_buffer), @@ -624,12 +637,14 @@ static int packet_send2(ssh_session session) { SSH_LOG(SSH_LOG_PACKET, "packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]", - ntohl(finallen), padding, compsize, payloadsize); + finallen, padding, compsize, payloadsize); if (ssh_buffer_reinit(session->out_buffer) < 0) { rc = SSH_ERROR; } error: - + if (header_buffer != NULL) { + ssh_buffer_free(header_buffer); + } return rc; /* SSH_OK, AGAIN or ERROR */ } diff --git a/src/packet_crypt.c b/src/packet_crypt.c index 7a30e66..5bcb6d6 100644 --- a/src/packet_crypt.c +++ b/src/packet_crypt.c @@ -93,7 +93,7 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) if (!session->current_crypto) { return NULL; /* nothing to do here */ } - if(len % session->current_crypto->in_cipher->blocksize != 0){ + if((len - session->current_crypto->out_cipher->lenfield_blocksize) % session->current_crypto->out_cipher->blocksize != 0){ ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len); return NULL; } @@ -106,26 +106,36 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) seq = ntohl(session->send_seq); crypto = session->current_crypto->out_cipher; - if (session->version == 2) { - ctx = hmac_init(session->current_crypto->encryptMAC, hmac_digest_len(type), type); - if (ctx == NULL) { - SAFE_FREE(out); - return NULL; - } - hmac_update(ctx,(unsigned char *)&seq,sizeof(uint32_t)); - hmac_update(ctx,data,len); - hmac_final(ctx,session->current_crypto->hmacbuf,&finallen); + if (crypto->aead_encrypt != NULL) { + crypto->aead_encrypt(crypto, data, out, len, + session->current_crypto->hmacbuf, session->send_seq); + } else { + if (session->version == 2) { + ctx = hmac_init(session->current_crypto->encryptMAC, hmac_digest_len(type), type); + if (ctx == NULL) { + SAFE_FREE(out); + return NULL; + } + hmac_update(ctx,(unsigned char *)&seq,sizeof(uint32_t)); + hmac_update(ctx,data,len); + hmac_final(ctx,session->current_crypto->hmacbuf,&finallen); + + if (crypto->set_encrypt_key(crypto, session->current_crypto->encryptkey, + session->current_crypto->encryptIV) < 0) { + SAFE_FREE(out); + return NULL; + } + #ifdef DEBUG_CRYPTO - ssh_print_hexa("mac: ",data,hmac_digest_len(type)); - if (finallen != hmac_digest_len(type)) { - printf("Final len is %d\n",finallen); - } - ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, hmac_digest_len(type)); + ssh_print_hexa("mac: ",data,hmac_digest_len(type)); + if (finallen != hmac_digest_len(type)) { + printf("Final len is %d\n",finallen); + } + ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, hmac_digest_len(type)); #endif - } - + } crypto->encrypt(crypto, data, out, len); - + } memcpy(data, out, len); explicit_bzero(out, len); SAFE_FREE(out); diff --git a/src/wrapper.c b/src/wrapper.c index 16f9327..69484ff 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -47,6 +47,7 @@ #include "libssh/crypto.h" #include "libssh/wrapper.h" #include "libssh/pki.h" +#include "libssh/poly1305.h" static struct ssh_hmac_struct ssh_hmac_tab[] = { { "hmac-sha1", SSH_HMAC_SHA1 }, @@ -54,6 +55,7 @@ static struct ssh_hmac_struct ssh_hmac_tab[] = { { "hmac-sha2-384", SSH_HMAC_SHA384 }, { "hmac-sha2-512", SSH_HMAC_SHA512 }, { "hmac-md5", SSH_HMAC_MD5 }, + { "aead-poly1305", SSH_HMAC_AEAD_POLY1305 }, { NULL, 0} }; @@ -73,6 +75,8 @@ size_t hmac_digest_len(enum ssh_hmac_e type) { return SHA512_DIGEST_LEN; case SSH_HMAC_MD5: return MD5_DIGEST_LEN; + case SSH_HMAC_AEAD_POLY1305: + return POLY1305_TAGLEN; default: return 0; } @@ -124,6 +128,9 @@ void ssh_cipher_clear(struct ssh_cipher_struct *cipher){ if (cipher->cleanup != NULL) { cipher->cleanup(cipher); } + if (cipher->chacha20_schedule != NULL){ + SAFE_FREE(cipher->chacha20_schedule); + } } static void cipher_free(struct ssh_cipher_struct *cipher) { @@ -247,9 +254,14 @@ static int crypt_set_algorithms2(ssh_session session){ } i = 0; - /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ - /* out */ - wanted = session->next_crypto->kex_methods[SSH_MAC_C_S]; + if (session->next_crypto->out_cipher->aead_encrypt != NULL){ + /* this cipher has integrated MAC */ + wanted = "aead-poly1305"; + } else { + /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ + /* out */ + wanted = session->next_crypto->kex_methods[SSH_MAC_C_S]; + } while (ssh_hmactab[i].name && strcmp(wanted, ssh_hmactab[i].name)) { i++; } @@ -357,7 +369,7 @@ int crypt_set_algorithms(ssh_session session, enum ssh_des_e des_type) { #ifdef WITH_SERVER int crypt_set_algorithms_server(ssh_session session){ - char *method = NULL; + const char *method = NULL; int i = 0; struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab(); struct ssh_hmac_struct *ssh_hmactab=ssh_get_hmactab(); @@ -372,9 +384,17 @@ int crypt_set_algorithms_server(ssh_session session){ */ /* out */ method = session->next_crypto->kex_methods[SSH_CRYPT_S_C]; - while(ssh_ciphertab[i].name && strcmp(method,ssh_ciphertab[i].name)) - i++; - if(!ssh_ciphertab[i].name){ + + for (i = 0; ssh_ciphertab[i].name != NULL; i++) { + int cmp; + + cmp = strcmp(method, ssh_ciphertab[i].name); + if (cmp == 0) { + break; + } + } + + if (ssh_ciphertab[i].name == NULL) { ssh_set_error(session,SSH_FATAL,"crypt_set_algorithms_server : " "no crypto algorithm function found for %s",method); return SSH_ERROR; @@ -387,26 +407,16 @@ int crypt_set_algorithms_server(ssh_session session){ return SSH_ERROR; } i=0; - /* in */ - method = session->next_crypto->kex_methods[SSH_CRYPT_C_S]; - while(ssh_ciphertab[i].name && strcmp(method,ssh_ciphertab[i].name)) - i++; - if(!ssh_ciphertab[i].name){ - ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server :" - "no crypto algorithm function found for %s",method); - return SSH_ERROR; - } - SSH_LOG(SSH_LOG_PACKET,"Set input algorithm %s",method); - - session->next_crypto->in_cipher = cipher_new(i); - if (session->next_crypto->in_cipher == NULL) { - ssh_set_error_oom(session); - return SSH_ERROR; + if (session->next_crypto->out_cipher->aead_encrypt != NULL){ + /* this cipher has integrated MAC */ + method = "aead-poly1305"; + } else { + /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ + /* out */ + method = session->next_crypto->kex_methods[SSH_MAC_S_C]; } - i=0; - /* HMAC algorithm selection */ - method = session->next_crypto->kex_methods[SSH_MAC_S_C]; + while (ssh_hmactab[i].name && strcmp(method, ssh_hmactab[i].name)) { i++; } @@ -420,11 +430,43 @@ int crypt_set_algorithms_server(ssh_session session){ SSH_LOG(SSH_LOG_PACKET, "Set HMAC output algorithm to %s", method); session->next_crypto->out_hmac = ssh_hmactab[i].hmac_type; + + /* in */ + i=0; + method = session->next_crypto->kex_methods[SSH_CRYPT_C_S]; + + for (i = 0; ssh_ciphertab[i].name; i++) { + int cmp; + + cmp = strcmp(method, ssh_ciphertab[i].name); + if (cmp == 0) { + break; + } + } + + if (ssh_ciphertab[i].name == NULL) { + ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server :" + "no crypto algorithm function found for %s",method); + return SSH_ERROR; + } + SSH_LOG(SSH_LOG_PACKET,"Set input algorithm %s",method); + + session->next_crypto->in_cipher = cipher_new(i); + if (session->next_crypto->in_cipher == NULL) { + ssh_set_error_oom(session); + return SSH_ERROR; + } i=0; method = session->next_crypto->kex_methods[SSH_MAC_C_S]; - while (ssh_hmactab[i].name && strcmp(method, ssh_hmactab[i].name)) { - i++; + + for (i = 0; ssh_hmactab[i].name != NULL; i++) { + int cmp; + + cmp = strcmp(method, ssh_hmactab[i].name); + if (cmp == 0) { + break; + } } if (ssh_hmactab[i].name == NULL) { -- 2.1.4 From 494cf5e8040fe4492c722dcad72b18ed19e8ccb6 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis <aris@xxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:54 -0600 Subject: [PATCH 13/30] chacha: packet decryption Signed-off-by: Aris Adamantiadis <aris@xxxxxxxxxxxx> --- include/libssh/crypto.h | 4 ++ include/libssh/packet.h | 5 +- src/chachapoly.c | 76 +++++++++++++++++++++++++++++ src/kex.c | 2 +- src/packet.c | 110 +++++++++++++++++++++--------------------- src/packet_crypt.c | 125 ++++++++++++++++++++++++++++++++++++------------ src/wrapper.c | 58 ++++++++++++++++------ 7 files changed, 276 insertions(+), 104 deletions(-) diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h index e6e5b8f..495a9c4 100644 --- a/include/libssh/crypto.h +++ b/include/libssh/crypto.h @@ -155,6 +155,10 @@ struct ssh_cipher_struct { unsigned long len); void (*aead_encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out, size_t len, uint8_t *mac, uint64_t seq); + int (*aead_decrypt_length)(struct ssh_cipher_struct *cipher, void *in, + uint8_t *out, size_t len, uint64_t seq); + int (*aead_decrypt)(struct ssh_cipher_struct *cipher, void *complete_packet, uint8_t *out, + size_t encrypted_size, uint64_t seq); void (*cleanup)(struct ssh_cipher_struct *cipher); }; diff --git a/include/libssh/packet.h b/include/libssh/packet.h index 3a84eb7..b10308f 100644 --- a/include/libssh/packet.h +++ b/include/libssh/packet.h @@ -78,8 +78,9 @@ void ssh_packet_set_default_callbacks(ssh_session session); void ssh_packet_process(ssh_session session, uint8_t type); /* PACKET CRYPT */ -uint32_t ssh_packet_decrypt_len(ssh_session session, char *crypted); -int ssh_packet_decrypt(ssh_session session, void *packet, unsigned int len); +uint32_t ssh_packet_decrypt_len(ssh_session session, uint8_t *destination, uint8_t *source); +int ssh_packet_decrypt(ssh_session session, uint8_t *destination, uint8_t *source, + size_t start, size_t encrypted_size); unsigned char *ssh_packet_encrypt(ssh_session session, void *packet, unsigned int len); diff --git a/src/chachapoly.c b/src/chachapoly.c index 1603217..f3319b6 100644 --- a/src/chachapoly.c +++ b/src/chachapoly.c @@ -109,8 +109,82 @@ static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher, out_packet->payload, len - sizeof(uint32_t)); + /* ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */ /* step 4, compute the MAC */ poly1305_auth(tag, (uint8_t *)out_packet, len, poly1305_ctx); + /* ssh_print_hexa("poly1305 src", (uint8_t *)out_packet, len); + ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN); */ +} + +static int chacha20_poly1305_aead_decrypt_length( + struct ssh_cipher_struct *cipher, + void *in, + uint8_t *out, + size_t len, + uint64_t seq) +{ + struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule; + + if (len < sizeof(uint32_t)) { + return SSH_ERROR; + } + seq = htonll(seq); + + chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter); + chacha_encrypt_bytes(&keys->k1, + in, + (uint8_t *)out, + sizeof(uint32_t)); + return SSH_OK; +} + +static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher, + void *complete_packet, + uint8_t *out, + size_t encrypted_size, + uint64_t seq) +{ + uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0}; + uint8_t tag[POLY1305_TAGLEN] = {0}; + struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule; + uint8_t *mac = (uint8_t *)complete_packet + sizeof(uint32_t) + encrypted_size; + int cmp; + + seq = htonll(seq); + + ZERO_STRUCT(poly1305_ctx); + chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter); + chacha_encrypt_bytes(&keys->k2, + poly1305_ctx, + poly1305_ctx, + POLY1305_KEYLEN); +#if 0 + ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); +#endif + + poly1305_auth(tag, (uint8_t *)complete_packet, encrypted_size + + sizeof(uint32_t), poly1305_ctx); +#if 0 + ssh_print_hexa("poly1305 src", + (uint8_t*)complete_packet, + encrypted_size + 4); + ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN); + ssh_print_hexa("received tag", mac, POLY1305_TAGLEN); +#endif + + cmp = memcmp(tag, mac, POLY1305_TAGLEN); + if(cmp != 0) { + /* mac error */ + SSH_LOG(SSH_LOG_PACKET,"poly1305 verify error"); + return SSH_ERROR; + } + chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter); + chacha_encrypt_bytes(&keys->k2, + (uint8_t *)complete_packet + sizeof(uint32_t), + out, + encrypted_size); + + return SSH_OK; } const struct ssh_cipher_struct chacha20poly1305_cipher = { @@ -123,4 +197,6 @@ const struct ssh_cipher_struct chacha20poly1305_cipher = { .set_encrypt_key = chacha20_set_encrypt_key, .set_decrypt_key = chacha20_set_encrypt_key, .aead_encrypt = chacha20_poly1305_aead_encrypt, + .aead_decrypt_length = chacha20_poly1305_aead_decrypt_length, + .aead_decrypt = chacha20_poly1305_aead_decrypt }; diff --git a/src/kex.c b/src/kex.c index 20044c3..00f4e00 100644 --- a/src/kex.c +++ b/src/kex.c @@ -120,7 +120,7 @@ static const char *supported_methods[] = { KEY_EXCHANGE, HOSTKEYS, CHACHA20 AES BLOWFISH DES_SUPPORTED, - AES BLOWFISH DES_SUPPORTED, + CHACHA20 AES BLOWFISH DES_SUPPORTED, "hmac-sha2-256,hmac-sha2-512,hmac-sha1", "hmac-sha2-256,hmac-sha2-512,hmac-sha1", ZLIB, diff --git a/src/packet.c b/src/packet.c index f6fb6bf..7d3c14b 100644 --- a/src/packet.c +++ b/src/packet.c @@ -144,20 +144,26 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) ssh_session session= (ssh_session) user; unsigned int blocksize = (session->current_crypto ? session->current_crypto->in_cipher->blocksize : 8); - unsigned char mac[DIGEST_MAX_LEN] = {0}; - char buffer[16] = {0}; + unsigned int lenfield_blocksize = (session->current_crypto ? + session->current_crypto->in_cipher->lenfield_blocksize : 8); size_t current_macsize = 0; - const uint8_t *packet; + uint8_t *ptr = NULL; int to_be_read; int rc; - uint32_t len, compsize, payloadsize; + uint8_t *cleartext_packet = NULL; + uint8_t *packet_second_block = NULL; + uint8_t *mac = NULL; + size_t packet_remaining; + uint32_t packet_len, compsize, payloadsize; uint8_t padding; size_t processed = 0; /* number of byte processed from the callback */ if(session->current_crypto != NULL) { current_macsize = hmac_digest_len(session->current_crypto->in_hmac); } - + if (lenfield_blocksize == 0) { + lenfield_blocksize = blocksize; + } if (data == NULL) { goto error; } @@ -178,7 +184,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) #endif switch(session->packet_state) { case PACKET_STATE_INIT: - if (receivedlen < blocksize) { + if (receivedlen < lenfield_blocksize) { /* * We didn't receive enough data to read at least one * block size, give up @@ -187,7 +193,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) SSH_LOG(SSH_LOG_PACKET, "Waiting for more data (%zu < %zu)", receivedlen, - blocksize); + lenfield_blocksize); #endif return 0; } @@ -206,24 +212,21 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) } } - memcpy(buffer, data, blocksize); - processed += blocksize; - len = ssh_packet_decrypt_len(session, buffer); - - rc = ssh_buffer_add_data(session->in_buffer, buffer, blocksize); - if (rc < 0) { + ptr = ssh_buffer_allocate(session->in_buffer, lenfield_blocksize); + if (ptr == NULL) { goto error; } + processed += lenfield_blocksize; + packet_len = ssh_packet_decrypt_len(session, ptr, (uint8_t *)data); - if (len > MAX_PACKET_LEN) { + if (packet_len > MAX_PACKET_LEN) { ssh_set_error(session, SSH_FATAL, "read_packet(): Packet len too high(%u %.4x)", - len, len); + packet_len, packet_len); goto error; } - - to_be_read = len - blocksize + sizeof(uint32_t); + to_be_read = packet_len - lenfield_blocksize + sizeof(uint32_t); if (to_be_read < 0) { /* remote sshd sends invalid sizes? */ ssh_set_error(session, @@ -233,59 +236,52 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) goto error; } - /* Saves the status of the current operations */ - session->in_packet.len = len; + session->in_packet.len = packet_len; session->packet_state = PACKET_STATE_SIZEREAD; FALL_THROUGH; case PACKET_STATE_SIZEREAD: - len = session->in_packet.len; - to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize; + packet_len = session->in_packet.len; + processed = lenfield_blocksize; + to_be_read = packet_len + sizeof(uint32_t) + current_macsize; /* if to_be_read is zero, the whole packet was blocksize bytes. */ if (to_be_read != 0) { - if (receivedlen - processed < (unsigned int)to_be_read) { + if (receivedlen < (unsigned int)to_be_read) { /* give up, not enough data in buffer */ - SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len); - return processed; + SSH_LOG(SSH_LOG_PACKET, + "packet: partial packet (read len) " + "[len=%d, receivedlen=%d, to_be_read=%d]", + packet_len, + (int)receivedlen, + to_be_read); + return 0; } - packet = ((uint8_t*)data) + processed; -#if 0 - ssh_socket_read(session->socket, - packet, - to_be_read - current_macsize); -#endif - - rc = ssh_buffer_add_data(session->in_buffer, - packet, - to_be_read - current_macsize); - if (rc < 0) { - goto error; - } - processed += to_be_read - current_macsize; + packet_second_block = (uint8_t*)data + lenfield_blocksize; + processed = to_be_read - current_macsize; } + /* remaining encrypted bytes from the packet, MAC not included */ + packet_remaining = + packet_len - (lenfield_blocksize - sizeof(uint32_t)); + cleartext_packet = ssh_buffer_allocate(session->in_buffer, + packet_remaining); if (session->current_crypto) { /* - * Decrypt the rest of the packet (blocksize bytes already + * Decrypt the rest of the packet (lenfield_blocksize bytes already * have been decrypted) */ - uint32_t buffer_len = ssh_buffer_get_len(session->in_buffer); - - /* The following check avoids decrypting zero bytes */ - if (buffer_len > blocksize) { - uint8_t *payload = ((uint8_t*)ssh_buffer_get(session->in_buffer) + blocksize); - uint32_t plen = buffer_len - blocksize; - - rc = ssh_packet_decrypt(session, payload, plen); + if (packet_remaining > 0) { + rc = ssh_packet_decrypt(session, + cleartext_packet, + (uint8_t *)data, + lenfield_blocksize, + processed - lenfield_blocksize); if (rc < 0) { - ssh_set_error(session, SSH_FATAL, "Decrypt error"); + ssh_set_error(session, SSH_FATAL, "Decryption error"); goto error; } } - - /* copy the last part from the incoming buffer */ - packet = ((uint8_t *)data) + processed; - memcpy(mac, packet, current_macsize); + mac = packet_second_block + packet_remaining; rc = ssh_packet_hmac_verify(session, session->in_buffer, mac, session->current_crypto->in_hmac); if (rc < 0) { @@ -293,6 +289,8 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) goto error; } processed += current_macsize; + } else { + memcpy(cleartext_packet, packet_second_block, packet_remaining); } /* skip the size field which has been processed before */ @@ -342,7 +340,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) ssh_packet_parse_type(session); SSH_LOG(SSH_LOG_PACKET, "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]", - session->in_packet.type, len, padding, compsize, payloadsize); + session->in_packet.type, packet_len, padding, compsize, payloadsize); /* Execute callbacks */ ssh_packet_process(session, session->in_packet.type); @@ -353,9 +351,9 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) "Processing %" PRIdS " bytes left in socket buffer", receivedlen-processed); - packet = ((uint8_t*)data) + processed; + ptr = ((uint8_t*)data) + processed; - rc = ssh_packet_socket_callback(packet, receivedlen - processed,user); + rc = ssh_packet_socket_callback(ptr, receivedlen - processed,user); processed += rc; } @@ -372,7 +370,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) error: session->session_state= SSH_SESSION_STATE_ERROR; - + SSH_LOG(SSH_LOG_PACKET,"Packet: processed %" PRIdS " bytes", processed); return processed; } diff --git a/src/packet_crypt.c b/src/packet_crypt.c index 5bcb6d6..fb09a22 100644 --- a/src/packet_crypt.c +++ b/src/packet_crypt.c @@ -44,40 +44,97 @@ #include "libssh/crypto.h" #include "libssh/buffer.h" -uint32_t ssh_packet_decrypt_len(ssh_session session, char *crypted){ - uint32_t decrypted; - - if (session->current_crypto) { - if (ssh_packet_decrypt(session, crypted, - session->current_crypto->in_cipher->blocksize) < 0) { - return 0; +/** @internal + * @brief decrypt the packet length from a raw encrypted packet, and store the first decrypted + * blocksize. + * @returns native byte-ordered decrypted length of the upcoming packet + */ +uint32_t ssh_packet_decrypt_len(ssh_session session, + uint8_t *destination, + uint8_t *source) +{ + uint32_t decrypted; + int rc; + + if (session->current_crypto != NULL) { + if (session->current_crypto->in_cipher->aead_decrypt_length != NULL) { + rc = + session->current_crypto->in_cipher->set_decrypt_key( + session->current_crypto->in_cipher, + session->current_crypto->decryptkey, + session->current_crypto->decryptIV); + if (rc < 0) { + return (uint32_t)-1; + } + session->current_crypto->in_cipher->aead_decrypt_length( + session->current_crypto->in_cipher, source, destination, + session->current_crypto->in_cipher->lenfield_blocksize, + session->recv_seq); + } else { + rc = ssh_packet_decrypt( + session, + destination, + source, + 0, + session->current_crypto->in_cipher->blocksize); + if (rc < 0) { + return 0; + } + } + } else { + memcpy(destination, source, 8); } - } - memcpy(&decrypted,crypted,sizeof(decrypted)); - return ntohl(decrypted); + memcpy(&decrypted,destination,sizeof(decrypted)); + + return ntohl(decrypted); } -int ssh_packet_decrypt(ssh_session session, void *data,uint32_t len) { - struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher; - char *out = NULL; +/** @internal + * @brief decrypts the content of an SSH packet. + * @param[source] source packet, including the encrypted length field + * @param[start] index in the packet that was not decrypted yet. + * @param[encrypted_size] size of the encrypted data to be decrypted after start. + */ +int ssh_packet_decrypt(ssh_session session, + uint8_t *destination, + uint8_t *source, + size_t start, + size_t encrypted_size) +{ + struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher; + int rc; + + if (encrypted_size <= 0) { + return SSH_ERROR; + } - assert(len); + if (encrypted_size % session->current_crypto->in_cipher->blocksize != 0) { + ssh_set_error(session, + SSH_FATAL, + "Cryptographic functions must be used on multiple of " + "blocksize (received %" PRIdS ")", + encrypted_size); + return SSH_ERROR; + } - if(len % session->current_crypto->in_cipher->blocksize != 0){ - ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len); - return SSH_ERROR; - } - out = malloc(len); - if (out == NULL) { - return -1; - } + rc = crypto->set_decrypt_key(crypto, + session->current_crypto->decryptkey, + session->current_crypto->decryptIV); + if (rc < 0) { + return -1; + } - crypto->decrypt(crypto,data,out,len); + if (crypto->aead_decrypt != NULL) { + return crypto->aead_decrypt(crypto, + source, + destination, + encrypted_size, + session->recv_seq); + } else { + crypto->decrypt(crypto, source + start, destination, encrypted_size); + } - memcpy(data,out,len); - explicit_bzero(out, len); - SAFE_FREE(out); - return 0; + return 0; } unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) { @@ -159,13 +216,21 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) * @return 0 if hmac and mac are equal, < 0 if not or an error * occurred. */ -int ssh_packet_hmac_verify(ssh_session session, ssh_buffer buffer, - unsigned char *mac, enum ssh_hmac_e type) { +int ssh_packet_hmac_verify(ssh_session session, + ssh_buffer buffer, + uint8_t *mac, + enum ssh_hmac_e type) +{ unsigned char hmacbuf[DIGEST_MAX_LEN] = {0}; HMACCTX ctx; unsigned int len; uint32_t seq; + /* AEAD type have no mac checking */ + if (type == SSH_HMAC_AEAD_POLY1305) { + return SSH_OK; + } + ctx = hmac_init(session->current_crypto->decryptMAC, hmac_digest_len(type), type); if (ctx == NULL) { return -1; @@ -188,5 +253,3 @@ int ssh_packet_hmac_verify(ssh_session session, ssh_buffer buffer, return -1; } - -/* vim: set ts=2 sw=2 et cindent: */ diff --git a/src/wrapper.c b/src/wrapper.c index 69484ff..77af522 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -231,8 +231,13 @@ static int crypt_set_algorithms2(ssh_session session){ int i = 0; struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab(); struct ssh_hmac_struct *ssh_hmactab=ssh_get_hmactab(); + int cmp; + + /* + * We must scan the kex entries to find crypto algorithms and set their + * appropriate structure. + */ - /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */ /* out */ wanted = session->next_crypto->kex_methods[SSH_CRYPT_C_S]; while (ssh_ciphertab[i].name && strcmp(wanted, ssh_ciphertab[i].name)) { @@ -258,12 +263,20 @@ static int crypt_set_algorithms2(ssh_session session){ /* this cipher has integrated MAC */ wanted = "aead-poly1305"; } else { - /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ + /* + * We must scan the kex entries to find hmac algorithms and set their + * appropriate structure. + */ + /* out */ wanted = session->next_crypto->kex_methods[SSH_MAC_C_S]; } - while (ssh_hmactab[i].name && strcmp(wanted, ssh_hmactab[i].name)) { - i++; + + for (i = 0; ssh_hmactab[i].name != NULL; i++) { + cmp = strcmp(wanted, ssh_hmactab[i].name); + if (cmp == 0) { + break; + } } if (ssh_hmactab[i].name == NULL) { @@ -275,12 +288,15 @@ static int crypt_set_algorithms2(ssh_session session){ SSH_LOG(SSH_LOG_PACKET, "Set HMAC output algorithm to %s", wanted); session->next_crypto->out_hmac = ssh_hmactab[i].hmac_type; - i = 0; /* in */ wanted = session->next_crypto->kex_methods[SSH_CRYPT_S_C]; - while (ssh_ciphertab[i].name && strcmp(wanted, ssh_ciphertab[i].name)) { - i++; + + for (i = 0; ssh_ciphertab[i].name != NULL; i++) { + cmp = strcmp(wanted, ssh_ciphertab[i].name); + if (cmp == 0) { + break; + } } if (ssh_ciphertab[i].name == NULL) { @@ -296,12 +312,20 @@ static int crypt_set_algorithms2(ssh_session session){ ssh_set_error_oom(session); return SSH_ERROR; } - i = 0; - /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ - wanted = session->next_crypto->kex_methods[SSH_MAC_S_C]; - while (ssh_hmactab[i].name && strcmp(wanted, ssh_hmactab[i].name)) { - i++; + if (session->next_crypto->in_cipher->aead_encrypt != NULL){ + /* this cipher has integrated MAC */ + wanted = "aead-poly1305"; + } else { + /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ + wanted = session->next_crypto->kex_methods[SSH_MAC_S_C]; + } + + for (i = 0; ssh_hmactab[i].name != NULL; i++) { + cmp = strcmp(wanted, ssh_hmactab[i].name); + if (cmp == 0) { + break; + } } if (ssh_hmactab[i].name == NULL) { @@ -310,7 +334,7 @@ static int crypt_set_algorithms2(ssh_session session){ wanted); return SSH_ERROR; } - SSH_LOG(SSH_LOG_PACKET, "Set HMAC output algorithm to %s", wanted); + SSH_LOG(SSH_LOG_PACKET, "Set HMAC input algorithm to %s", wanted); session->next_crypto->in_hmac = ssh_hmactab[i].hmac_type; i = 0; @@ -458,7 +482,13 @@ int crypt_set_algorithms_server(ssh_session session){ } i=0; - method = session->next_crypto->kex_methods[SSH_MAC_C_S]; + if (session->next_crypto->in_cipher->aead_encrypt != NULL){ + /* this cipher has integrated MAC */ + method = "aead-poly1305"; + } else { + /* we must scan the kex entries to find hmac algorithms and set their appropriate structure */ + method = session->next_crypto->kex_methods[SSH_MAC_C_S]; + } for (i = 0; ssh_hmactab[i].name != NULL; i++) { int cmp; -- 2.1.4 From f8497cf2c28292001b260845aa97b4c2abf885d9 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis <aris@xxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:55 -0600 Subject: [PATCH 14/30] libgcrypt: make it compatible with chacha20 Signed-off-by: Aris Adamantiadis <aris@xxxxxxxxxxxx> --- include/libssh/libgcrypt.h | 1 + src/dh.c | 1 + src/libgcrypt.c | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/include/libssh/libgcrypt.h b/include/libssh/libgcrypt.h index ec35391..307920d 100644 --- a/include/libssh/libgcrypt.h +++ b/include/libssh/libgcrypt.h @@ -88,6 +88,7 @@ ssh_string ssh_sexp_extract_mpi(const gcry_sexp_t sexp, #endif /* HAVE_LIBGCRYPT */ +void libgcrypt_init(void); struct ssh_cipher_struct *ssh_get_ciphertab(void); #endif /* LIBGCRYPT_H_ */ diff --git a/src/dh.c b/src/dh.c index 2bc0a9d..2b6b3f7 100644 --- a/src/dh.c +++ b/src/dh.c @@ -190,6 +190,7 @@ int ssh_crypto_init(void) { p_group1 = NULL; return -1; } + libgcrypt_init(); #elif defined HAVE_LIBCRYPTO p_group1 = bignum_new(); diff --git a/src/libgcrypt.c b/src/libgcrypt.c index d9dd5be..b695b6b 100644 --- a/src/libgcrypt.c +++ b/src/libgcrypt.c @@ -35,6 +35,8 @@ #ifdef HAVE_LIBGCRYPT #include <gcrypt.h> +extern const struct ssh_cipher_struct chacha20poly1305_cipher; + struct ssh_mac_ctx_struct { enum ssh_mac_e mac_type; gcry_md_hd_t ctx; @@ -638,6 +640,9 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .decrypt = des1_1_decrypt }, { + .name = "chacha20-poly1305@xxxxxxxxxxx" + }, + { .name = NULL, .blocksize = 0, .keylen = 0, @@ -650,6 +655,22 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { } }; +void libgcrypt_init(void) +{ + size_t i; + + for (i = 0; ssh_ciphertab[i].name != NULL; i++) { + int cmp; + cmp = strcmp(ssh_ciphertab[i].name, "chacha20-poly1305@xxxxxxxxxxx"); + if (cmp == 0) { + memcpy(&ssh_ciphertab[i], + &chacha20poly1305_cipher, + sizeof(struct ssh_cipher_struct)); + break; + } + } +} + struct ssh_cipher_struct *ssh_get_ciphertab(void) { return ssh_ciphertab; -- 2.1.4 From 40f896e553e81358425d3e127faf9003df49049b Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis <aris@xxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:56 -0600 Subject: [PATCH 15/30] tests: test for chacha20-poly1305@xxxxxxxxxxx Signed-off-by: Aris Adamantiadis <aris@xxxxxxxxxxxx> --- tests/client/torture_algorithms.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/client/torture_algorithms.c b/tests/client/torture_algorithms.c index 76ea2ce..857ba19 100644 --- a/tests/client/torture_algorithms.c +++ b/tests/client/torture_algorithms.c @@ -261,6 +261,10 @@ static void torture_algorithms_blowfish_cbc_hmac_sha2_512(void **state) { } #endif +static void torture_algorithms_chacha20_poly1305(void **state) { + test_algorithm(*state, NULL/*kex*/, "chacha20-poly1305@xxxxxxxxxxx", NULL); +} + static void torture_algorithms_zlib(void **state) { struct torture_state *s = *state; ssh_session session = s->ssh.session; @@ -441,6 +445,9 @@ int torture_run_tests(void) { session_setup, session_teardown), #endif + cmocka_unit_test_setup_teardown(torture_algorithms_chacha20_poly1305, + session_setup, + session_teardown), cmocka_unit_test_setup_teardown(torture_algorithms_zlib, session_setup, session_teardown), -- 2.1.4 From 7ae788c0e3b74c14127623e0e623d911ea8e72cd Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis <aris@xxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:57 -0600 Subject: [PATCH 16/30] tests: packet encryption unit testing That code is really ugly, but it wasn't meant to be modular at all in the first place. Signed-off-by: Aris Adamantiadis <aris@xxxxxxxxxxxx> --- tests/unittests/CMakeLists.txt | 1 + tests/unittests/torture_packet.c | 193 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 tests/unittests/torture_packet.c diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index ee8db1d..0afe11b 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -12,6 +12,7 @@ add_cmocka_test(torture_config torture_config.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_knownhosts_parsing torture_knownhosts_parsing.c ${TORTURE_LIBRARY}) +add_cmocka_test(torture_packet torture_packet.c ${TORTURE_LIBRARY}) if (UNIX AND NOT WIN32) # requires ssh-keygen add_cmocka_test(torture_keyfiles torture_keyfiles.c ${TORTURE_LIBRARY}) diff --git a/tests/unittests/torture_packet.c b/tests/unittests/torture_packet.c new file mode 100644 index 0000000..0e7d3f1 --- /dev/null +++ b/tests/unittests/torture_packet.c @@ -0,0 +1,193 @@ +#include "config.h" + +#define LIBSSH_STATIC + +#include "torture.h" +#include "libssh/libssh.h" +#include "libssh/session.h" +#include "libssh/crypto.h" +#include "libssh/buffer.h" +#include "libssh/socket.h" +#include "libssh/callbacks.h" +#include <sys/types.h> +#include <sys/socket.h> +#include "socket.c" + +uint8_t test_data[]="AThis is test data. Use it to check the validity of packet functions"; +uint8_t key[]="iekaeshoa7ooCie2shai8shahngee3ONsee3xoishooj0ojei6aeChieth1iraPh"; +uint8_t iv[]="eixaxughoomah4ui7Aew3ohxuolaifuu"; +uint8_t mac[]="thook2Jai0ahmahyae7ChuuruoPhee8Y"; + +static uint8_t *copy_data(uint8_t *data, size_t len){ + uint8_t *ret = malloc(len); + assert_non_null(ret); + memcpy(ret, data, len); + return ret; +} + +static SSH_PACKET_CALLBACK(copy_packet_data){ + uint8_t *response = user; + size_t len = ssh_buffer_get_len(packet); + (void)type; + (void)session; + + if(len > 1024){ + len = 1024; + } + ssh_buffer_get_data(packet, response, len); + + return 0; +} + +static void torture_packet(const char *cipher, + const char *mac_type, size_t payload_len) { + + ssh_session session = ssh_new(); + int verbosity = torture_libssh_verbosity(); + struct ssh_crypto_struct *crypto; + int rc; + int sockets[2]; + uint8_t buffer[1024]; + uint8_t response[1024]; + size_t encrypted_packet_len; + ssh_packet_callback callbacks[]={copy_packet_data}; + struct ssh_packet_callbacks_struct cb = { + .start='A', + .n_callbacks=1, + .callbacks=callbacks, + .user=response + }; + + assert_non_null(session); + ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); + crypto = session->next_crypto; + + rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); + assert_int_equal(rc, 0); + + session->version = 2; + crypto->kex_methods[SSH_KEX] = strdup("curve25519-sha256@xxxxxxxxxx"); + crypto->kex_methods[SSH_HOSTKEYS] = strdup("ssh-rsa"); + crypto->kex_methods[SSH_CRYPT_C_S] = strdup(cipher); + crypto->kex_methods[SSH_CRYPT_S_C] = strdup(cipher); + crypto->kex_methods[SSH_MAC_C_S] = strdup(mac_type); + crypto->kex_methods[SSH_MAC_S_C] = strdup(mac_type); + crypto->kex_methods[SSH_COMP_C_S] = strdup("none"); + crypto->kex_methods[SSH_COMP_S_C] = strdup("none"); + crypto->kex_methods[SSH_LANG_C_S] = strdup("none"); + crypto->kex_methods[SSH_LANG_S_C] = strdup("none"); + rc = crypt_set_algorithms(session, 0); + assert_int_equal(rc, SSH_OK); + session->current_crypto = session->next_crypto; + session->next_crypto = crypto_new(); + crypto->encryptkey = copy_data(key, sizeof(key)); + crypto->decryptkey = copy_data(key, sizeof(key)); + crypto->encryptIV = copy_data(iv, sizeof(iv)); + crypto->decryptIV = copy_data(iv, sizeof(iv)); + crypto->encryptMAC = copy_data(mac, sizeof(mac)); + crypto->decryptMAC = copy_data(mac, sizeof(mac)); + + assert_non_null(session->out_buffer); + ssh_buffer_add_data(session->out_buffer, test_data, payload_len); + session->socket->fd_out = sockets[0]; + session->socket->fd_in = -2; + session->socket->write_wontblock = 1; + rc = ssh_packet_send(session); + assert_int_equal(rc, SSH_OK); + + rc = recv(sockets[1], buffer, sizeof(buffer), 0); + assert_true(rc > 0); + encrypted_packet_len = rc; + assert_in_range(encrypted_packet_len, payload_len + 4, payload_len + (32 * 3)); + rc = send(sockets[0], buffer, encrypted_packet_len, 0); + assert_int_equal(rc, encrypted_packet_len); + + ssh_packet_set_callbacks(session, &cb); + explicit_bzero(response, sizeof(response)); + rc = ssh_packet_socket_callback(buffer, encrypted_packet_len, session); + assert_int_not_equal(rc, SSH_ERROR); + if(payload_len > 0){ + assert_memory_equal(response, test_data+1, payload_len-1); + } + close(sockets[0]); + close(sockets[1]); + session->socket->fd_in = SSH_INVALID_SOCKET; + session->socket->fd_out = SSH_INVALID_SOCKET; + ssh_free(session); +} + +static void torture_packet_aes128_ctr() { + int i; + for (i=1;i<256;++i){ + torture_packet("aes128-ctr","hmac-sha1",i); + } +} + +static void torture_packet_aes192_ctr(){ + int i; + for (i=1;i<256;++i){ + torture_packet("aes192-ctr","hmac-sha1",i); + } +} + +static void torture_packet_aes256_ctr(){ + int i; + for (i=1;i<256;++i){ + torture_packet("aes256-ctr","hmac-sha1",i); + } +} + +static void torture_packet_aes128_cbc() { + int i; + for (i=1;i<256;++i){ + torture_packet("aes128-cbc","hmac-sha1",i); + } +} + +static void torture_packet_aes192_cbc(){ + int i; + for (i=1;i<256;++i){ + torture_packet("aes192-cbc","hmac-sha1",i); + } +} + +static void torture_packet_aes256_cbc(){ + int i; + for (i=1;i<256;++i){ + torture_packet("aes256-cbc","hmac-sha1",i); + } +} + +static void torture_packet_3des_cbc(){ + int i; + for (i=1;i<256;++i){ + torture_packet("3des-cbc","hmac-sha1",i); + } +} + +static void torture_packet_chacha20(){ + int i; + for (i=1;i<256;++i){ + torture_packet("chacha20-poly1305@xxxxxxxxxxx","none",i); + } +} + +int torture_run_tests(void) { + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test(torture_packet_aes128_ctr), + cmocka_unit_test(torture_packet_aes192_ctr), + cmocka_unit_test(torture_packet_aes256_ctr), + cmocka_unit_test(torture_packet_aes128_cbc), + cmocka_unit_test(torture_packet_aes192_cbc), + cmocka_unit_test(torture_packet_aes256_cbc), + cmocka_unit_test(torture_packet_3des_cbc), + cmocka_unit_test(torture_packet_chacha20) + }; + + ssh_init(); + torture_filter_tests(tests); + rc = cmocka_run_group_tests(tests, NULL, NULL); + ssh_finalize(); + return rc; +} -- 2.1.4 From d12cd0749540f1b01843aec1959c7a3695289041 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis <aris@xxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:58 -0600 Subject: [PATCH 17/30] tests: send more packets of various sizes Signed-off-by: Aris Adamantiadis <aris@xxxxxxxxxxxx> --- tests/client/torture_algorithms.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/client/torture_algorithms.c b/tests/client/torture_algorithms.c index 857ba19..edeb697 100644 --- a/tests/client/torture_algorithms.c +++ b/tests/client/torture_algorithms.c @@ -26,6 +26,7 @@ #include "torture.h" #include "libssh/libssh.h" #include "libssh/priv.h" +#include "libssh/session.h" #include <errno.h> #include <sys/types.h> @@ -49,7 +50,6 @@ static int session_setup(void **state) { int verbosity = torture_libssh_verbosity(); struct passwd *pwd; int rc; - pwd = getpwnam("bob"); assert_non_null(pwd); @@ -80,6 +80,15 @@ static void test_algorithm(ssh_session session, const char *cipher, const char *hmac) { int rc; + char data[256]; + size_t len_to_test[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 10, + 12, 15, 16, 20, + 31, 32, 33, + 63, 64, 65, + 100, 127, 128 + }; + unsigned int i; int verbosity = torture_libssh_verbosity(); ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); @@ -106,6 +115,14 @@ static void test_algorithm(ssh_session session, rc = ssh_connect(session); assert_int_equal(rc, SSH_OK); + /* send ignore packets of all sizes */ + memset(data, 0, sizeof(data)); + for (i = 0; i < (sizeof(len_to_test) / sizeof(size_t)); i++) { + memset(data, 'A', len_to_test[i]); + ssh_send_ignore(session, data); + ssh_handle_packets(session, 50); + } + rc = ssh_userauth_none(session, NULL); if (rc != SSH_OK) { rc = ssh_get_error_code(session); -- 2.1.4 From 3cf6352e2a3d8e3951b129eb43b2fa1cfb4fc176 Mon Sep 17 00:00:00 2001 From: Alberto Aguirre <albaguirre@xxxxxxxxx> Date: Wed, 28 Feb 2018 10:25:02 -0600 Subject: [PATCH 18/30] packet_crypt: Avoid setting keys every time Avoid setting keys on every packet decrypt or encrypt operation. Signed-off-by: Alberto Aguirre <albaguirre@xxxxxxxxx> --- src/packet_crypt.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/packet_crypt.c b/src/packet_crypt.c index fb09a22..68103af 100644 --- a/src/packet_crypt.c +++ b/src/packet_crypt.c @@ -117,13 +117,6 @@ int ssh_packet_decrypt(ssh_session session, return SSH_ERROR; } - rc = crypto->set_decrypt_key(crypto, - session->current_crypto->decryptkey, - session->current_crypto->decryptIV); - if (rc < 0) { - return -1; - } - if (crypto->aead_decrypt != NULL) { return crypto->aead_decrypt(crypto, source, @@ -177,12 +170,6 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len) hmac_update(ctx,data,len); hmac_final(ctx,session->current_crypto->hmacbuf,&finallen); - if (crypto->set_encrypt_key(crypto, session->current_crypto->encryptkey, - session->current_crypto->encryptIV) < 0) { - SAFE_FREE(out); - return NULL; - } - #ifdef DEBUG_CRYPTO ssh_print_hexa("mac: ",data,hmac_digest_len(type)); if (finallen != hmac_digest_len(type)) { -- 2.1.4 From ae45a112ea0aa87c7b5ebea536c3dc9e5a252482 Mon Sep 17 00:00:00 2001 From: Alberto Aguirre <albaguirre@xxxxxxxxx> Date: Wed, 28 Feb 2018 10:25:04 -0600 Subject: [PATCH 19/30] torture_packet: Set encryption/decryption keys Signed-off-by: Alberto Aguirre <albaguirre@xxxxxxxxx> --- tests/unittests/torture_packet.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/unittests/torture_packet.c b/tests/unittests/torture_packet.c index 0e7d3f1..a01ea21 100644 --- a/tests/unittests/torture_packet.c +++ b/tests/unittests/torture_packet.c @@ -45,6 +45,8 @@ static void torture_packet(const char *cipher, ssh_session session = ssh_new(); int verbosity = torture_libssh_verbosity(); struct ssh_crypto_struct *crypto; + struct ssh_cipher_struct *in_cipher; + struct ssh_cipher_struct *out_cipher; int rc; int sockets[2]; uint8_t buffer[1024]; @@ -87,6 +89,18 @@ static void torture_packet(const char *cipher, crypto->encryptMAC = copy_data(mac, sizeof(mac)); crypto->decryptMAC = copy_data(mac, sizeof(mac)); + in_cipher = session->current_crypto->in_cipher; + rc = in_cipher->set_decrypt_key(in_cipher, + session->current_crypto->decryptkey, + session->current_crypto->decryptIV); + assert_int_equal(rc, SSH_OK); + + out_cipher = session->current_crypto->out_cipher; + rc = out_cipher->set_encrypt_key(out_cipher, + session->current_crypto->encryptkey, + session->current_crypto->encryptIV); + assert_int_equal(rc, SSH_OK); + assert_non_null(session->out_buffer); ssh_buffer_add_data(session->out_buffer, test_data, payload_len); session->socket->fd_out = sockets[0]; -- 2.1.4 From 5df1af0945bf2a36259bb4d893531440a1a5e817 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:24:59 -0600 Subject: [PATCH 20/30] pkd: add passes for chacha20-poly1305@xxxxxxxxxxx cipher Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/pkd_hello.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/pkd/pkd_hello.c b/tests/pkd/pkd_hello.c index 951bd7b..7a429e9 100644 --- a/tests/pkd/pkd_hello.c +++ b/tests/pkd/pkd_hello.c @@ -258,6 +258,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) { #endif #ifdef HAVE_DSA +#define CHACHA20 "chacha20-poly1305@xxxxxxxxxxx" #define PKDTESTS_CIPHER(f, client, ciphercmd) \ /* Ciphers. */ \ f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \ @@ -266,24 +267,28 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, rsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_rsa, teardown) \ f(client, rsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_rsa, teardown) \ f(client, rsa_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_rsa, teardown) \ + f(client, rsa_chacha20, ciphercmd(CHACHA20), setup_rsa, teardown) \ f(client, dsa_3des_cbc, ciphercmd("3des-cbc"), setup_dsa, teardown) \ f(client, dsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_dsa, teardown) \ f(client, dsa_aes128_ctr, ciphercmd("aes128-ctr"), setup_dsa, teardown) \ f(client, dsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_dsa, teardown) \ f(client, dsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_dsa, teardown) \ f(client, dsa_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_dsa, teardown) \ + f(client, dsa_chacha20, ciphercmd(CHACHA20), setup_dsa, teardown) \ f(client, ecdsa_256_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_chacha20, ciphercmd(CHACHA20), setup_ecdsa_256, teardown) \ f(client, ecdsa_384_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_chacha20, ciphercmd(CHACHA20), setup_ecdsa_384, teardown) \ f(client, ecdsa_521_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_521, teardown) \ @@ -316,7 +321,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_521_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_521, teardown) \ - f(client, ecdsa_521_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_521, teardown) + f(client, ecdsa_521_chacha20, ciphercmd(CHACHA20), setup_ecdsa_521, teardown) #endif #ifdef HAVE_DSA -- 2.1.4 From 97f2649c1771e569a96f9057e4956b5fbea5a1f3 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Wed, 28 Feb 2018 10:25:00 -0600 Subject: [PATCH 21/30] pkd: move chacha20-poly1305@xxxxxxxxxxx tests to OPENSSHONLY section Dropbear does not currently implement the 'chacha20-poly1305@xxxxxxxxxxx' cipher, so move it into the OPENSSHONLY suite. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/pkd_hello.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/pkd/pkd_hello.c b/tests/pkd/pkd_hello.c index 7a429e9..7c499be 100644 --- a/tests/pkd/pkd_hello.c +++ b/tests/pkd/pkd_hello.c @@ -258,7 +258,6 @@ static int torture_pkd_setup_ecdsa_521(void **state) { #endif #ifdef HAVE_DSA -#define CHACHA20 "chacha20-poly1305@xxxxxxxxxxx" #define PKDTESTS_CIPHER(f, client, ciphercmd) \ /* Ciphers. */ \ f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \ @@ -267,28 +266,24 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, rsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_rsa, teardown) \ f(client, rsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_rsa, teardown) \ f(client, rsa_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_rsa, teardown) \ - f(client, rsa_chacha20, ciphercmd(CHACHA20), setup_rsa, teardown) \ f(client, dsa_3des_cbc, ciphercmd("3des-cbc"), setup_dsa, teardown) \ f(client, dsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_dsa, teardown) \ f(client, dsa_aes128_ctr, ciphercmd("aes128-ctr"), setup_dsa, teardown) \ f(client, dsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_dsa, teardown) \ f(client, dsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_dsa, teardown) \ f(client, dsa_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_dsa, teardown) \ - f(client, dsa_chacha20, ciphercmd(CHACHA20), setup_dsa, teardown) \ f(client, ecdsa_256_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_256, teardown) \ - f(client, ecdsa_256_chacha20, ciphercmd(CHACHA20), setup_ecdsa_256, teardown) \ f(client, ecdsa_384_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_384, teardown) \ - f(client, ecdsa_384_chacha20, ciphercmd(CHACHA20), setup_ecdsa_384, teardown) \ f(client, ecdsa_521_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_521, teardown) \ @@ -325,16 +320,21 @@ static int torture_pkd_setup_ecdsa_521(void **state) { #endif #ifdef HAVE_DSA +#define CHACHA20 "chacha20-poly1305@xxxxxxxxxxx" #define PKDTESTS_CIPHER_OPENSSHONLY(f, client, ciphercmd) \ /* Ciphers. */ \ f(client, rsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_rsa, teardown) \ f(client, rsa_aes192_ctr, ciphercmd("aes192-ctr"), setup_rsa, teardown) \ + f(client, rsa_chacha20, ciphercmd(CHACHA20), setup_rsa, teardown) \ f(client, dsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_dsa, teardown) \ f(client, dsa_aes192_ctr, ciphercmd("aes192-ctr"), setup_dsa, teardown) \ + f(client, dsa_chacha20, ciphercmd(CHACHA20), setup_dsa, teardown) \ f(client, ecdsa_256_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_256, teardown) \ f(client, ecdsa_256_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_256, teardown) \ + f(client, ecdsa_256_chacha20, ciphercmd(CHACHA20), setup_ecdsa_256, teardown) \ f(client, ecdsa_384_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \ + f(client, ecdsa_384_chacha20, ciphercmd(CHACHA20), setup_ecdsa_384, teardown) \ f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) #else @@ -347,7 +347,8 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_384_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \ f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \ - f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) + f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_chacha20, ciphercmd(CHACHA20), setup_ecdsa_521, teardown) #endif #ifdef HAVE_DSA -- 2.1.4 From ff325390c4c1229c8d8076bc5dae84d8683f69e2 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Thu, 10 May 2018 16:46:57 -0400 Subject: [PATCH 22/30] tests: fix torture_packet.c `test_data` Make the `test_data` larger so that tests do not read beyond its length. Observed in testing with an `-fsanitize=address` build locally. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/unittests/torture_packet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unittests/torture_packet.c b/tests/unittests/torture_packet.c index a01ea21..729aacc 100644 --- a/tests/unittests/torture_packet.c +++ b/tests/unittests/torture_packet.c @@ -13,7 +13,10 @@ #include <sys/socket.h> #include "socket.c" -uint8_t test_data[]="AThis is test data. Use it to check the validity of packet functions"; +uint8_t test_data[]="AThis is test data. Use it to check the validity of packet functions" + "AThis is test data. Use it to check the validity of packet functions" + "AThis is test data. Use it to check the validity of packet functions" + "AThis is test data. Use it to check the validity of packet functions"; uint8_t key[]="iekaeshoa7ooCie2shai8shahngee3ONsee3xoishooj0ojei6aeChieth1iraPh"; uint8_t iv[]="eixaxughoomah4ui7Aew3ohxuolaifuu"; uint8_t mac[]="thook2Jai0ahmahyae7ChuuruoPhee8Y"; -- 2.1.4 From 7d80a39135eb789d1f35929ce496252118167f22 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 8 Jun 2018 17:32:27 -0400 Subject: [PATCH 23/30] packet_crypt: fix unused variable compiler warning The local `rc` variable here is never set. Fix a warning that is emitted due to `-Wunused-variable`. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- src/packet_crypt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/packet_crypt.c b/src/packet_crypt.c index 68103af..57be946 100644 --- a/src/packet_crypt.c +++ b/src/packet_crypt.c @@ -102,7 +102,6 @@ int ssh_packet_decrypt(ssh_session session, size_t encrypted_size) { struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher; - int rc; if (encrypted_size <= 0) { return SSH_ERROR; -- 2.1.4 From 4e885fc2b6c3586721176c733f1db42182e81fd9 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Wed, 19 Jul 2017 17:23:16 -0400 Subject: [PATCH 24/30] chacha: use a cipher cleanup callback With this change there is less code specific to the chacha20-poly1305 cipher found in src/wrapper.c. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- src/chachapoly.c | 7 ++++++- src/wrapper.c | 3 --- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/chachapoly.c b/src/chachapoly.c index f3319b6..12600e8 100644 --- a/src/chachapoly.c +++ b/src/chachapoly.c @@ -187,6 +187,10 @@ static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher, return SSH_OK; } +static void chacha20_cleanup(struct ssh_cipher_struct *cipher) { + SAFE_FREE(cipher->chacha20_schedule); +} + const struct ssh_cipher_struct chacha20poly1305_cipher = { .name = "chacha20-poly1305@xxxxxxxxxxx", .blocksize = 8, @@ -198,5 +202,6 @@ const struct ssh_cipher_struct chacha20poly1305_cipher = { .set_decrypt_key = chacha20_set_encrypt_key, .aead_encrypt = chacha20_poly1305_aead_encrypt, .aead_decrypt_length = chacha20_poly1305_aead_decrypt_length, - .aead_decrypt = chacha20_poly1305_aead_decrypt + .aead_decrypt = chacha20_poly1305_aead_decrypt, + .cleanup = chacha20_cleanup }; diff --git a/src/wrapper.c b/src/wrapper.c index 77af522..961c3d0 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -128,9 +128,6 @@ void ssh_cipher_clear(struct ssh_cipher_struct *cipher){ if (cipher->cleanup != NULL) { cipher->cleanup(cipher); } - if (cipher->chacha20_schedule != NULL){ - SAFE_FREE(cipher->chacha20_schedule); - } } static void cipher_free(struct ssh_cipher_struct *cipher) { -- 2.1.4 From 8895b9337fa08b3af33909840eb081ff8944fa95 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 8 Jun 2018 18:32:32 -0400 Subject: [PATCH 25/30] packet_crypt: remove `set_decrypt_key` upon `ssh_packet_decrypt_len` In 06b9901e64f1ea2a1141115e5645552034d25850, invocations of `set_decrypt_key` and `set_encrypt_key` were moved into the `ssh_packet_newkeys` callback, away from the packet decrypt and encrypt functions. Remove the extra `set_decrypt_key` for the case that an `aead_decrypt_length` is not NULL. At this time, only the chacha20-poly1305@xxxxxxxxxxx cipher is affected by this change. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- src/packet_crypt.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/packet_crypt.c b/src/packet_crypt.c index 57be946..b2f075c 100644 --- a/src/packet_crypt.c +++ b/src/packet_crypt.c @@ -58,14 +58,6 @@ uint32_t ssh_packet_decrypt_len(ssh_session session, if (session->current_crypto != NULL) { if (session->current_crypto->in_cipher->aead_decrypt_length != NULL) { - rc = - session->current_crypto->in_cipher->set_decrypt_key( - session->current_crypto->in_cipher, - session->current_crypto->decryptkey, - session->current_crypto->decryptIV); - if (rc < 0) { - return (uint32_t)-1; - } session->current_crypto->in_cipher->aead_decrypt_length( session->current_crypto->in_cipher, source, destination, session->current_crypto->in_cipher->lenfield_blocksize, -- 2.1.4 From 3ae630aca316b4aa1c9dd8f7ab2b43734ff597dd Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 8 Jun 2018 16:16:49 -0700 Subject: [PATCH 26/30] pkd: fix CHACHA20 test lists Ensure that the CHACHA20 test entires are only included for OpenSSH. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/pkd_hello.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/pkd/pkd_hello.c b/tests/pkd/pkd_hello.c index 7c499be..c0994f1 100644 --- a/tests/pkd/pkd_hello.c +++ b/tests/pkd/pkd_hello.c @@ -316,7 +316,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_521_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown) \ f(client, ecdsa_521_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_521, teardown) \ - f(client, ecdsa_521_chacha20, ciphercmd(CHACHA20), setup_ecdsa_521, teardown) + f(client, ecdsa_521_blowfish_cbc, ciphercmd("blowfish-cbc"), setup_ecdsa_521, teardown) #endif #ifdef HAVE_DSA @@ -336,7 +336,8 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_chacha20, ciphercmd(CHACHA20), setup_ecdsa_384, teardown) \ f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \ - f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) + f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) \ + f(client, ecdsa_521_chacha20, ciphercmd(CHACHA20), setup_ecdsa_521, teardown) #else #define PKDTESTS_CIPHER_OPENSSHONLY(f, client, ciphercmd) \ /* Ciphers. */ \ @@ -347,8 +348,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) { f(client, ecdsa_384_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_384, teardown) \ f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \ f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \ - f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) \ - f(client, ecdsa_521_chacha20, ciphercmd(CHACHA20), setup_ecdsa_521, teardown) + f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) #endif #ifdef HAVE_DSA -- 2.1.4 From 0c1681553d74db4906f236d40c3c6faaab4f7e7a Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 8 Jun 2018 16:18:06 -0700 Subject: [PATCH 27/30] chacha: fix build for mbedTLS Fix the build for mbedTLS: * set HAVE_CHACHA for non-mbedTLS builds * only compile chachapoly.c when HAVE_CHACHA * use empty CHACHA20 in src/kex.c unless HAVE_CHACHA Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- ConfigureChecks.cmake | 3 ++- config.h.cmake | 3 +++ src/CMakeLists.txt | 8 +++++++- src/kex.c | 4 ++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index fd8ff13..3bb4a5e 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -138,7 +138,8 @@ endif () if (NOT WITH_MBEDTLS) set(HAVE_DSA 1) -endif() + set(HAVE_CHACHA 1) +endif (NOT WITH_MBEDTLS) # FUNCTIONS diff --git a/config.h.cmake b/config.h.cmake index 61d20ac..044e603 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -89,6 +89,9 @@ /* Define to 1 if you have DSA */ #cmakedefine HAVE_DSA 1 +/* Define to 1 if you have chacha20-poly1305 */ +#cmakedefine HAVE_CHACHA 1 + /*************************** FUNCTIONS ***************************/ /* Define to 1 if you have the `EVP_aes128_ctr' function. */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90e4425..4edc59f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -122,7 +122,6 @@ set(libssh_SRCS bignum.c buffer.c callbacks.c - chachapoly.c channels.c client.c config.c @@ -167,6 +166,13 @@ set(libssh_SRCS external/sc25519.c ) +if (NOT WITH_MBEDTLS) + set(libssh_SRCS + ${libssh_SRCS} + chachapoly.c + ) +endif (NOT WITH_MBEDTLS) + if (WITH_GCRYPT) set(libssh_SRCS ${libssh_SRCS} diff --git a/src/kex.c b/src/kex.c index 00f4e00..8c51566 100644 --- a/src/kex.c +++ b/src/kex.c @@ -95,7 +95,11 @@ #define ECDH "" #endif +#ifdef HAVE_CHACHA #define CHACHA20 "chacha20-poly1305@xxxxxxxxxxx," +#else /* HAVE_CHACHA */ +#define CHACHA20 +#endif /* HAVE_CHACHA */ #define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1" #define KEX_METHODS_SIZE 10 -- 2.1.4 From 54575f4ef1ce20d043ec0d93820ed977751ae1e9 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Fri, 15 Jun 2018 18:45:43 -0400 Subject: [PATCH 28/30] pkd: specify HostKeyAlgorithms for OpenSSH client As of OpenSSH 6.9, support for `ssh-dss` host keys is disabled by default at runtime. Specify an explicit `-o HostKeyAlgorithms` in the pkd tests to explicitly enable each host key type being tested, including `ssh-dss`. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/pkd_client.h | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/tests/pkd/pkd_client.h b/tests/pkd/pkd_client.h index c4a8a60..13909a6 100644 --- a/tests/pkd/pkd_client.h +++ b/tests/pkd/pkd_client.h @@ -2,24 +2,47 @@ * pkd_client.h -- macros for generating client-specific command * invocations for use with pkd testing * - * (c) 2014 Jon Simons + * (c) 2014, 2018 Jon Simons <jon@xxxxxxxxxxxxx> */ #ifndef __PKD_CLIENT_H__ #define __PKD_CLIENT_H__ +#include "config.h" + /* OpenSSH */ #define OPENSSH_BINARY "ssh" #define OPENSSH_KEYGEN "ssh-keygen" +#define OPENSSH_HOSTKEY_ALGOS_DEFAULT "ssh-rsa" + +#if HAVE_ECC +#define OPENSSH_HOSTKEY_ALGOS_ECDSA ",ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521" +#else /* HAVE_ECC */ +#define OPENSSH_HOSTKEY_ALGOS_ECDSA "" +#endif /* HAVE_ECC */ + +#if HAVE_DSA +#define OPENSSH_HOSTKEY_ALGOS_DSA ",ssh-dss" +#else /* HAVE_DSA */ +#define OPENSSH_HOSTKEY_ALGOS_DSA "" +#endif /* HAVE_DSA */ + +#define OPENSSH_HOSTKEY_ALGOS \ + "-o HostKeyAlgorithms=" \ + OPENSSH_HOSTKEY_ALGOS_DEFAULT \ + OPENSSH_HOSTKEY_ALGOS_ECDSA \ + OPENSSH_HOSTKEY_ALGOS_DSA + #define OPENSSH_CMD_START \ - OPENSSH_BINARY " " \ - "-o UserKnownHostsFile=/dev/null " \ - "-o StrictHostKeyChecking=no " \ - "-i " CLIENT_ID_FILE " " \ - "1> %s.out " \ - "2> %s.err " \ + OPENSSH_BINARY " " \ + "-o UserKnownHostsFile=/dev/null " \ + "-o StrictHostKeyChecking=no " \ + OPENSSH_HOSTKEY_ALGOS " " \ + "-i " CLIENT_ID_FILE " " \ + "1> %s.out " \ + "2> %s.err " \ "-vvv " #define OPENSSH_CMD_END "-p 1234 localhost ls" -- 2.1.4 From 2f564f169ad83506369ad23e04b44f36252a77b2 Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Mon, 18 Jun 2018 18:57:51 -0400 Subject: [PATCH 29/30] pkd: specify PubkeyAcceptedTypes for OpenSSH client As of OpenSSH 6.9, support for `ssh-dss` user keys is disabled by default at runtime. Specify an explicit `-o PubkeyAcceptedKeyTYpes` in the pkd tests to explicitly enable each user key type being tested, including `ssh-dss`. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/pkd_client.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/pkd/pkd_client.h b/tests/pkd/pkd_client.h index 13909a6..4f9b48b 100644 --- a/tests/pkd/pkd_client.h +++ b/tests/pkd/pkd_client.h @@ -15,18 +15,23 @@ #define OPENSSH_BINARY "ssh" #define OPENSSH_KEYGEN "ssh-keygen" -#define OPENSSH_HOSTKEY_ALGOS_DEFAULT "ssh-rsa" +#define OPENSSH_HOSTKEY_ALGOS_DEFAULT "ssh-ed25519,ssh-rsa" +#define OPENSSH_PKACCEPTED_DEFAULT "ssh-ed25519,ssh-rsa" #if HAVE_ECC #define OPENSSH_HOSTKEY_ALGOS_ECDSA ",ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521" +#define OPENSSH_PKACCEPTED_ECDSA ",ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521" #else /* HAVE_ECC */ #define OPENSSH_HOSTKEY_ALGOS_ECDSA "" +#define OPENSSH_PKACCEPTED_ECDSA "" #endif /* HAVE_ECC */ #if HAVE_DSA #define OPENSSH_HOSTKEY_ALGOS_DSA ",ssh-dss" +#define OPENSSH_PKACCEPTED_DSA ",ssh-dss" #else /* HAVE_DSA */ #define OPENSSH_HOSTKEY_ALGOS_DSA "" +#define OPENSSH_PKACCEPTED_DSA "" #endif /* HAVE_DSA */ #define OPENSSH_HOSTKEY_ALGOS \ @@ -35,11 +40,19 @@ OPENSSH_HOSTKEY_ALGOS_ECDSA \ OPENSSH_HOSTKEY_ALGOS_DSA +#define OPENSSH_PKACCEPTED_TYPES \ + "-o PubkeyAcceptedKeyTypes=" \ + OPENSSH_PKACCEPTED_DEFAULT \ + OPENSSH_PKACCEPTED_ECDSA \ + OPENSSH_PKACCEPTED_DSA + #define OPENSSH_CMD_START \ OPENSSH_BINARY " " \ "-o UserKnownHostsFile=/dev/null " \ "-o StrictHostKeyChecking=no " \ + "-F /dev/null " \ OPENSSH_HOSTKEY_ALGOS " " \ + OPENSSH_PKACCEPTED_TYPES " " \ "-i " CLIENT_ID_FILE " " \ "1> %s.out " \ "2> %s.err " \ -- 2.1.4 From b627e2662e31fea7d9eb5b84ce6854fa4b321bdb Mon Sep 17 00:00:00 2001 From: Jon Simons <jon@xxxxxxxxxxxxx> Date: Mon, 18 Jun 2018 19:31:35 -0400 Subject: [PATCH 30/30] pkd: emit error message for OpenSSH clients < 7.0 Emit a friendly error message for OpenSSH clients older than 7.0. Some of the recent pkd changes now require a modern client to support some newer config options. Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx> --- tests/pkd/pkd_util.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/tests/pkd/pkd_util.c b/tests/pkd/pkd_util.c index 963b58d..89a417f 100644 --- a/tests/pkd/pkd_util.c +++ b/tests/pkd/pkd_util.c @@ -1,12 +1,15 @@ /* * pkd_util.c -- pkd utilities * - * (c) 2014 Jon Simons + * (c) 2014, 2018 Jon Simons <jon@xxxxxxxxxxxxx> */ +#include <errno.h> +#include <limits.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/wait.h> #include "pkd_client.h" @@ -37,8 +40,64 @@ static int bin_exists(const char *binary) { return (system_checked(bin) == 0); } +static int is_openssh_client_new_enough(void) { + int rc = -1; + FILE *fp = NULL; + char version[1024] = { 0 }; + + int version_ok = 0; + unsigned long int major = 0; + char *tmp = NULL; + + fp = popen("ssh -V 2>&1", "r"); + if (fp == NULL) { + fprintf(stderr, "failed to get OpenSSH client version\n"); + goto done; + } + + if (fgets(&version[0], sizeof(version), fp) == NULL) { + fprintf(stderr, "failed to get OpenSSH client version string\n"); + goto errfgets; + } + + /* "OpenSSH_<major>.<minor><SP>..." */ + if (strlen(version) < 11) { + goto errversion; + } + + /* Extract major. */ + major = strtoul(version + 8, &tmp, 10); + if ((tmp == (version + 8)) || + ((errno = ERANGE) && (major == ULONG_MAX)) || + ((errno != 0) && (major == 0)) || + ((major < 1) || (major > 100))) { + fprintf(stderr, "failed to parse OpenSSH client version, " + "errno %d\n", errno); + goto errversion; + } + + if (major < 7) { + fprintf(stderr, "error: minimum OpenSSH client version " + "required is 7, found: %ld\n", major); + goto errversion; + } + + version_ok = 1; + +errversion: +errfgets: + rc = pclose(fp); + if (rc != 0) { + fprintf(stderr, "failed to get OpenSSH client version: %d\n", rc); + } +done: + return version_ok; +} + int is_openssh_client_enabled(void) { - return (bin_exists(OPENSSH_BINARY) && bin_exists(OPENSSH_KEYGEN)); + return (bin_exists(OPENSSH_BINARY) && + bin_exists(OPENSSH_KEYGEN) && + is_openssh_client_new_enough()); } int is_dropbear_client_enabled(void) { -- 2.1.4
Re: Missing signed-off for pkg chacha20 patches | Andreas Schneider <asn@xxxxxxxxxxxxxx> |
Missing signed-off for pkg chacha20 patches | Andreas Schneider <asn@xxxxxxxxxxxxxx> |
Re: Missing signed-off for pkg chacha20 patches | Andreas Schneider <asn@xxxxxxxxxxxxxx> |
Re: Missing signed-off for pkg chacha20 patches | Andreas Schneider <asn@xxxxxxxxxxxxxx> |
Re: Missing signed-off for pkg chacha20 patches | Andreas Schneider <asn@xxxxxxxxxxxxxx> |