version 1.36, 2019/01/27 02:08:33 |
version 1.37, 2019/04/20 17:16:40 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
/* $OpenBSD: packet.c,v 1.277 2018/07/16 03:09:13 djm Exp $ */ |
/* $OpenBSD: packet.c,v 1.283 2019/03/01 03:29:32 djm Exp $ */ |
|
|
/* |
/* |
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
Line 58 __RCSID("$NetBSD$"); |
|
Line 57 __RCSID("$NetBSD$"); |
|
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <limits.h> |
#include <limits.h> |
|
#include <poll.h> |
#include <signal.h> |
#include <signal.h> |
#include <time.h> |
#include <time.h> |
|
|
Line 216 ssh_alloc_session_state(void) |
|
Line 216 ssh_alloc_session_state(void) |
|
|
|
if ((ssh = calloc(1, sizeof(*ssh))) == NULL || |
if ((ssh = calloc(1, sizeof(*ssh))) == NULL || |
(state = calloc(1, sizeof(*state))) == NULL || |
(state = calloc(1, sizeof(*state))) == NULL || |
|
(ssh->kex = kex_new()) == NULL || |
(state->input = sshbuf_new()) == NULL || |
(state->input = sshbuf_new()) == NULL || |
(state->output = sshbuf_new()) == NULL || |
(state->output = sshbuf_new()) == NULL || |
(state->outgoing_packet = sshbuf_new()) == NULL || |
(state->outgoing_packet = sshbuf_new()) == NULL || |
Line 238 ssh_alloc_session_state(void) |
|
Line 239 ssh_alloc_session_state(void) |
|
ssh->state = state; |
ssh->state = state; |
return ssh; |
return ssh; |
fail: |
fail: |
|
if (ssh) { |
|
kex_free(ssh->kex); |
|
free(ssh); |
|
} |
if (state) { |
if (state) { |
sshbuf_free(state->input); |
sshbuf_free(state->input); |
sshbuf_free(state->output); |
sshbuf_free(state->output); |
Line 245 ssh_alloc_session_state(void) |
|
Line 250 ssh_alloc_session_state(void) |
|
sshbuf_free(state->outgoing_packet); |
sshbuf_free(state->outgoing_packet); |
free(state); |
free(state); |
} |
} |
free(ssh); |
|
return NULL; |
return NULL; |
} |
} |
|
|
Line 260 ssh_packet_set_input_hook(struct ssh *ss |
|
Line 264 ssh_packet_set_input_hook(struct ssh *ss |
|
int |
int |
ssh_packet_is_rekeying(struct ssh *ssh) |
ssh_packet_is_rekeying(struct ssh *ssh) |
{ |
{ |
return ssh->state->rekeying || |
return ssh->state->rekeying || ssh->kex->done == 0; |
(ssh->kex != NULL && ssh->kex->done == 0); |
|
} |
} |
|
|
/* |
/* |
Line 458 ssh_packet_connection_af(struct ssh *ssh |
|
Line 461 ssh_packet_connection_af(struct ssh *ssh |
|
if (getsockname(ssh->state->connection_out, (struct sockaddr *)&to, |
if (getsockname(ssh->state->connection_out, (struct sockaddr *)&to, |
&tolen) < 0) |
&tolen) < 0) |
return 0; |
return 0; |
|
#ifdef IPV4_IN_IPV6 |
|
if (to.ss_family == AF_INET6 && |
|
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr)) |
|
return AF_INET; |
|
#endif |
return to.ss_family; |
return to.ss_family; |
} |
} |
|
|
Line 587 ssh_packet_close_internal(struct ssh *ss |
|
Line 595 ssh_packet_close_internal(struct ssh *ss |
|
state->newkeys[mode] = NULL; |
state->newkeys[mode] = NULL; |
ssh_clear_newkeys(ssh, mode); /* next keys */ |
ssh_clear_newkeys(ssh, mode); /* next keys */ |
} |
} |
/* comression state is in shared mem, so we can only release it once */ |
/* compression state is in shared mem, so we can only release it once */ |
if (do_close && state->compression_buffer) { |
if (do_close && state->compression_buffer) { |
sshbuf_free(state->compression_buffer); |
sshbuf_free(state->compression_buffer); |
if (state->compression_out_started) { |
if (state->compression_out_started) { |
Line 820 ssh_set_newkeys(struct ssh *ssh, int mod |
|
Line 828 ssh_set_newkeys(struct ssh *ssh, int mod |
|
u_int64_t *max_blocks; |
u_int64_t *max_blocks; |
const char *wmsg; |
const char *wmsg; |
int r, crypt_type; |
int r, crypt_type; |
|
const char *dir = mode == MODE_OUT ? "out" : "in"; |
|
|
debug2("set_newkeys: mode %d", mode); |
debug2("set_newkeys: mode %d", mode); |
|
|
Line 835 ssh_set_newkeys(struct ssh *ssh, int mod |
|
Line 844 ssh_set_newkeys(struct ssh *ssh, int mod |
|
max_blocks = &state->max_blocks_in; |
max_blocks = &state->max_blocks_in; |
} |
} |
if (state->newkeys[mode] != NULL) { |
if (state->newkeys[mode] != NULL) { |
debug("set_newkeys: rekeying, input %llu bytes %llu blocks, " |
debug("%s: rekeying %s, input %llu bytes %llu blocks, " |
"output %llu bytes %llu blocks", |
"output %llu bytes %llu blocks", __func__, dir, |
(unsigned long long)state->p_read.bytes, |
(unsigned long long)state->p_read.bytes, |
(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); |
cipher_free(*ccp); |
|
*ccp = NULL; |
|
kex_free_newkeys(state->newkeys[mode]); |
kex_free_newkeys(state->newkeys[mode]); |
state->newkeys[mode] = NULL; |
state->newkeys[mode] = NULL; |
} |
} |
Line 860 ssh_set_newkeys(struct ssh *ssh, int mod |
|
Line 867 ssh_set_newkeys(struct ssh *ssh, int mod |
|
return r; |
return r; |
} |
} |
mac->enabled = 1; |
mac->enabled = 1; |
DBG(debug("cipher_init_context: %d", mode)); |
DBG(debug("%s: cipher_init_context: %s", __func__, dir)); |
|
cipher_free(*ccp); |
|
*ccp = NULL; |
if ((r = cipher_init(ccp, 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; |
Line 899 ssh_set_newkeys(struct ssh *ssh, int mod |
|
Line 908 ssh_set_newkeys(struct ssh *ssh, int mod |
|
if (state->rekey_limit) |
if (state->rekey_limit) |
*max_blocks = MINIMUM(*max_blocks, |
*max_blocks = MINIMUM(*max_blocks, |
state->rekey_limit / enc->block_size); |
state->rekey_limit / enc->block_size); |
debug("rekey after %llu blocks", (unsigned long long)*max_blocks); |
debug("rekey %s after %llu blocks", dir, |
|
(unsigned long long)*max_blocks); |
return 0; |
return 0; |
} |
} |
|
|
Line 915 ssh_packet_need_rekeying(struct ssh *ssh |
|
Line 925 ssh_packet_need_rekeying(struct ssh *ssh |
|
return 0; |
return 0; |
|
|
/* Haven't keyed yet or KEX in progress. */ |
/* Haven't keyed yet or KEX in progress. */ |
if (ssh->kex == NULL || ssh_packet_is_rekeying(ssh)) |
if (ssh_packet_is_rekeying(ssh)) |
return 0; |
return 0; |
|
|
/* Peer can't rekey */ |
/* Peer can't rekey */ |
Line 942 ssh_packet_need_rekeying(struct ssh *ssh |
|
Line 952 ssh_packet_need_rekeying(struct ssh *ssh |
|
state->p_read.packets > MAX_PACKETS) |
state->p_read.packets > MAX_PACKETS) |
return 1; |
return 1; |
|
|
/* Rekey after (cipher-specific) maxiumum blocks */ |
/* Rekey after (cipher-specific) maximum blocks */ |
out_blocks = ROUNDUP(outbound_packet_len, |
out_blocks = ROUNDUP(outbound_packet_len, |
state->newkeys[MODE_OUT]->enc.block_size); |
state->newkeys[MODE_OUT]->enc.block_size); |
return (state->max_blocks_out && |
return (state->max_blocks_out && |
Line 1112 ssh_packet_send2_wrapped(struct ssh *ssh |
|
Line 1122 ssh_packet_send2_wrapped(struct ssh *ssh |
|
len, padlen, aadlen)); |
len, padlen, aadlen)); |
|
|
/* compute MAC over seqnr and packet(length fields, payload, padding) */ |
/* compute MAC over seqnr and packet(length fields, payload, padding) */ |
debug2("mac %p, %d %d", mac, mac? mac->enabled : -1, mac ? mac->etm : -1); |
|
if (mac && mac->enabled && !mac->etm) { |
if (mac && mac->enabled && !mac->etm) { |
if ((r = mac_compute(mac, state->p_send.seqnr, |
if ((r = mac_compute(mac, state->p_send.seqnr, |
sshbuf_ptr(state->outgoing_packet), len, |
sshbuf_ptr(state->outgoing_packet), len, |
Line 1778 ssh_packet_send_debug(struct ssh *ssh, c |
|
Line 1787 ssh_packet_send_debug(struct ssh *ssh, c |
|
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */ |
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */ |
(r = sshpkt_put_cstring(ssh, buf)) != 0 || |
(r = sshpkt_put_cstring(ssh, buf)) != 0 || |
(r = sshpkt_put_cstring(ssh, "")) != 0 || |
(r = sshpkt_put_cstring(ssh, "")) != 0 || |
(r = sshpkt_send(ssh)) != 0) |
(r = sshpkt_send(ssh)) != 0 || |
|
(r = ssh_packet_write_wait(ssh)) < 0) |
fatal("%s: %s", __func__, ssh_err(r)); |
fatal("%s: %s", __func__, ssh_err(r)); |
if ((r = ssh_packet_write_wait(ssh)) < 0) |
|
sshpkt_fatal(ssh, __func__, r); |
|
} |
} |
|
|
void |
void |
Line 1796 sshpkt_fmt_connection_id(struct ssh *ssh |
|
Line 1804 sshpkt_fmt_connection_id(struct ssh *ssh |
|
/* |
/* |
* Pretty-print connection-terminating errors and exit. |
* Pretty-print connection-terminating errors and exit. |
*/ |
*/ |
void |
static void |
sshpkt_fatal(struct ssh *ssh, const char *tag, int r) |
sshpkt_vfatal(struct ssh *ssh, int r, const char *fmt, va_list ap) |
{ |
{ |
char remote_id[512]; |
char *tag = NULL, remote_id[512]; |
|
|
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); |
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); |
|
|
Line 1833 sshpkt_fatal(struct ssh *ssh, const char |
|
Line 1841 sshpkt_fatal(struct ssh *ssh, const char |
|
} |
} |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
default: |
default: |
|
if (vasprintf(&tag, fmt, ap) == -1) { |
|
ssh_packet_clear_keys(ssh); |
|
logdie("%s: could not allocate failure message", |
|
__func__); |
|
} |
ssh_packet_clear_keys(ssh); |
ssh_packet_clear_keys(ssh); |
logdie("%s%sConnection %s %s: %s", |
logdie("%s%sConnection %s %s: %s", |
tag != NULL ? tag : "", tag != NULL ? ": " : "", |
tag != NULL ? tag : "", tag != NULL ? ": " : "", |
Line 1841 sshpkt_fatal(struct ssh *ssh, const char |
|
Line 1854 sshpkt_fatal(struct ssh *ssh, const char |
|
} |
} |
} |
} |
|
|
|
void |
|
sshpkt_fatal(struct ssh *ssh, int r, const char *fmt, ...) |
|
{ |
|
va_list ap; |
|
|
|
va_start(ap, fmt); |
|
sshpkt_vfatal(ssh, r, fmt, ap); |
|
/* NOTREACHED */ |
|
va_end(ap); |
|
logdie("%s: should have exited", __func__); |
|
} |
|
|
/* |
/* |
* Logs the error plus constructs and sends a disconnect packet, closes the |
* Logs the error plus constructs and sends a disconnect packet, closes the |
* connection, and exits. This function never returns. The error message |
* connection, and exits. This function never returns. The error message |
Line 1876 ssh_packet_disconnect(struct ssh *ssh, c |
|
Line 1901 ssh_packet_disconnect(struct ssh *ssh, c |
|
* for it to get sent. |
* for it to get sent. |
*/ |
*/ |
if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0) |
if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0) |
sshpkt_fatal(ssh, __func__, r); |
sshpkt_fatal(ssh, r, "%s", __func__); |
|
|
if ((r = ssh_packet_write_wait(ssh)) < 0) |
if ((r = ssh_packet_write_wait(ssh)) < 0) |
sshpkt_fatal(ssh, __func__, r); |
sshpkt_fatal(ssh, r, "%s", __func__); |
|
|
/* Close the connection. */ |
/* Close the connection. */ |
ssh_packet_close(ssh); |
ssh_packet_close(ssh); |
|
|
ssh_packet_set_server(struct ssh *ssh) |
ssh_packet_set_server(struct ssh *ssh) |
{ |
{ |
ssh->state->server_side = 1; |
ssh->state->server_side = 1; |
|
ssh->kex->server = 1; /* XXX unify? */ |
} |
} |
|
|
void |
void |
Line 2163 kex_to_blob(struct sshbuf *m, struct kex |
|
Line 2189 kex_to_blob(struct sshbuf *m, struct kex |
|
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 || |
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 || |
(r = sshbuf_put_stringb(m, kex->my)) != 0 || |
(r = sshbuf_put_stringb(m, kex->my)) != 0 || |
(r = sshbuf_put_stringb(m, kex->peer)) != 0 || |
(r = sshbuf_put_stringb(m, kex->peer)) != 0 || |
(r = sshbuf_put_u32(m, kex->flags)) != 0 || |
(r = sshbuf_put_stringb(m, kex->client_version)) != 0 || |
(r = sshbuf_put_cstring(m, kex->client_version_string)) != 0 || |
(r = sshbuf_put_stringb(m, kex->server_version)) != 0 || |
(r = sshbuf_put_cstring(m, kex->server_version_string)) != 0) |
(r = sshbuf_put_u32(m, kex->flags)) != 0) |
return r; |
return r; |
return 0; |
return 0; |
} |
} |
Line 2315 kex_from_blob(struct sshbuf *m, struct k |
|
Line 2341 kex_from_blob(struct sshbuf *m, struct k |
|
struct kex *kex; |
struct kex *kex; |
int r; |
int r; |
|
|
if ((kex = calloc(1, sizeof(struct kex))) == NULL || |
if ((kex = kex_new()) == NULL) |
(kex->my = sshbuf_new()) == NULL || |
return SSH_ERR_ALLOC_FAIL; |
(kex->peer = sshbuf_new()) == NULL) { |
|
r = SSH_ERR_ALLOC_FAIL; |
|
goto out; |
|
} |
|
if ((r = sshbuf_get_string(m, &kex->session_id, &kex->session_id_len)) != 0 || |
if ((r = sshbuf_get_string(m, &kex->session_id, &kex->session_id_len)) != 0 || |
(r = sshbuf_get_u32(m, &kex->we_need)) != 0 || |
(r = sshbuf_get_u32(m, &kex->we_need)) != 0 || |
(r = sshbuf_get_cstring(m, &kex->hostkey_alg, NULL)) != 0 || |
(r = sshbuf_get_cstring(m, &kex->hostkey_alg, NULL)) != 0 || |
Line 2329 kex_from_blob(struct sshbuf *m, struct k |
|
Line 2351 kex_from_blob(struct sshbuf *m, struct k |
|
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 || |
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 || |
(r = sshbuf_get_stringb(m, kex->my)) != 0 || |
(r = sshbuf_get_stringb(m, kex->my)) != 0 || |
(r = sshbuf_get_stringb(m, kex->peer)) != 0 || |
(r = sshbuf_get_stringb(m, kex->peer)) != 0 || |
(r = sshbuf_get_u32(m, &kex->flags)) != 0 || |
(r = sshbuf_get_stringb(m, kex->client_version)) != 0 || |
(r = sshbuf_get_cstring(m, &kex->client_version_string, NULL)) != 0 || |
(r = sshbuf_get_stringb(m, kex->server_version)) != 0 || |
(r = sshbuf_get_cstring(m, &kex->server_version_string, NULL)) != 0) |
(r = sshbuf_get_u32(m, &kex->flags)) != 0) |
goto out; |
goto out; |
kex->server = 1; |
kex->server = 1; |
kex->done = 1; |
kex->done = 1; |
r = 0; |
r = 0; |
out: |
out: |
if (r != 0 || kexp == NULL) { |
if (r != 0 || kexp == NULL) { |
if (kex != NULL) { |
kex_free(kex); |
sshbuf_free(kex->my); |
|
sshbuf_free(kex->peer); |
|
free(kex); |
|
} |
|
if (kexp != NULL) |
if (kexp != NULL) |
*kexp = NULL; |
*kexp = NULL; |
} else { |
} else { |
|
kex_free(*kexp); |
*kexp = kex; |
*kexp = kex; |
} |
} |
return r; |
return r; |
Line 2521 sshpkt_get_cstring(struct ssh *ssh, char |
|
Line 2540 sshpkt_get_cstring(struct ssh *ssh, char |
|
return sshbuf_get_cstring(ssh->state->incoming_packet, valp, lenp); |
return sshbuf_get_cstring(ssh->state->incoming_packet, valp, lenp); |
} |
} |
|
|
|
int |
|
sshpkt_getb_froms(struct ssh *ssh, struct sshbuf **valp) |
|
{ |
|
return sshbuf_froms(ssh->state->incoming_packet, valp); |
|
} |
|
|
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
int |
int |
sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g) |
sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g) |
Line 2528 sshpkt_get_ec(struct ssh *ssh, EC_POINT |
|
Line 2553 sshpkt_get_ec(struct ssh *ssh, EC_POINT |
|
return sshbuf_get_ec(ssh->state->incoming_packet, v, g); |
return sshbuf_get_ec(ssh->state->incoming_packet, v, g); |
} |
} |
|
|
|
|
int |
int |
sshpkt_get_bignum2(struct ssh *ssh, BIGNUM *v) |
sshpkt_get_bignum2(struct ssh *ssh, BIGNUM **valp) |
{ |
{ |
return sshbuf_get_bignum2(ssh->state->incoming_packet, v); |
return sshbuf_get_bignum2(ssh->state->incoming_packet, valp); |
} |
} |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
|
|
Line 2673 sshpkt_add_padding(struct ssh *ssh, u_ch |
|
Line 2697 sshpkt_add_padding(struct ssh *ssh, u_ch |
|
} |
} |
|
|
int |
int |
ssh_packet_authentication_state(void) |
ssh_packet_authentication_state(struct ssh *ssh) |
{ |
{ |
return active_state->state->after_authentication; |
return ssh->state->after_authentication; |
} |
} |