[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Missing signed-off for pkg chacha20 patches


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


Follow-Ups:
Re: Missing signed-off for pkg chacha20 patchesAndreas Schneider <asn@xxxxxxxxxxxxxx>
References:
Missing signed-off for pkg chacha20 patchesAndreas Schneider <asn@xxxxxxxxxxxxxx>
Re: Missing signed-off for pkg chacha20 patchesAndreas Schneider <asn@xxxxxxxxxxxxxx>
Re: Missing signed-off for pkg chacha20 patchesAndreas Schneider <asn@xxxxxxxxxxxxxx>
Re: Missing signed-off for pkg chacha20 patchesAndreas Schneider <asn@xxxxxxxxxxxxxx>
Archive administrator: postmaster@lists.cynapses.org