Index: Makefile.in
===================================================================
RCS file: /cvsroot/cilogon/gssapi-openssh/openssh/Makefile.in,v
retrieving revision 1.5.2.52.2.17
retrieving revision 1.5.2.52.2.16
diff -u -r1.5.2.52.2.17 -r1.5.2.52.2.16
--- Makefile.in	8 Nov 2013 20:26:50 -0000	1.5.2.52.2.17
+++ Makefile.in	8 Nov 2013 13:42:44 -0000	1.5.2.52.2.16
@@ -71,7 +71,7 @@
 
 LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
 	canohost.o channels.o cipher.o cipher-aes.o \
-	cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
+	cipher-bf1.o cipher-ctr.o cipher-ctr-mt.o cipher-3des1.o cleanup.o \
 	compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
 	log.o match.o md-sha256.o moduli.o nchan.o packet.o \
 	readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
Index: cipher-ctr-mt.c
===================================================================
RCS file: cipher-ctr-mt.c
diff -N cipher-ctr-mt.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cipher-ctr-mt.c	8 Nov 2013 17:10:40 -0000	1.1.2.5
@@ -0,0 +1,507 @@
+/*
+ * OpenSSH Multi-threaded AES-CTR Cipher
+ *
+ * Author: Benjamin Bennett <ben@psc.edu>
+ * Author: Mike Tasota <tasota@gmail.com>
+ * Author: Chris Rapier <rapier@psc.edu>
+ * Copyright (c) 2008-2013 Pittsburgh Supercomputing Center. All rights reserved.
+ *
+ * Based on original OpenSSH AES-CTR cipher. Small portions remain unchanged,
+ * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "log.h"
+
+/* compatibility with old or broken OpenSSL versions */
+#include "openbsd-compat/openssl-compat.h"
+
+#ifndef USE_BUILTIN_RIJNDAEL
+#include <openssl/aes.h>
+#endif
+
+#include <pthread.h>
+
+/*-------------------- TUNABLES --------------------*/
+/* Number of pregen threads to use */
+#define CIPHER_THREADS	2
+
+/* Number of keystream queues */
+#define NUMKQ		(CIPHER_THREADS + 2)
+
+/* Length of a keystream queue */
+#define KQLEN		4096
+
+/* Processor cacheline length */
+#define CACHELINE_LEN	64
+
+/* Collect thread stats and print at cancellation when in debug mode */
+/* #define CIPHER_THREAD_STATS */
+
+/* Use single-byte XOR instead of 8-byte XOR */
+/* #define CIPHER_BYTE_XOR */
+/*-------------------- END TUNABLES --------------------*/
+
+
+const EVP_CIPHER *evp_aes_ctr_mt(void);
+
+#ifdef CIPHER_THREAD_STATS
+/*
+ * Struct to collect thread stats
+ */
+struct thread_stats {
+	u_int	fills;
+	u_int	skips;
+	u_int	waits;
+	u_int	drains;
+};
+
+/*
+ * Debug print the thread stats
+ * Use with pthread_cleanup_push for displaying at thread cancellation
+ */
+static void
+thread_loop_stats(void *x)
+{
+	struct thread_stats *s = x;
+
+	debug("tid %lu - %u fills, %u skips, %u waits", pthread_self(),
+			s->fills, s->skips, s->waits);
+}
+
+ #define STATS_STRUCT(s)	struct thread_stats s
+ #define STATS_INIT(s)		{ memset(&s, 0, sizeof(s)); }
+ #define STATS_FILL(s)		{ s.fills++; }
+ #define STATS_SKIP(s)		{ s.skips++; }
+ #define STATS_WAIT(s)		{ s.waits++; }
+ #define STATS_DRAIN(s)		{ s.drains++; }
+#else
+ #define STATS_STRUCT(s)
+ #define STATS_INIT(s)
+ #define STATS_FILL(s)
+ #define STATS_SKIP(s)
+ #define STATS_WAIT(s)
+ #define STATS_DRAIN(s)
+#endif
+
+/* Keystream Queue state */
+enum {
+	KQINIT,
+	KQEMPTY,
+	KQFILLING,
+	KQFULL,
+	KQDRAINING
+};
+
+/* Keystream Queue struct */
+struct kq {
+	u_char		keys[KQLEN][AES_BLOCK_SIZE];
+	u_char		ctr[AES_BLOCK_SIZE];
+	u_char		pad0[CACHELINE_LEN];
+	volatile int	qstate;
+	pthread_mutex_t	lock;
+	pthread_cond_t	cond;
+	u_char		pad1[CACHELINE_LEN];
+};
+
+/* Context struct */
+struct ssh_aes_ctr_ctx
+{
+	struct kq	q[NUMKQ];
+	AES_KEY		aes_ctx;
+	STATS_STRUCT(stats);
+	u_char		aes_counter[AES_BLOCK_SIZE];
+	pthread_t	tid[CIPHER_THREADS];
+	int		state;
+	int		qidx;
+	int		ridx;
+};
+
+/* <friedl>
+ * increment counter 'ctr',
+ * the counter is of size 'len' bytes and stored in network-byte-order.
+ * (LSB at ctr[len-1], MSB at ctr[0])
+ */
+static void
+ssh_ctr_inc(u_char *ctr, u_int len)
+{
+	int i;
+
+	for (i = len - 1; i >= 0; i--)
+		if (++ctr[i])	/* continue on overflow */
+			return;
+}
+
+/*
+ * Add num to counter 'ctr'
+ */
+static void
+ssh_ctr_add(u_char *ctr, uint32_t num, u_int len)
+{
+	int i;
+	uint16_t n;
+
+	for (n = 0, i = len - 1; i >= 0 && (num || n); i--) {
+		n = ctr[i] + (num & 0xff) + n;
+		num >>= 8;
+		ctr[i] = n & 0xff;
+		n >>= 8;
+	}
+}
+
+/*
+ * Threads may be cancelled in a pthread_cond_wait, we must free the mutex
+ */
+static void
+thread_loop_cleanup(void *x)
+{
+	pthread_mutex_unlock((pthread_mutex_t *)x);
+}
+
+/*
+ * The life of a pregen thread:
+ *    Find empty keystream queues and fill them using their counter.
+ *    When done, update counter for the next fill.
+ */
+static void *
+thread_loop(void *x)
+{
+	AES_KEY key;
+	STATS_STRUCT(stats);
+	struct ssh_aes_ctr_ctx *c = x;
+	struct kq *q;
+	int i;
+	int qidx;
+
+	/* Threads stats on cancellation */
+	STATS_INIT(stats);
+#ifdef CIPHER_THREAD_STATS
+	pthread_cleanup_push(thread_loop_stats, &stats);
+#endif
+
+	/* Thread local copy of AES key */
+	memcpy(&key, &c->aes_ctx, sizeof(key));
+
+	/*
+	 * Handle the special case of startup, one thread must fill
+ 	 * the first KQ then mark it as draining. Lock held throughout.
+ 	 */
+	if (pthread_equal(pthread_self(), c->tid[0])) {
+		q = &c->q[0];
+		pthread_mutex_lock(&q->lock);
+		if (q->qstate == KQINIT) {
+			for (i = 0; i < KQLEN; i++) {
+				AES_encrypt(q->ctr, q->keys[i], &key);
+				ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE);
+			}
+			ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE);
+			q->qstate = KQDRAINING;
+			STATS_FILL(stats);
+			pthread_cond_broadcast(&q->cond);
+		}
+		pthread_mutex_unlock(&q->lock);
+	}
+	else 
+		STATS_SKIP(stats);
+
+	/*
+ 	 * Normal case is to find empty queues and fill them, skipping over
+ 	 * queues already filled by other threads and stopping to wait for
+ 	 * a draining queue to become empty.
+ 	 *
+ 	 * Multiple threads may be waiting on a draining queue and awoken
+ 	 * when empty.  The first thread to wake will mark it as filling,
+ 	 * others will move on to fill, skip, or wait on the next queue.
+ 	 */
+	for (qidx = 1;; qidx = (qidx + 1) % NUMKQ) {
+		/* Check if I was cancelled, also checked in cond_wait */
+		pthread_testcancel();
+
+		/* Lock queue and block if its draining */
+		q = &c->q[qidx];
+		pthread_mutex_lock(&q->lock);
+		pthread_cleanup_push(thread_loop_cleanup, &q->lock);
+		while (q->qstate == KQDRAINING || q->qstate == KQINIT) {
+			STATS_WAIT(stats);
+			pthread_cond_wait(&q->cond, &q->lock);
+		}
+		pthread_cleanup_pop(0);
+
+		/* If filling or full, somebody else got it, skip */
+		if (q->qstate != KQEMPTY) {
+			pthread_mutex_unlock(&q->lock);
+			STATS_SKIP(stats);
+			continue;
+		}
+
+		/*
+ 		 * Empty, let's fill it.
+ 		 * Queue lock is relinquished while we do this so others
+ 		 * can see that it's being filled.
+ 		 */
+		q->qstate = KQFILLING;
+		pthread_mutex_unlock(&q->lock);
+		for (i = 0; i < KQLEN; i++) {
+			AES_encrypt(q->ctr, q->keys[i], &key);
+			ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE);
+		}
+
+		/* Re-lock, mark full and signal consumer */
+		pthread_mutex_lock(&q->lock);
+		ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE);
+		q->qstate = KQFULL;
+		STATS_FILL(stats);
+		pthread_cond_signal(&q->cond);
+		pthread_mutex_unlock(&q->lock);
+	}
+
+#ifdef CIPHER_THREAD_STATS
+	/* Stats */
+	pthread_cleanup_pop(1);
+#endif
+
+	return NULL;
+}
+
+static int
+ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
+    u_int len)
+{
+	struct ssh_aes_ctr_ctx *c;
+	struct kq *q, *oldq;
+	int ridx;
+	u_char *buf;
+
+	if (len == 0)
+		return (1);
+	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
+		return (0);
+
+	q = &c->q[c->qidx];
+	ridx = c->ridx;
+
+	/* src already padded to block multiple */
+	while (len > 0) {
+		buf = q->keys[ridx];
+
+#ifdef CIPHER_BYTE_XOR
+		dest[0] = src[0] ^ buf[0];
+		dest[1] = src[1] ^ buf[1];
+		dest[2] = src[2] ^ buf[2];
+		dest[3] = src[3] ^ buf[3];
+		dest[4] = src[4] ^ buf[4];
+		dest[5] = src[5] ^ buf[5];
+		dest[6] = src[6] ^ buf[6];
+		dest[7] = src[7] ^ buf[7];
+		dest[8] = src[8] ^ buf[8];
+		dest[9] = src[9] ^ buf[9];
+		dest[10] = src[10] ^ buf[10];
+		dest[11] = src[11] ^ buf[11];
+		dest[12] = src[12] ^ buf[12];
+		dest[13] = src[13] ^ buf[13];
+		dest[14] = src[14] ^ buf[14];
+		dest[15] = src[15] ^ buf[15];
+#else
+		*(uint64_t *)dest = *(uint64_t *)src ^ *(uint64_t *)buf;
+		*(uint64_t *)(dest + 8) = *(uint64_t *)(src + 8) ^
+						*(uint64_t *)(buf + 8);
+#endif
+
+		dest += 16;
+		src += 16;
+		len -= 16;
+		ssh_ctr_inc(ctx->iv, AES_BLOCK_SIZE);
+
+		/* Increment read index, switch queues on rollover */
+		if ((ridx = (ridx + 1) % KQLEN) == 0) {
+			oldq = q;
+
+			/* Mark next queue draining, may need to wait */
+			c->qidx = (c->qidx + 1) % NUMKQ;
+			q = &c->q[c->qidx];
+			pthread_mutex_lock(&q->lock);
+			while (q->qstate != KQFULL) {
+				STATS_WAIT(c->stats);
+				pthread_cond_wait(&q->cond, &q->lock);
+			}
+			q->qstate = KQDRAINING;
+			pthread_mutex_unlock(&q->lock);
+
+			/* Mark consumed queue empty and signal producers */
+			pthread_mutex_lock(&oldq->lock);
+			oldq->qstate = KQEMPTY;
+			STATS_DRAIN(c->stats);
+			pthread_cond_broadcast(&oldq->cond);
+			pthread_mutex_unlock(&oldq->lock);
+		}
+	}
+	c->ridx = ridx;
+	return (1);
+}
+
+#define HAVE_NONE       0
+#define HAVE_KEY        1
+#define HAVE_IV         2
+static int
+ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
+    int enc)
+{
+	struct ssh_aes_ctr_ctx *c;
+	int i;
+
+	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+		c = xmalloc(sizeof(*c));
+
+		c->state = HAVE_NONE;
+		for (i = 0; i < NUMKQ; i++) {
+			pthread_mutex_init(&c->q[i].lock, NULL);
+			pthread_cond_init(&c->q[i].cond, NULL);
+		}
+
+		STATS_INIT(c->stats);
+		
+		EVP_CIPHER_CTX_set_app_data(ctx, c);
+	}
+
+	if (c->state == (HAVE_KEY | HAVE_IV)) {
+		/* Cancel pregen threads */
+		for (i = 0; i < CIPHER_THREADS; i++)
+			pthread_cancel(c->tid[i]);
+		for (i = 0; i < CIPHER_THREADS; i++)
+			pthread_join(c->tid[i], NULL);
+		/* Start over getting key & iv */
+		c->state = HAVE_NONE;
+	}
+
+	if (key != NULL) {
+		AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
+		    &c->aes_ctx);
+		c->state |= HAVE_KEY;
+	}
+
+	if (iv != NULL) {
+		memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
+		c->state |= HAVE_IV;
+	}
+
+	if (c->state == (HAVE_KEY | HAVE_IV)) {
+		/* Clear queues */
+		memcpy(c->q[0].ctr, ctx->iv, AES_BLOCK_SIZE);
+		c->q[0].qstate = KQINIT;
+		for (i = 1; i < NUMKQ; i++) {
+			memcpy(c->q[i].ctr, ctx->iv, AES_BLOCK_SIZE);
+			ssh_ctr_add(c->q[i].ctr, i * KQLEN, AES_BLOCK_SIZE);
+			c->q[i].qstate = KQEMPTY;
+		}
+		c->qidx = 0;
+		c->ridx = 0;
+
+		/* Start threads */
+		for (i = 0; i < CIPHER_THREADS; i++) {
+			debug("spawned a thread");
+			pthread_create(&c->tid[i], NULL, thread_loop, c);
+		}
+		pthread_mutex_lock(&c->q[0].lock);
+		while (c->q[0].qstate != KQDRAINING)
+			pthread_cond_wait(&c->q[0].cond, &c->q[0].lock);
+		pthread_mutex_unlock(&c->q[0].lock);
+		
+	}
+	return (1);
+}
+
+/* this function is no longer used but might prove handy in the future
+ * this comment also applies to ssh_aes_ctr_thread_reconstruction
+ */
+void
+ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx)
+{
+	struct ssh_aes_ctr_ctx *c;
+	int i;
+	c = EVP_CIPHER_CTX_get_app_data(ctx);
+	/* destroy threads */
+	for (i = 0; i < CIPHER_THREADS; i++) {
+		pthread_cancel(c->tid[i]);
+	}
+	for (i = 0; i < CIPHER_THREADS; i++) {
+		pthread_join(c->tid[i], NULL);
+	}
+}
+
+void
+ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx)
+{
+	struct ssh_aes_ctr_ctx *c;
+	int i;
+	c = EVP_CIPHER_CTX_get_app_data(ctx);
+	/* reconstruct threads */
+	for (i = 0; i < CIPHER_THREADS; i++) {
+		debug("spawned a thread");
+		pthread_create(&c->tid[i], NULL, thread_loop, c);
+	}
+}
+
+static int
+ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
+{
+	struct ssh_aes_ctr_ctx *c;
+	int i;
+
+	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
+#ifdef CIPHER_THREAD_STATS
+		debug("main thread: %u drains, %u waits", c->stats.drains,
+				c->stats.waits);
+#endif
+		/* Cancel pregen threads */
+		for (i = 0; i < CIPHER_THREADS; i++)
+			pthread_cancel(c->tid[i]);
+		for (i = 0; i < CIPHER_THREADS; i++)
+			pthread_join(c->tid[i], NULL);
+
+		memset(c, 0, sizeof(*c));
+		free(c);
+		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
+	}
+	return (1);
+}
+
+/* <friedl> */
+const EVP_CIPHER *
+evp_aes_ctr_mt(void)
+{
+	static EVP_CIPHER aes_ctr;
+
+	memset(&aes_ctr, 0, sizeof(EVP_CIPHER));
+	aes_ctr.nid = NID_undef;
+	aes_ctr.block_size = AES_BLOCK_SIZE;
+	aes_ctr.iv_len = AES_BLOCK_SIZE;
+	aes_ctr.key_len = 16;
+	aes_ctr.init = ssh_aes_ctr_init;
+	aes_ctr.cleanup = ssh_aes_ctr_cleanup;
+	aes_ctr.do_cipher = ssh_aes_ctr;
+#ifndef SSH_OLD_EVP
+	aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
+	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
+#endif
+	return (&aes_ctr);
+}
Index: cipher.c
===================================================================
RCS file: /cvsroot/cilogon/gssapi-openssh/openssh/cipher.c,v
retrieving revision 1.1.1.2.2.13.2.6
retrieving revision 1.1.1.2.2.13.2.5
diff -u -r1.1.1.2.2.13.2.6 -r1.1.1.2.2.13.2.5
--- cipher.c	8 Nov 2013 20:26:50 -0000	1.1.1.2.2.13.2.6
+++ cipher.c	8 Nov 2013 13:42:45 -0000	1.1.1.2.2.13.2.5
@@ -55,6 +55,13 @@
 extern const EVP_CIPHER *evp_ssh1_3des(void);
 extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
 
