version 1.234, 2016/07/18 11:35:33 |
version 1.235, 2016/08/03 05:41:57 |
|
|
u_int remote_protocol_flags; |
u_int remote_protocol_flags; |
|
|
/* Encryption context for receiving data. Only used for decryption. */ |
/* Encryption context for receiving data. Only used for decryption. */ |
struct sshcipher_ctx receive_context; |
struct sshcipher_ctx *receive_context; |
|
|
/* Encryption context for sending data. Only used for encryption. */ |
/* Encryption context for sending data. Only used for encryption. */ |
struct sshcipher_ctx send_context; |
struct sshcipher_ctx *send_context; |
|
|
/* Buffer for raw input data from the socket. */ |
/* Buffer for raw input data from the socket. */ |
struct sshbuf *input; |
struct sshbuf *input; |
|
|
ssh_packet_close(struct ssh *ssh) |
ssh_packet_close(struct ssh *ssh) |
{ |
{ |
struct session_state *state = ssh->state; |
struct session_state *state = ssh->state; |
int r; |
|
u_int mode; |
u_int mode; |
|
|
if (!state->initialized) |
if (!state->initialized) |
|
|
inflateEnd(stream); |
inflateEnd(stream); |
} |
} |
} |
} |
if ((r = cipher_cleanup(&state->send_context)) != 0) |
cipher_free(state->send_context); |
error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); |
cipher_free(state->receive_context); |
if ((r = cipher_cleanup(&state->receive_context)) != 0) |
state->send_context = state->receive_context = NULL; |
error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); |
|
free(ssh->remote_ipaddr); |
free(ssh->remote_ipaddr); |
ssh->remote_ipaddr = NULL; |
ssh->remote_ipaddr = NULL; |
free(ssh->state); |
free(ssh->state); |
|
|
NULL, 0, CIPHER_DECRYPT) != 0)) |
NULL, 0, CIPHER_DECRYPT) != 0)) |
fatal("%s: cipher_init failed: %s", __func__, ssh_err(r)); |
fatal("%s: cipher_init failed: %s", __func__, ssh_err(r)); |
if (!state->cipher_warning_done && |
if (!state->cipher_warning_done && |
((wmsg = cipher_warning_message(&state->send_context)) != NULL || |
((wmsg = cipher_warning_message(state->send_context)) != NULL || |
(wmsg = cipher_warning_message(&state->send_context)) != NULL)) { |
(wmsg = cipher_warning_message(state->send_context)) != NULL)) { |
error("Warning: %s", wmsg); |
error("Warning: %s", wmsg); |
state->cipher_warning_done = 1; |
state->cipher_warning_done = 1; |
} |
} |
|
|
|
|
/* Insert padding. Initialized to zero in packet_start1() */ |
/* Insert padding. Initialized to zero in packet_start1() */ |
padding = 8 - len % 8; |
padding = 8 - len % 8; |
if (!state->send_context.plaintext) { |
if (!cipher_ctx_is_plaintext(state->send_context)) { |
cp = sshbuf_mutable_ptr(state->outgoing_packet); |
cp = sshbuf_mutable_ptr(state->outgoing_packet); |
if (cp == NULL) { |
if (cp == NULL) { |
r = SSH_ERR_INTERNAL_ERROR; |
r = SSH_ERR_INTERNAL_ERROR; |
|
|
if ((r = sshbuf_reserve(state->output, |
if ((r = sshbuf_reserve(state->output, |
sshbuf_len(state->outgoing_packet), &cp)) != 0) |
sshbuf_len(state->outgoing_packet), &cp)) != 0) |
goto out; |
goto out; |
if ((r = cipher_crypt(&state->send_context, 0, cp, |
if ((r = cipher_crypt(state->send_context, 0, cp, |
sshbuf_ptr(state->outgoing_packet), |
sshbuf_ptr(state->outgoing_packet), |
sshbuf_len(state->outgoing_packet), 0, 0)) != 0) |
sshbuf_len(state->outgoing_packet), 0, 0)) != 0) |
goto out; |
goto out; |
|
|
struct sshenc *enc; |
struct sshenc *enc; |
struct sshmac *mac; |
struct sshmac *mac; |
struct sshcomp *comp; |
struct sshcomp *comp; |
struct sshcipher_ctx *cc; |
struct sshcipher_ctx **ccp; |
u_int64_t *max_blocks; |
u_int64_t *max_blocks; |
const char *wmsg; |
const char *wmsg; |
int r, crypt_type; |
int r, crypt_type; |
|
|
debug2("set_newkeys: mode %d", mode); |
debug2("set_newkeys: mode %d", mode); |
|
|
if (mode == MODE_OUT) { |
if (mode == MODE_OUT) { |
cc = &state->send_context; |
ccp = &state->send_context; |
crypt_type = CIPHER_ENCRYPT; |
crypt_type = CIPHER_ENCRYPT; |
state->p_send.packets = state->p_send.blocks = 0; |
state->p_send.packets = state->p_send.blocks = 0; |
max_blocks = &state->max_blocks_out; |
max_blocks = &state->max_blocks_out; |
} else { |
} else { |
cc = &state->receive_context; |
ccp = &state->receive_context; |
crypt_type = CIPHER_DECRYPT; |
crypt_type = CIPHER_DECRYPT; |
state->p_read.packets = state->p_read.blocks = 0; |
state->p_read.packets = state->p_read.blocks = 0; |
max_blocks = &state->max_blocks_in; |
max_blocks = &state->max_blocks_in; |
|
|
(unsigned long long)state->p_read.blocks, |
(unsigned long long)state->p_read.blocks, |
(unsigned long long)state->p_send.bytes, |
(unsigned long long)state->p_send.bytes, |
(unsigned long long)state->p_send.blocks); |
(unsigned long long)state->p_send.blocks); |
if ((r = cipher_cleanup(cc)) != 0) |
cipher_free(*ccp); |
return r; |
*ccp = NULL; |
enc = &state->newkeys[mode]->enc; |
enc = &state->newkeys[mode]->enc; |
mac = &state->newkeys[mode]->mac; |
mac = &state->newkeys[mode]->mac; |
comp = &state->newkeys[mode]->comp; |
comp = &state->newkeys[mode]->comp; |
|
|
} |
} |
mac->enabled = 1; |
mac->enabled = 1; |
DBG(debug("cipher_init_context: %d", mode)); |
DBG(debug("cipher_init_context: %d", mode)); |
if ((r = cipher_init(cc, enc->cipher, enc->key, enc->key_len, |
if ((r = cipher_init(ccp, enc->cipher, enc->key, enc->key_len, |
enc->iv, enc->iv_len, crypt_type)) != 0) |
enc->iv, enc->iv_len, crypt_type)) != 0) |
return r; |
return r; |
if (!state->cipher_warning_done && |
if (!state->cipher_warning_done && |
(wmsg = cipher_warning_message(cc)) != NULL) { |
(wmsg = cipher_warning_message(*ccp)) != NULL) { |
error("Warning: %s", wmsg); |
error("Warning: %s", wmsg); |
state->cipher_warning_done = 1; |
state->cipher_warning_done = 1; |
} |
} |
|
|
} |
} |
if ((r = sshbuf_reserve(state->outgoing_packet, padlen, &cp)) != 0) |
if ((r = sshbuf_reserve(state->outgoing_packet, padlen, &cp)) != 0) |
goto out; |
goto out; |
if (enc && !state->send_context.plaintext) { |
if (enc && !cipher_ctx_is_plaintext(state->send_context)) { |
/* random padding */ |
/* random padding */ |
arc4random_buf(cp, padlen); |
arc4random_buf(cp, padlen); |
} else { |
} else { |
|
|
if ((r = sshbuf_reserve(state->output, |
if ((r = sshbuf_reserve(state->output, |
sshbuf_len(state->outgoing_packet) + authlen, &cp)) != 0) |
sshbuf_len(state->outgoing_packet) + authlen, &cp)) != 0) |
goto out; |
goto out; |
if ((r = cipher_crypt(&state->send_context, state->p_send.seqnr, cp, |
if ((r = cipher_crypt(state->send_context, state->p_send.seqnr, cp, |
sshbuf_ptr(state->outgoing_packet), |
sshbuf_ptr(state->outgoing_packet), |
len - aadlen, aadlen, authlen)) != 0) |
len - aadlen, aadlen, authlen)) != 0) |
goto out; |
goto out; |
|
|
* (C)1998 CORE-SDI, Buenos Aires Argentina |
* (C)1998 CORE-SDI, Buenos Aires Argentina |
* Ariel Futoransky(futo@core-sdi.com) |
* Ariel Futoransky(futo@core-sdi.com) |
*/ |
*/ |
if (!state->receive_context.plaintext) { |
if (!cipher_ctx_is_plaintext(state->receive_context)) { |
emsg = NULL; |
emsg = NULL; |
switch (detect_attack(&state->deattack, |
switch (detect_attack(&state->deattack, |
sshbuf_ptr(state->input), padded_len)) { |
sshbuf_ptr(state->input), padded_len)) { |
|
|
sshbuf_reset(state->incoming_packet); |
sshbuf_reset(state->incoming_packet); |
if ((r = sshbuf_reserve(state->incoming_packet, padded_len, &p)) != 0) |
if ((r = sshbuf_reserve(state->incoming_packet, padded_len, &p)) != 0) |
goto out; |
goto out; |
if ((r = cipher_crypt(&state->receive_context, 0, p, |
if ((r = cipher_crypt(state->receive_context, 0, p, |
sshbuf_ptr(state->input), padded_len, 0, 0)) != 0) |
sshbuf_ptr(state->input), padded_len, 0, 0)) != 0) |
goto out; |
goto out; |
|
|
|
|
aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; |
aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; |
|
|
if (aadlen && state->packlen == 0) { |
if (aadlen && state->packlen == 0) { |
if (cipher_get_length(&state->receive_context, |
if (cipher_get_length(state->receive_context, |
&state->packlen, state->p_read.seqnr, |
&state->packlen, state->p_read.seqnr, |
sshbuf_ptr(state->input), sshbuf_len(state->input)) != 0) |
sshbuf_ptr(state->input), sshbuf_len(state->input)) != 0) |
return 0; |
return 0; |
|
|
if ((r = sshbuf_reserve(state->incoming_packet, block_size, |
if ((r = sshbuf_reserve(state->incoming_packet, block_size, |
&cp)) != 0) |
&cp)) != 0) |
goto out; |
goto out; |
if ((r = cipher_crypt(&state->receive_context, |
if ((r = cipher_crypt(state->receive_context, |
state->p_send.seqnr, cp, sshbuf_ptr(state->input), |
state->p_send.seqnr, cp, sshbuf_ptr(state->input), |
block_size, 0, 0)) != 0) |
block_size, 0, 0)) != 0) |
goto out; |
goto out; |
|
|
if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need, |
if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need, |
&cp)) != 0) |
&cp)) != 0) |
goto out; |
goto out; |
if ((r = cipher_crypt(&state->receive_context, state->p_read.seqnr, cp, |
if ((r = cipher_crypt(state->receive_context, state->p_read.seqnr, cp, |
sshbuf_ptr(state->input), need, aadlen, authlen)) != 0) |
sshbuf_ptr(state->input), need, aadlen, authlen)) != 0) |
goto out; |
goto out; |
if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0) |
if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0) |
|
|
enc = &newkey->enc; |
enc = &newkey->enc; |
mac = &newkey->mac; |
mac = &newkey->mac; |
comp = &newkey->comp; |
comp = &newkey->comp; |
cc = (mode == MODE_OUT) ? &ssh->state->send_context : |
cc = (mode == MODE_OUT) ? ssh->state->send_context : |
&ssh->state->receive_context; |
ssh->state->receive_context; |
if ((r = cipher_get_keyiv(cc, enc->iv, enc->iv_len)) != 0) |
if ((r = cipher_get_keyiv(cc, enc->iv, enc->iv_len)) != 0) |
return r; |
return r; |
if ((b = sshbuf_new()) == NULL) |
if ((b = sshbuf_new()) == NULL) |
|
|
int r, ssh1cipher; |
int r, ssh1cipher; |
|
|
if (!compat20) { |
if (!compat20) { |
ssh1cipher = cipher_get_number(state->receive_context.cipher); |
ssh1cipher = cipher_ctx_get_number(state->receive_context); |
slen = cipher_get_keyiv_len(&state->send_context); |
slen = cipher_get_keyiv_len(state->send_context); |
rlen = cipher_get_keyiv_len(&state->receive_context); |
rlen = cipher_get_keyiv_len(state->receive_context); |
if ((r = sshbuf_put_u32(m, state->remote_protocol_flags)) != 0 || |
if ((r = sshbuf_put_u32(m, state->remote_protocol_flags)) != 0 || |
(r = sshbuf_put_u32(m, ssh1cipher)) != 0 || |
(r = sshbuf_put_u32(m, ssh1cipher)) != 0 || |
(r = sshbuf_put_string(m, state->ssh1_key, state->ssh1_keylen)) != 0 || |
(r = sshbuf_put_string(m, state->ssh1_key, state->ssh1_keylen)) != 0 || |
(r = sshbuf_put_u32(m, slen)) != 0 || |
(r = sshbuf_put_u32(m, slen)) != 0 || |
(r = sshbuf_reserve(m, slen, &p)) != 0 || |
(r = sshbuf_reserve(m, slen, &p)) != 0 || |
(r = cipher_get_keyiv(&state->send_context, p, slen)) != 0 || |
(r = cipher_get_keyiv(state->send_context, p, slen)) != 0 || |
(r = sshbuf_put_u32(m, rlen)) != 0 || |
(r = sshbuf_put_u32(m, rlen)) != 0 || |
(r = sshbuf_reserve(m, rlen, &p)) != 0 || |
(r = sshbuf_reserve(m, rlen, &p)) != 0 || |
(r = cipher_get_keyiv(&state->receive_context, p, rlen)) != 0) |
(r = cipher_get_keyiv(state->receive_context, p, rlen)) != 0) |
return r; |
return r; |
} else { |
} else { |
if ((r = kex_to_blob(m, ssh->kex)) != 0 || |
if ((r = kex_to_blob(m, ssh->kex)) != 0 || |
|
|
return r; |
return r; |
} |
} |
|
|
slen = cipher_get_keycontext(&state->send_context, NULL); |
slen = cipher_get_keycontext(state->send_context, NULL); |
rlen = cipher_get_keycontext(&state->receive_context, NULL); |
rlen = cipher_get_keycontext(state->receive_context, NULL); |
if ((r = sshbuf_put_u32(m, slen)) != 0 || |
if ((r = sshbuf_put_u32(m, slen)) != 0 || |
(r = sshbuf_reserve(m, slen, &p)) != 0) |
(r = sshbuf_reserve(m, slen, &p)) != 0) |
return r; |
return r; |
if (cipher_get_keycontext(&state->send_context, p) != (int)slen) |
if (cipher_get_keycontext(state->send_context, p) != (int)slen) |
return SSH_ERR_INTERNAL_ERROR; |
return SSH_ERR_INTERNAL_ERROR; |
if ((r = sshbuf_put_u32(m, rlen)) != 0 || |
if ((r = sshbuf_put_u32(m, rlen)) != 0 || |
(r = sshbuf_reserve(m, rlen, &p)) != 0) |
(r = sshbuf_reserve(m, rlen, &p)) != 0) |
return r; |
return r; |
if (cipher_get_keycontext(&state->receive_context, p) != (int)rlen) |
if (cipher_get_keycontext(state->receive_context, p) != (int)rlen) |
return SSH_ERR_INTERNAL_ERROR; |
return SSH_ERR_INTERNAL_ERROR; |
|
|
if ((r = ssh_packet_get_compress_state(m, ssh)) != 0 || |
if ((r = ssh_packet_get_compress_state(m, ssh)) != 0 || |
|
|
return SSH_ERR_KEY_UNKNOWN_CIPHER; |
return SSH_ERR_KEY_UNKNOWN_CIPHER; |
ssh_packet_set_encryption_key(ssh, ssh1key, ssh1keylen, |
ssh_packet_set_encryption_key(ssh, ssh1key, ssh1keylen, |
(int)ssh1cipher); |
(int)ssh1cipher); |
if (cipher_get_keyiv_len(&state->send_context) != (int)slen || |
if (cipher_get_keyiv_len(state->send_context) != (int)slen || |
cipher_get_keyiv_len(&state->receive_context) != (int)rlen) |
cipher_get_keyiv_len(state->receive_context) != (int)rlen) |
return SSH_ERR_INVALID_FORMAT; |
return SSH_ERR_INVALID_FORMAT; |
if ((r = cipher_set_keyiv(&state->send_context, ivout)) != 0 || |
if ((r = cipher_set_keyiv(state->send_context, ivout)) != 0 || |
(r = cipher_set_keyiv(&state->receive_context, ivin)) != 0) |
(r = cipher_set_keyiv(state->receive_context, ivin)) != 0) |
return r; |
return r; |
} else { |
} else { |
if ((r = kex_from_blob(m, &ssh->kex)) != 0 || |
if ((r = kex_from_blob(m, &ssh->kex)) != 0 || |
|
|
if ((r = sshbuf_get_string_direct(m, &keyout, &slen)) != 0 || |
if ((r = sshbuf_get_string_direct(m, &keyout, &slen)) != 0 || |
(r = sshbuf_get_string_direct(m, &keyin, &rlen)) != 0) |
(r = sshbuf_get_string_direct(m, &keyin, &rlen)) != 0) |
return r; |
return r; |
if (cipher_get_keycontext(&state->send_context, NULL) != (int)slen || |
if (cipher_get_keycontext(state->send_context, NULL) != (int)slen || |
cipher_get_keycontext(&state->receive_context, NULL) != (int)rlen) |
cipher_get_keycontext(state->receive_context, NULL) != (int)rlen) |
return SSH_ERR_INVALID_FORMAT; |
return SSH_ERR_INVALID_FORMAT; |
cipher_set_keycontext(&state->send_context, keyout); |
cipher_set_keycontext(state->send_context, keyout); |
cipher_set_keycontext(&state->receive_context, keyin); |
cipher_set_keycontext(state->receive_context, keyin); |
|
|
if ((r = ssh_packet_set_compress_state(ssh, m)) != 0 || |
if ((r = ssh_packet_set_compress_state(ssh, m)) != 0 || |
(r = ssh_packet_set_postauth(ssh)) != 0) |
(r = ssh_packet_set_postauth(ssh)) != 0) |