=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/packet.c,v retrieving revision 1.38.2.3 retrieving revision 1.38.2.4 diff -u -r1.38.2.3 -r1.38.2.4 --- src/usr.bin/ssh/packet.c 2001/03/21 19:46:26 1.38.2.3 +++ src/usr.bin/ssh/packet.c 2001/05/07 21:09:31 1.38.2.4 @@ -37,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: packet.c,v 1.38.2.3 2001/03/21 19:46:26 jason Exp $"); +RCSID("$OpenBSD: packet.c,v 1.38.2.4 2001/05/07 21:09:31 jason Exp $"); #include "xmalloc.h" #include "buffer.h" @@ -104,6 +104,7 @@ /* Scratch buffer for packet compression/decompression. */ static Buffer compression_buffer; +static int compression_buffer_ready = 0; /* Flag indicating whether packet compression/decompression is enabled. */ static int packet_compression = 0; @@ -121,35 +122,14 @@ int use_ssh2_packet_format = 0; /* Session key information for Encryption and MAC */ -Kex *kex = NULL; +Newkeys *newkeys[MODE_MAX]; void -packet_set_kex(Kex *k) -{ - if( k->mac[MODE_IN ].key == NULL || - k->enc[MODE_IN ].key == NULL || - k->enc[MODE_IN ].iv == NULL || - k->mac[MODE_OUT].key == NULL || - k->enc[MODE_OUT].key == NULL || - k->enc[MODE_OUT].iv == NULL) - fatal("bad KEX"); - kex = k; -} -void -clear_enc_keys(Enc *enc, int len) -{ - memset(enc->iv, 0, len); - memset(enc->key, 0, len); - xfree(enc->iv); - xfree(enc->key); - enc->iv = NULL; - enc->key = NULL; -} -void packet_set_ssh2_format(void) { DBG(debug("use_ssh2_packet_format")); use_ssh2_packet_format = 1; + newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; } /* @@ -270,7 +250,7 @@ buffer_free(&output); buffer_free(&outgoing_packet); buffer_free(&incoming_packet); - if (packet_compression) { + if (compression_buffer_ready) { buffer_free(&compression_buffer); buffer_compress_uninit(); } @@ -298,15 +278,24 @@ * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ -/*** XXXXX todo: kex means re-init */ void +packet_init_compression() +{ + if (compression_buffer_ready == 1) + return; + compression_buffer_ready = 1; + buffer_init(&compression_buffer); +} + +void packet_start_compression(int level) { - if (packet_compression) + if (packet_compression && !use_ssh2_packet_format) fatal("Compression already enabled."); packet_compression = 1; - buffer_init(&compression_buffer); - buffer_compress_init(level); + packet_init_compression(); + buffer_compress_init_send(level); + buffer_compress_init_recv(); } /* @@ -522,6 +511,56 @@ */ } +void +set_newkeys(int mode) +{ + Enc *enc; + Mac *mac; + Comp *comp; + CipherContext *cc; + + debug("newkeys: mode %d", mode); + + cc = (mode == MODE_OUT) ? &send_context : &receive_context; + if (newkeys[mode] != NULL) { + debug("newkeys: rekeying"); + /* todo: free old keys, reset compression/cipher-ctxt; */ + memset(cc, 0, sizeof(*cc)); + enc = &newkeys[mode]->enc; + mac = &newkeys[mode]->mac; + comp = &newkeys[mode]->comp; + memset(mac->key, 0, mac->key_len); + xfree(enc->name); + xfree(enc->iv); + xfree(enc->key); + xfree(mac->name); + xfree(mac->key); + xfree(comp->name); + xfree(newkeys[mode]); + } + newkeys[mode] = kex_get_newkeys(mode); + if (newkeys[mode] == NULL) + fatal("newkeys: no keys for mode %d", mode); + enc = &newkeys[mode]->enc; + mac = &newkeys[mode]->mac; + comp = &newkeys[mode]->comp; + if (mac->md != NULL) + mac->enabled = 1; + DBG(debug("cipher_init_context: %d", mode)); + cipher_init(cc, enc->cipher, enc->key, enc->cipher->key_len, + enc->iv, enc->cipher->block_size); + memset(enc->iv, 0, enc->cipher->block_size); + memset(enc->key, 0, enc->cipher->key_len); + if (comp->type != 0 && comp->enabled == 0) { + packet_init_compression(); + if (mode == MODE_OUT) + buffer_compress_init_send(6); + else + buffer_compress_init_recv(); + comp->enabled = 1; + } +} + /* * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) */ @@ -540,10 +579,10 @@ Comp *comp = NULL; int block_size; - if (kex != NULL) { - enc = &kex->enc[MODE_OUT]; - mac = &kex->mac[MODE_OUT]; - comp = &kex->comp[MODE_OUT]; + if (newkeys[MODE_OUT] != NULL) { + enc = &newkeys[MODE_OUT]->enc; + mac = &newkeys[MODE_OUT]->mac; + comp = &newkeys[MODE_OUT]->comp; } block_size = enc ? enc->cipher->block_size : 8; @@ -622,22 +661,8 @@ log("outgoing seqnr wraps around"); buffer_clear(&outgoing_packet); - if (type == SSH2_MSG_NEWKEYS) { - if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) - fatal("packet_send2: no KEX"); - if (mac->md != NULL) - mac->enabled = 1; - DBG(debug("cipher_init send_context")); - cipher_init(&send_context, enc->cipher, - enc->key, enc->cipher->key_len, - enc->iv, enc->cipher->block_size); - clear_enc_keys(enc, kex->we_need); - if (comp->type != 0 && comp->enabled == 0) { - comp->enabled = 1; - if (! packet_compression) - packet_start_compression(6); - } - } + if (type == SSH2_MSG_NEWKEYS) + set_newkeys(MODE_OUT); } void @@ -833,10 +858,10 @@ Mac *mac = NULL; Comp *comp = NULL; - if (kex != NULL) { - enc = &kex->enc[MODE_IN]; - mac = &kex->mac[MODE_IN]; - comp = &kex->comp[MODE_IN]; + if (newkeys[MODE_IN] != NULL) { + enc = &newkeys[MODE_IN]->enc; + mac = &newkeys[MODE_IN]->mac; + comp = &newkeys[MODE_IN]->comp; } maclen = mac && mac->enabled ? mac->mac_len : 0; block_size = enc ? enc->cipher->block_size : 8; @@ -930,22 +955,8 @@ /* extract packet type */ type = (u_char)buf[0]; - if (type == SSH2_MSG_NEWKEYS) { - if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) - fatal("packet_read_poll2: no KEX"); - if (mac->md != NULL) - mac->enabled = 1; - DBG(debug("cipher_init receive_context")); - cipher_init(&receive_context, enc->cipher, - enc->key, enc->cipher->key_len, - enc->iv, enc->cipher->block_size); - clear_enc_keys(enc, kex->we_need); - if (comp->type != 0 && comp->enabled == 0) { - comp->enabled = 1; - if (! packet_compression) - packet_start_compression(6); - } - } + if (type == SSH2_MSG_NEWKEYS) + set_newkeys(MODE_IN); #ifdef PACKET_DEBUG fprintf(stderr, "read/plain[%d]:\r\n", type); @@ -1312,10 +1323,10 @@ /* * 9.2. Ignored Data Message - * + * * byte SSH_MSG_IGNORE * string data - * + * * All implementations MUST understand (and ignore) this message at any * time (after receiving the protocol version). No implementation is * required to send them. This message can be used as an additional @@ -1333,8 +1344,8 @@ have = buffer_len(&outgoing_packet); debug2("packet_inject_ignore: current %d", have); - if (kex != NULL) - enc = &kex->enc[MODE_OUT]; + if (newkeys[MODE_OUT] != NULL) + enc = &newkeys[MODE_OUT]->enc; blocksize = enc ? enc->cipher->block_size : 8; padlen = blocksize - (have % blocksize); if (padlen < 4)