+/* for multi-threaded aes-ctr cipher */
+extern const EVP_CIPHER *evp_aes_ctr_mt(void);
+
+/* no longer needed. replaced by evp pointer swap */
+/* extern void ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx); */
+/* extern void ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx); */
+
 struct Cipher {
 	char	*name;
 	int	number;		/* for ssh1 only */
@@ -67,7 +74,7 @@
 	const EVP_CIPHER	*(*evptype)(void);
 };
 
-static const struct Cipher ciphers[] = {
+static struct Cipher ciphers[] = {
 	{ "none",	SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
 	{ "des",	SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
 	{ "3des",	SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
@@ -121,6 +128,27 @@
 	return ret;
 }
 
+/* used to get the cipher name so when force rekeying to handle the 
+ * single to multithreaded ctr cipher swap we only rekey when appropriate
+*/
+char *
+cipher_return_name(const Cipher *c)
+{
+        return (c->name);
+}
+
+/* in order to get around sandbox and forking issues with a threaded cipher
+ * we set the initial pre-auth aes-ctr cipher to the default OpenSSH cipher
+ * post auth we set them to the new evp as defined by cipher-ctr-mt
+*/
+void
+cipher_reset_multithreaded()
+{
+  (cipher_by_name("aes128-ctr"))->evptype = evp_aes_ctr_mt;
+  (cipher_by_name("aes192-ctr"))->evptype = evp_aes_ctr_mt;
+  (cipher_by_name("aes256-ctr"))->evptype = evp_aes_ctr_mt;
+}
+
 u_int
 cipher_blocksize(const Cipher *c)
 {
@@ -169,7 +197,7 @@
 	return mask;
 }
 
-const Cipher *
+Cipher *
 cipher_by_name(const char *name)
 {
 	const Cipher *c;
Index: cipher.h
===================================================================
RCS file: /cvsroot/cilogon/gssapi-openssh/openssh/cipher.h,v
retrieving revision 1.1.1.2.2.4.2.4
retrieving revision 1.1.1.2.2.4.2.3
diff -u -r1.1.1.2.2.4.2.4 -r1.1.1.2.2.4.2.3
--- cipher.h	8 Nov 2013 20:26:50 -0000	1.1.1.2.2.4.2.4
+++ cipher.h	8 Nov 2013 13:42:45 -0000	1.1.1.2.2.4.2.3
@@ -69,8 +69,11 @@
 	const Cipher *cipher;
 };
 
+void ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx); // defined in cipher-ctr-mt.c
+void ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx);
+
 u_int	 cipher_mask_ssh1(int);
-const Cipher	*cipher_by_name(const char *);
+Cipher	*cipher_by_name(const char *);
 const Cipher	*cipher_by_number(int);
 int	 cipher_number(const char *);
 char	*cipher_name(int);
@@ -87,6 +90,8 @@
 u_int	 cipher_authlen(const Cipher *);
 u_int	 cipher_ivlen(const Cipher *);
 u_int	 cipher_is_cbc(const Cipher *);
+void	 cipher_reset_multithreaded(void);
+char 	*cipher_return_name(const Cipher *);
 
 u_int	 cipher_get_number(const Cipher *);
 void	 cipher_get_keyiv(CipherContext *, u_char *, u_int);
Index: ssh.c
===================================================================
RCS file: /cvsroot/cilogon/gssapi-openssh/openssh/ssh.c,v
retrieving revision 1.1.1.2.2.14.2.12
retrieving revision 1.1.1.2.2.14.2.11
diff -u -r1.1.1.2.2.14.2.12 -r1.1.1.2.2.14.2.11
--- ssh.c	8 Nov 2013 20:26:50 -0000	1.1.1.2.2.14.2.12
+++ ssh.c	8 Nov 2013 13:42:50 -0000	1.1.1.2.2.14.2.11
@@ -1060,6 +1060,8 @@
 	setproctitle("%s [mux]", options.control_path);
 }
 
+extern const EVP_CIPHER *evp_aes_ctr_mt(void);
+
 /* Do fork() after authentication. Used by "ssh -f" */
 static void
 fork_postauth(void)
Index: sshconnect2.c
===================================================================
RCS file: /cvsroot/cilogon/gssapi-openssh/openssh/sshconnect2.c,v
retrieving revision 1.4.2.19.2.13
retrieving revision 1.4.2.19.2.12
diff -u -r1.4.2.19.2.13 -r1.4.2.19.2.12
--- sshconnect2.c	8 Nov 2013 20:26:50 -0000	1.4.2.19.2.13
+++ sshconnect2.c	8 Nov 2013 13:42:50 -0000	1.4.2.19.2.12
@@ -513,6 +513,22 @@
                 }
         }
 
