summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ssh/libssh
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/ssh/libssh')
-rw-r--r--usr/src/cmd/ssh/libssh/Makefile.com5
-rw-r--r--usr/src/cmd/ssh/libssh/common/buffer.c24
-rw-r--r--usr/src/cmd/ssh/libssh/common/cipher-ctr.c76
-rw-r--r--usr/src/cmd/ssh/libssh/common/cipher.c13
-rw-r--r--usr/src/cmd/ssh/libssh/common/dh.c4
-rw-r--r--usr/src/cmd/ssh/libssh/common/engine.c112
-rw-r--r--usr/src/cmd/ssh/libssh/common/kex.c22
-rw-r--r--usr/src/cmd/ssh/libssh/common/packet.c279
-rw-r--r--usr/src/cmd/ssh/libssh/common/readconf.c14
-rw-r--r--usr/src/cmd/ssh/libssh/common/ssh-gss.c11
10 files changed, 441 insertions, 119 deletions
diff --git a/usr/src/cmd/ssh/libssh/Makefile.com b/usr/src/cmd/ssh/libssh/Makefile.com
index c691c21225..ebae4e0bcb 100644
--- a/usr/src/cmd/ssh/libssh/Makefile.com
+++ b/usr/src/cmd/ssh/libssh/Makefile.com
@@ -18,10 +18,10 @@
#
# CDDL HEADER END
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
+# ident "@(#)Makefile.com 1.19 08/08/12 SMI"
#
LIBRARY = libssh.a
@@ -43,6 +43,7 @@ OBJECTS = \
deattack.o \
dh.o \
dispatch.o \
+ engine.o \
fatal.o \
g11n.o \
mac.o \
diff --git a/usr/src/cmd/ssh/libssh/common/buffer.c b/usr/src/cmd/ssh/libssh/common/buffer.c
index 45d6860157..2ec761b7ad 100644
--- a/usr/src/cmd/ssh/libssh/common/buffer.c
+++ b/usr/src/cmd/ssh/libssh/common/buffer.c
@@ -10,11 +10,13 @@
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
/* $OpenBSD: buffer.c,v 1.31 2006/08/03 03:34:41 deraadt Exp $ */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "includes.h"
#include "xmalloc.h"
@@ -231,7 +233,6 @@ buffer_ptr(Buffer *buffer)
}
/* Dumps the contents of the buffer to stderr. */
-
void
buffer_dump(Buffer *buffer)
{
@@ -241,9 +242,22 @@ buffer_dump(Buffer *buffer)
for (i = buffer->offset; i < buffer->end; i++) {
fprintf(stderr, "%02x", ucp[i]);
if ((i-buffer->offset)%16==15)
- fprintf(stderr, "\r\n");
+ fprintf(stderr, "\n");
else if ((i-buffer->offset)%2==1)
fprintf(stderr, " ");
}
- fprintf(stderr, "\r\n");
+
+ if (buffer->offset == buffer->end) {
+ /* explicitly state when the buffer is empty */
+ fprintf(stderr, "<EMPTY BUFFER>\n");
+ } else {
+ /* print the terminal '\n' if it wasn't already printed */
+ if ((i - buffer->offset) % 16 != 0)
+ fprintf(stderr, "\n");
+ }
+ /*
+ * We want an extra empty line after the packet dump for better
+ * readability.
+ */
+ fprintf(stderr, "\n");
}
diff --git a/usr/src/cmd/ssh/libssh/common/cipher-ctr.c b/usr/src/cmd/ssh/libssh/common/cipher-ctr.c
index a5e95f6caa..d728064b53 100644
--- a/usr/src/cmd/ssh/libssh/common/cipher-ctr.c
+++ b/usr/src/cmd/ssh/libssh/common/cipher-ctr.c
@@ -14,32 +14,18 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+
#include "includes.h"
RCSID("$OpenBSD: cipher-ctr.c,v 1.4 2004/02/06 23:41:13 dtucker Exp $");
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <openssl/evp.h>
#include "log.h"
#include "xmalloc.h"
-
-#if OPENSSL_VERSION_NUMBER < 0x00906000L
-#define SSH_OLD_EVP
-#endif
-
-#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
-#include "rijndael.h"
-#define AES_KEY rijndael_ctx
-#define AES_BLOCK_SIZE 16
-#define AES_encrypt(a, b, c) rijndael_encrypt(c, a, b)
-#define AES_set_encrypt_key(a, b, c) rijndael_set_key(c, (u_char *)a, b, 1)
-#else
#include <openssl/aes.h>
-#endif
const EVP_CIPHER *evp_aes_128_ctr(void);
void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
@@ -133,22 +119,54 @@ ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, u_int len)
memcpy(iv, c->aes_counter, len);
}
+/*
+ * Function fills an EVP_CIPHER structure for AES CTR functions based on the NID
+ * and the key length.
+ */
+static const EVP_CIPHER *
+evp_aes_ctr(const char *nid, int key_len, EVP_CIPHER *aes_ctr)
+{
+ memset(aes_ctr, 0, sizeof(EVP_CIPHER));
+ /*
+ * If the PKCS#11 engine is used the AES CTR NIDs were dynamically
+ * created during the engine initialization. If the engine is not used
+ * we work with NID_undef's which is OK since in that case OpenSSL
+ * doesn't use NIDs at all.
+ */
+ if ((aes_ctr->nid = OBJ_ln2nid(nid)) != NID_undef)
+ debug3("%s NID found", nid);
+
+ aes_ctr->block_size = AES_BLOCK_SIZE;
+ aes_ctr->iv_len = AES_BLOCK_SIZE;
+ aes_ctr->key_len = key_len;
+ aes_ctr->init = ssh_aes_ctr_init;
+ aes_ctr->cleanup = ssh_aes_ctr_cleanup;
+ aes_ctr->do_cipher = ssh_aes_ctr;
+ aes_ctr->flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
+ return (aes_ctr);
+}
+
const EVP_CIPHER *
evp_aes_128_ctr(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);
+ return (evp_aes_ctr("aes-128-ctr", 16, &aes_ctr));
+}
+
+const EVP_CIPHER *
+evp_aes_192_ctr(void)
+{
+ static EVP_CIPHER aes_ctr;
+
+ return (evp_aes_ctr("aes-192-ctr", 24, &aes_ctr));
+}
+
+const EVP_CIPHER *
+evp_aes_256_ctr(void)
+{
+ static EVP_CIPHER aes_ctr;
+
+ return (evp_aes_ctr("aes-256-ctr", 32, &aes_ctr));
}
diff --git a/usr/src/cmd/ssh/libssh/common/cipher.c b/usr/src/cmd/ssh/libssh/common/cipher.c
index 391f5d3288..e09eba803c 100644
--- a/usr/src/cmd/ssh/libssh/common/cipher.c
+++ b/usr/src/cmd/ssh/libssh/common/cipher.c
@@ -42,8 +42,6 @@
#include "includes.h"
RCSID("$OpenBSD: cipher.c,v 1.61 2002/07/12 15:50:17 markus Exp $");
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "xmalloc.h"
#include "log.h"
#include "cipher.h"
@@ -55,7 +53,14 @@ RCSID("$OpenBSD: cipher.c,v 1.61 2002/07/12 15:50:17 markus Exp $");
#define EVP_CIPHER_CTX_get_app_data(e) ((e)->app_data)
#endif
+/*
+ * Symmetric ciphers can be offloaded to any engine through the EVP API only.
+ * However, OpenSSL doesn't offer AES in counter mode through EVP. So, we must
+ * define our own EVP functions.
+ */
extern const EVP_CIPHER *evp_aes_128_ctr(void);
+extern const EVP_CIPHER *evp_aes_192_ctr(void);
+extern const EVP_CIPHER *evp_aes_256_ctr(void);
extern void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
static const EVP_CIPHER *evp_ssh1_3des(void);
@@ -82,8 +87,8 @@ struct Cipher {
{ "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, EVP_aes_192_cbc },
{ "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, EVP_aes_256_cbc },
{ "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, evp_aes_128_ctr },
- { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, evp_aes_128_ctr },
- { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, evp_aes_128_ctr },
+ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, evp_aes_192_ctr },
+ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, evp_aes_256_ctr },
{ NULL, SSH_CIPHER_ILLEGAL, 0, 0, NULL }
};
diff --git a/usr/src/cmd/ssh/libssh/common/dh.c b/usr/src/cmd/ssh/libssh/common/dh.c
index f6643a09af..9293db7bb7 100644
--- a/usr/src/cmd/ssh/libssh/common/dh.c
+++ b/usr/src/cmd/ssh/libssh/common/dh.c
@@ -25,8 +25,6 @@
#include "includes.h"
RCSID("$OpenBSD: dh.c,v 1.22 2002/06/27 08:49:44 markus Exp $");
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "xmalloc.h"
#include <openssl/bn.h>
@@ -212,7 +210,7 @@ dh_gen_key(DH *dh, int need)
if (!BN_rand(dh->priv_key, 2*need, 0, 0))
fatal("dh_gen_key: BN_rand failed");
if (DH_generate_key(dh) == 0)
- fatal("DH_generate_key");
+ fatal("dh_gen_key: DH_generate_key() failed");
for (i = 0; i <= BN_num_bits(dh->priv_key); i++)
if (BN_is_bit_set(dh->priv_key, i))
bits_set++;
diff --git a/usr/src/cmd/ssh/libssh/common/engine.c b/usr/src/cmd/ssh/libssh/common/engine.c
new file mode 100644
index 0000000000..5565c269e0
--- /dev/null
+++ b/usr/src/cmd/ssh/libssh/common/engine.c
@@ -0,0 +1,112 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "includes.h"
+#include "log.h"
+#include "engine.h"
+
+#define PKCS11_ENGINE "pkcs11"
+
+/*
+ * Loads the PKCS#11 engine if the UseOpenSSLEngine is set to yes which is the
+ * default value.
+ */
+ENGINE *
+pkcs11_engine_load(int use_engine)
+{
+ ENGINE *e = NULL;
+
+ debug("use_engine is '%s'", use_engine == 1 ? "yes" : "no");
+ if (use_engine == 0)
+ return (NULL);
+
+ ENGINE_load_pk11();
+ /* get structural reference */
+ if ((e = ENGINE_by_id(PKCS11_ENGINE)) == NULL) {
+ fatal("%s engine does not exist", PKCS11_ENGINE);
+ }
+
+ /* get functional reference */
+ if (ENGINE_init(e) == 0) {
+ fatal("can't initialize %s engine", PKCS11_ENGINE);
+ }
+
+ debug("%s engine initialized, now setting it as default for "
+ "RSA, DSA, and symmetric ciphers", PKCS11_ENGINE);
+
+ /*
+ * Offloading RSA, DSA and symmetric ciphers to the engine is all we
+ * want. We don't offload Diffie-Helmann since we use longer DH keys
+ * than supported in ncp/n2cp (2048 bits). And, we don't offload digest
+ * operations since that would be beneficial if only big packets were
+ * processed (~8K). However, that's not the case. For example,
+ * SSH_MSG_CHANNEL_WINDOW_ADJUST messages are always small. Given the
+ * fact that digest operations are fast in software and the inherent
+ * overhead of offloading anything to HW is quite big, not offloading
+ * digests to HW actually makes SSH data transfer faster.
+ */
+ if (!ENGINE_set_default_RSA(e)) {
+ fatal("can't use %s engine for RSA", PKCS11_ENGINE);
+ }
+ if (!ENGINE_set_default_DSA(e)) {
+ fatal("can't use %s engine for DSA", PKCS11_ENGINE);
+ }
+ if (!ENGINE_set_default_ciphers(e)) {
+ fatal("can't use %s engine for ciphers", PKCS11_ENGINE);
+ }
+
+ debug("%s engine initialization complete", PKCS11_ENGINE);
+ return (e);
+}
+
+/*
+ * Finishes the PKCS#11 engine after all remaining structural and functional
+ * references to the ENGINE structure are freed.
+ */
+void
+pkcs11_engine_finish(void *engine)
+{
+ ENGINE *e = (ENGINE *)engine;
+
+ debug("in pkcs11_engine_finish(), engine pointer is %p", e);
+ /* UseOpenSSLEngine was 'no' */
+ if (engine == NULL)
+ return;
+
+ debug("unregistering RSA");
+ ENGINE_unregister_RSA(e);
+ debug("unregistering DSA");
+ ENGINE_unregister_DSA(e);
+ debug("unregistering ciphers");
+ ENGINE_unregister_ciphers(e);
+
+ debug("calling ENGINE_finish()");
+ ENGINE_finish(engine);
+ debug("calling ENGINE_remove()");
+ ENGINE_remove(engine);
+ debug("calling ENGINE_free()");
+ ENGINE_free(engine);
+ debug("%s engine finished", PKCS11_ENGINE);
+}
diff --git a/usr/src/cmd/ssh/libssh/common/kex.c b/usr/src/cmd/ssh/libssh/common/kex.c
index d535254210..358e80625d 100644
--- a/usr/src/cmd/ssh/libssh/common/kex.c
+++ b/usr/src/cmd/ssh/libssh/common/kex.c
@@ -21,15 +21,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "includes.h"
RCSID("$OpenBSD: kex.c,v 1.51 2002/06/24 14:55:38 markus Exp $");
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <locale.h>
#include <openssl/crypto.h>
@@ -266,6 +264,18 @@ kex_do_hook(Kex *kex)
kex_prop_free(prop);
}
+/* Initiate the key exchange by sending the SSH2_MSG_KEXINIT message. */
+void
+kex_start(Kex *kex)
+{
+ kex_send_kexinit(kex);
+ kex_reset_dispatch();
+}
+
+/*
+ * Allocate a key exchange structure and populate it with a proposal we are
+ * going to use. This function does not start the actual key exchange.
+ */
Kex *
kex_setup(const char *host, char *proposal[PROPOSAL_MAX], Kex_hook_func hook)
{
@@ -285,9 +295,6 @@ kex_setup(const char *host, char *proposal[PROPOSAL_MAX], Kex_hook_func hook)
kex_prop2buf(&kex->my, proposal);
- kex_send_kexinit(kex);
- kex_reset_dispatch();
-
return kex;
}
@@ -364,7 +371,8 @@ choose_kex(Kex *k, char *client, char *server)
{
k->name = match_list(client, server, NULL);
if (k->name == NULL)
- fatal("no kex alg");
+ fatal("no common kex alg: client '%s', server '%s'", client,
+ server);
/* XXX Finish 3.6/7 merge of kex stuff -- choose_kex() done */
if (strcmp(k->name, KEX_DH1) == 0) {
k->kex_type = KEX_DH_GRP1_SHA1;
diff --git a/usr/src/cmd/ssh/libssh/common/packet.c b/usr/src/cmd/ssh/libssh/common/packet.c
index 51b4183cca..59a33a1a98 100644
--- a/usr/src/cmd/ssh/libssh/common/packet.c
+++ b/usr/src/cmd/ssh/libssh/common/packet.c
@@ -42,8 +42,6 @@
/* $OpenBSD: packet.c,v 1.148 2007/06/07 19:37:34 pvalchev Exp $ */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "includes.h"
#include "sys-queue.h"
@@ -66,6 +64,10 @@
#include "canohost.h"
#include "misc.h"
#include "ssh.h"
+#include "engine.h"
+
+/* PKCS#11 engine */
+ENGINE *e;
#ifdef ALTPRIVSEP
static int packet_server = 0;
@@ -78,6 +80,8 @@ static int packet_monitor = 0;
#define DBG(x)
#endif
+static void packet_send2(void);
+
/*
* This variable contains the file descriptors used for communicating with
* the other side. connection_in is used for reading; connection_out for
@@ -150,6 +154,31 @@ struct packet {
TAILQ_HEAD(, packet) outgoing;
/*
+ * Part of what -f option and ~& escape sequence do in the client is that they
+ * will force it to daemonize itself. Due to the fork safety rules inherent in
+ * any PKCS#11 environment, if the engine is used we must do a key re-exchange
+ * before forking a child to negotiate the new keys. Those keys will be used to
+ * inicialize the new crypto contexts. This involves finishing the engine in the
+ * parent and reinitializing it again in both processes after fork() returns.
+ * This approach also leaves protocol 1 out since it doesn't support rekeying.
+ */
+int will_daemonize;
+
+#ifdef PACKET_DEBUG
+/* This function dumps data onto stderr. This is for debugging only. */
+void
+data_dump(void *data, u_int len)
+{
+ Buffer buf;
+
+ buffer_init(&buf);
+ buffer_append(&buf, data, len);
+ buffer_dump(&buf);
+ buffer_free(&buf);
+}
+#endif
+
+/*
* Sets the descriptors used for communication. Disables encryption until
* packet_set_encryption_key is called.
*/
@@ -520,7 +549,8 @@ packet_send1(void)
buffer_len(&outgoing_packet));
#ifdef PACKET_DEBUG
- fprintf(stderr, "encrypted: ");
+ debug("encrypted output queue now contains (%d bytes):\n",
+ buffer_len(&output));
buffer_dump(&output);
#endif
@@ -556,12 +586,15 @@ set_newkeys(int mode)
p_read.packets = p_read.blocks = 0;
max_blocks = &max_blocks_in;
}
+
+ debug("set_newkeys: setting new keys for '%s' mode",
+ mode == MODE_IN ? "in" : "out");
+
if (newkeys[mode] != NULL) {
- debug("set_newkeys: setting new keys for '%s' mode",
- mode == MODE_IN ? "in" : "out");
cipher_cleanup(cc);
free_keys(newkeys[mode]);
}
+
newkeys[mode] = kex_get_newkeys(mode);
if (newkeys[mode] == NULL)
fatal("newkeys: no keys for mode %d", mode);
@@ -570,7 +603,14 @@ set_newkeys(int mode)
comp = &newkeys[mode]->comp;
if (mac->md != NULL)
mac->enabled = 1;
- DBG(debug("cipher_init_context: %d", mode));
+#ifdef PACKET_DEBUG
+ debug("new encryption key:\n");
+ data_dump(enc->key, enc->key_len);
+ debug("new encryption IV:\n");
+ data_dump(enc->iv, enc->block_size);
+ debug("new MAC key:\n");
+ data_dump(mac->key, mac->key_len);
+#endif
cipher_init(cc, enc->cipher, enc->key, enc->key_len,
enc->iv, enc->block_size, crypt_type);
/* Deleting the keys does not gain extra security */
@@ -642,6 +682,43 @@ free_keys(Newkeys *keys)
}
/*
+ * Process SSH2_MSG_NEWKEYS message. If we are using the engine we must have
+ * both SSH2_MSG_NEWKEYS processed before we can finish the engine, fork, and
+ * reinitialize the crypto contexts. We can't fork before processing the 2nd
+ * message otherwise we couldn't encrypt/decrypt that message at all - note that
+ * parent's PKCS#11 sessions are useless after the fork and we must process
+ * both SSH2_MSG_NEWKEYS messages using the old keys.
+ */
+void
+process_newkeys(int mode)
+{
+ if (packet_is_server() != 0)
+ return;
+
+ if (will_daemonize == FIRST_NEWKEYS_PROCESSED) {
+ debug3("both SSH2_MSG_NEWKEYS processed, will daemonize now");
+ cipher_cleanup(&send_context);
+ cipher_cleanup(&receive_context);
+ pkcs11_engine_finish(e);
+ if (daemon(1, 1) < 0) {
+ fatal("daemon() failed: %.200s",
+ strerror(errno));
+ }
+ e = pkcs11_engine_load(e != NULL ? 1 : 0);
+
+ set_newkeys(MODE_OUT);
+ set_newkeys(MODE_IN);
+ will_daemonize = SECOND_NEWKEYS_PROCESSED;
+ packet_send2();
+ } else {
+ if (will_daemonize == DAEMONIZING_REQUESTED)
+ will_daemonize = FIRST_NEWKEYS_PROCESSED;
+ else
+ set_newkeys(mode);
+ }
+}
+
+/*
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
*/
static void
@@ -668,7 +745,8 @@ packet_send2_wrapped(void)
type = cp[5];
#ifdef PACKET_DEBUG
- fprintf(stderr, "plain: ");
+ debug("plain output packet to be processed (%d bytes):\n",
+ buffer_len(&outgoing_packet));
buffer_dump(&outgoing_packet);
#endif
@@ -723,7 +801,8 @@ packet_send2_wrapped(void)
cp = buffer_ptr(&outgoing_packet);
PUT_32BIT(cp, packet_length);
cp[4] = padlen;
- DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
+ DBG(debug("will send %d bytes (includes padlen %d)",
+ packet_length + 4, padlen));
/* compute MAC over seqnr and packet(length fields, payload, padding) */
if (mac && mac->enabled) {
@@ -740,7 +819,8 @@ packet_send2_wrapped(void)
if (mac && mac->enabled)
buffer_append(&output, (char *)macbuf, mac->mac_len);
#ifdef PACKET_DEBUG
- fprintf(stderr, "encrypted: ");
+ debug("encrypted output queue now contains (%d bytes):\n",
+ buffer_len(&output));
buffer_dump(&output);
#endif
/* increment sequence number for outgoing packets */
@@ -765,14 +845,29 @@ packet_send2_wrapped(void)
p_send.blocks += (packet_length + 4) / block_size;
buffer_clear(&outgoing_packet);
- if (type == SSH2_MSG_NEWKEYS)
-#ifdef ALTPRIVSEP
- /* set_newkeys(MODE_OUT) in client, server, but not monitor */
- if (!packet_is_server() && !packet_is_monitor())
-#endif /* ALTPRIVSEP */
- set_newkeys(MODE_OUT);
+ if (type == SSH2_MSG_NEWKEYS) {
+ /*
+ * set_newkeys(MODE_OUT) in the client. Note that in the
+ * unprivileged child, set_newkeys() for MODE_OUT are set after
+ * SSH2_MSG_NEWKEYS is read from the monitor and forwarded to
+ * the client side.
+ */
+ process_newkeys(MODE_OUT);
+ }
}
+/*
+ * Packets we deal with here are plain until we encrypt them in
+ * packet_send2_wrapped().
+ *
+ * As already mentioned in a comment at process_newkeys() function we must not
+ * fork() until both SSH2_MSG_NEWKEYS packets were processed. Until this is done
+ * we must queue all packets so that they can be encrypted with the new keys and
+ * then sent to the other side. However, what can happen here is that we get
+ * SSH2_MSG_NEWKEYS after we sent it. In that situation we must call
+ * packet_send2() anyway to empty the queue, and set the rekey flag to the
+ * finished state. If we didn't do that we would just hang and enqueue data.
+ */
static void
packet_send2(void)
{
@@ -780,35 +875,41 @@ packet_send2(void)
struct packet *p;
u_char type, *cp;
- cp = buffer_ptr(&outgoing_packet);
- type = cp[5];
-
- /* during rekeying we can only send key exchange messages */
- if (rekeying) {
- if (!((type >= SSH2_MSG_TRANSPORT_MIN) &&
- (type <= SSH2_MSG_TRANSPORT_MAX))) {
- debug("enqueue packet: %u", type);
- p = xmalloc(sizeof(*p));
- p->type = type;
- memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));
- buffer_init(&outgoing_packet);
- TAILQ_INSERT_TAIL(&outgoing, p, next);
- return;
+ if (will_daemonize != SECOND_NEWKEYS_PROCESSED) {
+ cp = buffer_ptr(&outgoing_packet);
+ type = cp[5];
+
+ /* during rekeying we can only send key exchange messages */
+ if (rekeying) {
+ if (!((type >= SSH2_MSG_TRANSPORT_MIN) &&
+ (type <= SSH2_MSG_TRANSPORT_MAX))) {
+ debug("enqueue a plain packet because rekex in "
+ "progress [type %u]", type);
+ p = xmalloc(sizeof(*p));
+ p->type = type;
+ memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));
+ buffer_init(&outgoing_packet);
+ TAILQ_INSERT_TAIL(&outgoing, p, next);
+ return;
+ }
}
- }
- /* rekeying starts with sending KEXINIT */
- if (type == SSH2_MSG_KEXINIT)
- rekeying = 1;
+ /* rekeying starts with sending KEXINIT */
+ if (type == SSH2_MSG_KEXINIT)
+ rekeying = 1;
- packet_send2_wrapped();
+ packet_send2_wrapped();
+ }
- /* after a NEWKEYS message we can send the complete queue */
- if (type == SSH2_MSG_NEWKEYS) {
+ /* after rekex is done we can process the queue of plain packets */
+ if (will_daemonize == SECOND_NEWKEYS_PROCESSED ||
+ (will_daemonize == NOT_DAEMONIZING && type == SSH2_MSG_NEWKEYS)) {
rekeying = 0;
+ will_daemonize = NOT_DAEMONIZING;
while ((p = TAILQ_FIRST(&outgoing)) != NULL) {
type = p->type;
- debug("dequeue packet: %u", type);
+ debug("dequeuing a plain packet since rekex is over "
+ "[type %u]", type);
buffer_free(&outgoing_packet);
memcpy(&outgoing_packet, &p->payload, sizeof(Buffer));
TAILQ_REMOVE(&outgoing, p, next);
@@ -973,7 +1074,7 @@ packet_read_poll1(void)
buffer_consume(&input, padded_len);
#ifdef PACKET_DEBUG
- fprintf(stderr, "read_poll plain: ");
+ debug("read_poll plain/full:\n");
buffer_dump(&incoming_packet);
#endif
@@ -1032,6 +1133,11 @@ packet_read_poll2(u_int32_t *seqnr_p)
*/
if (buffer_len(&input) < block_size)
return SSH_MSG_NONE;
+#ifdef PACKET_DEBUG
+ debug("encrypted data we have in read queue (%d bytes):\n",
+ buffer_len(&input));
+ buffer_dump(&input);
+#endif
buffer_clear(&incoming_packet);
cp = buffer_append_space(&incoming_packet, block_size);
cipher_crypt(&receive_context, cp, buffer_ptr(&input),
@@ -1039,15 +1145,23 @@ packet_read_poll2(u_int32_t *seqnr_p)
cp = buffer_ptr(&incoming_packet);
packet_length = GET_32BIT(cp);
if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
+ error("bad packet length %d; i/o counters "
+ "%llu/%llu", packet_length,
+ p_read.blocks * block_size,
+ p_send.blocks * block_size);
+ error("decrypted %d bytes follows:\n", block_size);
buffer_dump(&incoming_packet);
- packet_disconnect("Bad packet length %d.", packet_length);
+ packet_disconnect("Bad packet length %d, i/o counters "
+ "%llu/%llu.", packet_length,
+ p_read.blocks * block_size,
+ p_send.blocks * block_size);
}
DBG(debug("input: packet len %u", packet_length + 4));
buffer_consume(&input, block_size);
}
/* we have a partial packet of block_size bytes */
need = 4 + packet_length - block_size;
- DBG(debug("partial packet %d, need %d, maclen %d", block_size,
+ DBG(debug("partial packet %d, still need %d, maclen %d", block_size,
need, maclen));
if (need % block_size != 0)
fatal("padding error: need %d block %d mod %d",
@@ -1059,7 +1173,8 @@ packet_read_poll2(u_int32_t *seqnr_p)
if (buffer_len(&input) < need + maclen)
return SSH_MSG_NONE;
#ifdef PACKET_DEBUG
- fprintf(stderr, "read_poll enc/full: ");
+ debug("in read_poll, the encrypted input queue now contains "
+ "(%d bytes):\n", buffer_len(&input));
buffer_dump(&input);
#endif
cp = buffer_append_space(&incoming_packet, need);
@@ -1115,17 +1230,20 @@ packet_read_poll2(u_int32_t *seqnr_p)
* return length of payload (without type field)
*/
type = buffer_get_char(&incoming_packet);
-#ifdef ALTPRIVSEP
- if (type == SSH2_MSG_NEWKEYS)
- /* set_newkeys(MODE_OUT) in client, server, but not monitor */
- if (!packet_is_server() && !packet_is_monitor())
- set_newkeys(MODE_IN);
-#else /* ALTPRIVSEP */
- if (type == SSH2_MSG_NEWKEYS)
- set_newkeys(MODE_IN);
-#endif /* ALTPRIVSEP */
+ if (type == SSH2_MSG_NEWKEYS) {
+ /*
+ * set_newkeys(MODE_IN) in the client because it doesn't have a
+ * dispatch function for SSH2_MSG_NEWKEYS in contrast to the
+ * server processes. Note that in the unprivileged child,
+ * set_newkeys() for MODE_IN are set in dispatch function
+ * altprivsep_rekey() after SSH2_MSG_NEWKEYS packet is received
+ * from the client.
+ */
+ process_newkeys(MODE_IN);
+ }
+
#ifdef PACKET_DEBUG
- fprintf(stderr, "read/plain[%d]:\r\n", type);
+ debug("decrypted input packet [type %d]:\n", type);
buffer_dump(&incoming_packet);
#endif
/* reset for next packet */
@@ -1133,6 +1251,10 @@ packet_read_poll2(u_int32_t *seqnr_p)
return type;
}
+/*
+ * This tries to read a packet from the buffer of received data. Note that it
+ * doesn't read() anything from the network socket.
+ */
int
packet_read_poll_seqnr(u_int32_t *seqnr_p)
{
@@ -1414,6 +1536,10 @@ packet_write_poll(void)
else
fatal("Write failed: %.100s", strerror(errno));
}
+#ifdef PACKET_DEBUG
+ debug("in packet_write_poll, %d bytes just sent to the "
+ "remote side", len);
+#endif
buffer_consume(&output, len);
}
}
@@ -1608,12 +1734,6 @@ packet_set_server(void)
packet_server = 1;
}
-void
-packet_set_no_monitor(void)
-{
- packet_server = 0;
-}
-
int
packet_is_server(void)
{
@@ -1661,18 +1781,57 @@ packet_set_monitor(int pipe)
/*
* make sure that the monitor's child's socket is not shutdown(3SOCKET)
- * when we packet_close()
+ * when we packet_close(). Setting connection_out to -1 will take care
+ * of that.
*/
if (packet_connection_is_on_socket())
connection_out = -1;
- /* now cleanup state related to ssh socket */
+ /*
+ * Now clean up the state related to the server socket. As a side
+ * effect, we also clean up existing cipher contexts that were
+ * initialized with 'none' cipher in packet_set_connection(). That
+ * function was called in the child server process shortly after the
+ * master SSH process forked. However, all of that is reinialized again
+ * by another packet_set_connection() call right below.
+ */
packet_close();
- /* now make the monitor pipe look like the ssh connection */
+ /*
+ * Now make the monitor pipe look like the ssh connection which means
+ * that connection_in and connection_out will be set to the
+ * communication pipe descriptors.
+ */
packet_set_connection(pipe, dup_fd);
}
+/*
+ * We temporarily need to set connection_in and connection_out descriptors so
+ * that we can make use of existing code that gets the IP address and hostname
+ * of the peer to write a login/logout record. It's not nice but we would have
+ * to change more code when implementing the PKCS#11 engine support.
+ */
+void
+packet_set_fds(int fd, int restore)
+{
+ static int stored_fd;
+
+ if (stored_fd == 0 && restore == 0) {
+ debug3("packet_set_fds: saving %d, installing %d",
+ connection_in, fd);
+ stored_fd = connection_in;
+ /* we don't have a socket in inetd mode */
+ if (fd != -1)
+ connection_in = connection_out = fd;
+ return;
+ }
+
+ if (restore == 1) {
+ debug3("restoring %d to connection_in/out", stored_fd);
+ connection_in = connection_out = stored_fd;
+ }
+}
+
int
packet_is_monitor(void)
{
diff --git a/usr/src/cmd/ssh/libssh/common/readconf.c b/usr/src/cmd/ssh/libssh/common/readconf.c
index e08ff1e0b0..fe0b7a3ee8 100644
--- a/usr/src/cmd/ssh/libssh/common/readconf.c
+++ b/usr/src/cmd/ssh/libssh/common/readconf.c
@@ -11,15 +11,13 @@
* called by a name other than "ssh" or "Secure Shell".
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "includes.h"
RCSID("$OpenBSD: readconf.c,v 1.100 2002/06/19 00:27:55 deraadt Exp $");
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "ssh.h"
#include "xmalloc.h"
#include "compat.h"
@@ -129,7 +127,7 @@ typedef enum {
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oFallBackToRsh, oUseRsh, oConnectTimeout, oHashKnownHosts,
oServerAliveInterval, oServerAliveCountMax, oDisableBanner,
- oIgnoreIfUnknown, oRekeyLimit,
+ oIgnoreIfUnknown, oRekeyLimit, oUseOpenSSLEngine,
oDeprecated
} OpCodes;
@@ -223,6 +221,7 @@ static struct {
{ "disablebanner", oDisableBanner },
{ "hashknownhosts", oHashKnownHosts },
{ "ignoreifunknown", oIgnoreIfUnknown },
+ { "useopensslengine", oUseOpenSSLEngine },
{ NULL, oBadOption }
};
@@ -850,6 +849,10 @@ parse_int:
charptr = &options->ignore_if_unknown;
goto parse_string;
+ case oUseOpenSSLEngine:
+ intptr = &options->use_openssl_engine;
+ goto parse_flag;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@@ -989,6 +992,7 @@ initialize_options(Options * options)
options->ignore_if_unknown = NULL;
options->unknown_opts_num = 0;
options->disable_banner = -1;
+ options->use_openssl_engine = -1;
}
/*
@@ -1135,6 +1139,8 @@ fill_default_options(Options * options)
options->hash_known_hosts = 0;
if (options->disable_banner == -1)
options->disable_banner = 0;
+ if (options->use_openssl_engine == -1)
+ options->use_openssl_engine = 1;
/* options->proxy_command should not be set by default */
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
diff --git a/usr/src/cmd/ssh/libssh/common/ssh-gss.c b/usr/src/cmd/ssh/libssh/common/ssh-gss.c
index c784426e90..4de5abb1da 100644
--- a/usr/src/cmd/ssh/libssh/common/ssh-gss.c
+++ b/usr/src/cmd/ssh/libssh/common/ssh-gss.c
@@ -29,8 +29,6 @@
#ifdef GSSAPI
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "ssh.h"
#include "ssh2.h"
#include "xmalloc.h"
@@ -246,6 +244,7 @@ ssh_gssapi_encode_oid_for_kex(const gss_OID oid, char **enc_name)
buffer_put_char(&buf, '\0');
debug2("GSS-API Mechanism encoded as %s", encoded);
+ xfree(encoded);
*enc_name = xstrdup(buffer_ptr(&buf));
buffer_free(&buf);
@@ -271,6 +270,7 @@ ssh_gssapi_make_kexalgs_list(gss_OID_set mechs, const char *old_kexalgs)
len = strlen(old_kexalgs) + strlen(gss_kexalgs) + 2;
new_kexalgs = xmalloc(len);
(void) snprintf(new_kexalgs, len, "%s,%s", gss_kexalgs, old_kexalgs);
+ xfree(gss_kexalgs);
return (new_kexalgs);
}
@@ -286,7 +286,7 @@ ssh_gssapi_modify_kex(Kex *kex, gss_OID_set mechs, char **proposal)
int i;
if (kex == NULL || proposal == NULL ||
- (orig_kexalgs = proposal[PROPOSAL_KEX_ALGS]) == NULL) {
+ proposal[PROPOSAL_KEX_ALGS] == NULL) {
fatal("INTERNAL ERROR (%s)", __func__);
}
@@ -340,7 +340,7 @@ mod_offer:
(void) gss_release_oid_set(&min, &kex->mechs); /* ok if !kex->mechs */
- /* Not offering GSS kexalgs now -> all done */
+ /* Not offering GSS kex algorithms now -> all done */
if (mechs == GSS_C_NULL_OID_SET)
return;
@@ -358,9 +358,10 @@ mod_offer:
}
}
- /* Add mechs to kexalgs ... */
+ /* Add mechs to kex algorithms ... */
proposal[PROPOSAL_KEX_ALGS] = ssh_gssapi_make_kexalgs_list(mechs,
kexalgs);
+ xfree(kexalgs);
kex->mechs = dup_mechs; /* remember what we offer now */
/*