diff options
Diffstat (limited to 'usr/src/cmd/ssh/libssh')
-rw-r--r-- | usr/src/cmd/ssh/libssh/Makefile.com | 5 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/buffer.c | 24 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/cipher-ctr.c | 76 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/cipher.c | 13 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/dh.c | 4 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/engine.c | 112 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/kex.c | 22 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/packet.c | 279 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/readconf.c | 14 | ||||
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/ssh-gss.c | 11 |
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 */ /* |