version 1.38.2.3, 2001/03/21 19:46:26 |
version 1.38.2.4, 2001/05/07 21:09:31 |
|
|
|
|
/* Scratch buffer for packet compression/decompression. */ |
/* Scratch buffer for packet compression/decompression. */ |
static Buffer compression_buffer; |
static Buffer compression_buffer; |
|
static int compression_buffer_ready = 0; |
|
|
/* Flag indicating whether packet compression/decompression is enabled. */ |
/* Flag indicating whether packet compression/decompression is enabled. */ |
static int packet_compression = 0; |
static int packet_compression = 0; |
|
|
int use_ssh2_packet_format = 0; |
int use_ssh2_packet_format = 0; |
|
|
/* Session key information for Encryption and MAC */ |
/* Session key information for Encryption and MAC */ |
Kex *kex = NULL; |
Newkeys *newkeys[MODE_MAX]; |
|
|
void |
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) |
packet_set_ssh2_format(void) |
{ |
{ |
DBG(debug("use_ssh2_packet_format")); |
DBG(debug("use_ssh2_packet_format")); |
use_ssh2_packet_format = 1; |
use_ssh2_packet_format = 1; |
|
newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; |
} |
} |
|
|
/* |
/* |
|
|
buffer_free(&output); |
buffer_free(&output); |
buffer_free(&outgoing_packet); |
buffer_free(&outgoing_packet); |
buffer_free(&incoming_packet); |
buffer_free(&incoming_packet); |
if (packet_compression) { |
if (compression_buffer_ready) { |
buffer_free(&compression_buffer); |
buffer_free(&compression_buffer); |
buffer_compress_uninit(); |
buffer_compress_uninit(); |
} |
} |
|
|
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. |
* Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. |
*/ |
*/ |
|
|
/*** XXXXX todo: kex means re-init */ |
|
void |
void |
|
packet_init_compression() |
|
{ |
|
if (compression_buffer_ready == 1) |
|
return; |
|
compression_buffer_ready = 1; |
|
buffer_init(&compression_buffer); |
|
} |
|
|
|
void |
packet_start_compression(int level) |
packet_start_compression(int level) |
{ |
{ |
if (packet_compression) |
if (packet_compression && !use_ssh2_packet_format) |
fatal("Compression already enabled."); |
fatal("Compression already enabled."); |
packet_compression = 1; |
packet_compression = 1; |
buffer_init(&compression_buffer); |
packet_init_compression(); |
buffer_compress_init(level); |
buffer_compress_init_send(level); |
|
buffer_compress_init_recv(); |
} |
} |
|
|
/* |
/* |
|
|
*/ |
*/ |
} |
} |
|
|
|
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) |
* Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) |
*/ |
*/ |
|
|
Comp *comp = NULL; |
Comp *comp = NULL; |
int block_size; |
int block_size; |
|
|
if (kex != NULL) { |
if (newkeys[MODE_OUT] != NULL) { |
enc = &kex->enc[MODE_OUT]; |
enc = &newkeys[MODE_OUT]->enc; |
mac = &kex->mac[MODE_OUT]; |
mac = &newkeys[MODE_OUT]->mac; |
comp = &kex->comp[MODE_OUT]; |
comp = &newkeys[MODE_OUT]->comp; |
} |
} |
block_size = enc ? enc->cipher->block_size : 8; |
block_size = enc ? enc->cipher->block_size : 8; |
|
|
|
|
log("outgoing seqnr wraps around"); |
log("outgoing seqnr wraps around"); |
buffer_clear(&outgoing_packet); |
buffer_clear(&outgoing_packet); |
|
|
if (type == SSH2_MSG_NEWKEYS) { |
if (type == SSH2_MSG_NEWKEYS) |
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) |
set_newkeys(MODE_OUT); |
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); |
|
} |
|
} |
|
} |
} |
|
|
void |
void |
|
|
Mac *mac = NULL; |
Mac *mac = NULL; |
Comp *comp = NULL; |
Comp *comp = NULL; |
|
|
if (kex != NULL) { |
if (newkeys[MODE_IN] != NULL) { |
enc = &kex->enc[MODE_IN]; |
enc = &newkeys[MODE_IN]->enc; |
mac = &kex->mac[MODE_IN]; |
mac = &newkeys[MODE_IN]->mac; |
comp = &kex->comp[MODE_IN]; |
comp = &newkeys[MODE_IN]->comp; |
} |
} |
maclen = mac && mac->enabled ? mac->mac_len : 0; |
maclen = mac && mac->enabled ? mac->mac_len : 0; |
block_size = enc ? enc->cipher->block_size : 8; |
block_size = enc ? enc->cipher->block_size : 8; |
|
|
/* extract packet type */ |
/* extract packet type */ |
type = (u_char)buf[0]; |
type = (u_char)buf[0]; |
|
|
if (type == SSH2_MSG_NEWKEYS) { |
if (type == SSH2_MSG_NEWKEYS) |
if (kex==NULL || mac==NULL || enc==NULL || comp==NULL) |
set_newkeys(MODE_IN); |
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); |
|
} |
|
} |
|
|
|
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "read/plain[%d]:\r\n", type); |
fprintf(stderr, "read/plain[%d]:\r\n", type); |
|
|
|
|
/* |
/* |
* 9.2. Ignored Data Message |
* 9.2. Ignored Data Message |
* |
* |
* byte SSH_MSG_IGNORE |
* byte SSH_MSG_IGNORE |
* string data |
* string data |
* |
* |
* All implementations MUST understand (and ignore) this message at any |
* All implementations MUST understand (and ignore) this message at any |
* time (after receiving the protocol version). No implementation is |
* time (after receiving the protocol version). No implementation is |
* required to send them. This message can be used as an additional |
* required to send them. This message can be used as an additional |
|
|
|
|
have = buffer_len(&outgoing_packet); |
have = buffer_len(&outgoing_packet); |
debug2("packet_inject_ignore: current %d", have); |
debug2("packet_inject_ignore: current %d", have); |
if (kex != NULL) |
if (newkeys[MODE_OUT] != NULL) |
enc = &kex->enc[MODE_OUT]; |
enc = &newkeys[MODE_OUT]->enc; |
blocksize = enc ? enc->cipher->block_size : 8; |
blocksize = enc ? enc->cipher->block_size : 8; |
padlen = blocksize - (have % blocksize); |
padlen = blocksize - (have % blocksize); |
if (padlen < 4) |
if (padlen < 4) |