+        /* if we are using aes-ctr there can be issues in either a fork or sandbox
+         * so the initial aes-ctr is defined to point to the original single process
+         * evp. After authentication we'll be past the fork and the sandboxed privsep
+         * so we repoint the define to the multithreaded evp. To start the threads we
+         * then force a rekey
+         */
+        CipherContext *ccsend;
+        ccsend = (CipherContext*)packet_get_send_context();
+	
+	/* only do this for the ctr cipher. otherwise gcm mode breaks. Don't know why though */
+        if (strstr(cipher_return_name((Cipher*)ccsend->cipher), "ctr")) {
+		debug ("Single to Multithread CTR cipher swap - client request");
+                cipher_reset_multithreaded();
+                packet_request_rekeying();
+        }
+
 	debug("Authentication succeeded (%s).", authctxt.method->name);
 }
 
Index: sshd.c
===================================================================
RCS file: /cvsroot/cilogon/gssapi-openssh/openssh/sshd.c,v
retrieving revision 1.4.2.18.2.13
retrieving revision 1.4.2.18.2.12
diff -u -r1.4.2.18.2.13 -r1.4.2.18.2.12
--- sshd.c	8 Nov 2013 20:26:50 -0000	1.4.2.18.2.13
+++ sshd.c	8 Nov 2013 13:42:50 -0000	1.4.2.18.2.12
@@ -2321,6 +2321,22 @@
 
 	/* Start session. */
 
+	/* if we are using aes-ctr there can be issues in either a fork or sandbox
+         * so the initial aes-ctr is defined to point ot the original single process
+	 * evp. After authentication we'll be past the fork and the sandboxed privsep
+	 * so we repoint the define to the multithreaded evp. To start the threads we
+	 * then force a rekey
+	 */
+        CipherContext *ccsend;
+        ccsend = (CipherContext*)packet_get_send_context();
+
+	/* only rekey if necessary. If we don't do this gcm mode cipher breaks */
+	if (strstr(cipher_return_name((Cipher*)ccsend->cipher), "ctr")) {
+		debug ("Single to Multithreaded CTR cipher swap - server request");
+		cipher_reset_multithreaded();
+		packet_request_rekeying();
+	}
+
 	do_authenticated(authctxt);
 
 #ifdef NERSC_MOD
