sync code with last improvements from OpenBSD

This commit is contained in:
purplerain 2023-08-28 17:23:15 +00:00
parent 4ee2459da1
commit 12cd8aa4a2
Signed by: purplerain
GPG Key ID: F42C07F07E2E35B7
17 changed files with 397 additions and 66 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dt_prov_static.c,v 1.21 2023/08/14 08:33:24 mpi Exp $ */
/* $OpenBSD: dt_prov_static.c,v 1.22 2023/08/28 14:50:01 bluhm Exp $ */
/*
* Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
@ -100,6 +100,7 @@ DT_STATIC_PROBE3(refcnt, ifaddr, "void *", "int", "int");
DT_STATIC_PROBE3(refcnt, ifmaddr, "void *", "int", "int");
DT_STATIC_PROBE3(refcnt, inpcb, "void *", "int", "int");
DT_STATIC_PROBE3(refcnt, rtentry, "void *", "int", "int");
DT_STATIC_PROBE3(refcnt, syncache, "void *", "int", "int");
DT_STATIC_PROBE3(refcnt, tdb, "void *", "int", "int");
/*
@ -152,6 +153,7 @@ struct dt_probe *const dtps_static[] = {
&_DT_STATIC_P(refcnt, ifmaddr),
&_DT_STATIC_P(refcnt, inpcb),
&_DT_STATIC_P(refcnt, rtentry),
&_DT_STATIC_P(refcnt, syncache),
&_DT_STATIC_P(refcnt, tdb),
};

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tcp_input.c,v 1.389 2023/07/06 09:15:23 bluhm Exp $ */
/* $OpenBSD: tcp_input.c,v 1.390 2023/08/28 14:50:01 bluhm Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@ -192,7 +192,6 @@ void syn_cache_put(struct syn_cache *);
void syn_cache_rm(struct syn_cache *);
int syn_cache_respond(struct syn_cache *, struct mbuf *, uint64_t);
void syn_cache_timer(void *);
void syn_cache_reaper(void *);
void syn_cache_insert(struct syn_cache *, struct tcpcb *);
void syn_cache_reset(struct sockaddr *, struct sockaddr *,
struct tcphdr *, u_int);
@ -3091,6 +3090,7 @@ int tcp_syn_cache_limit = TCP_SYN_HASH_SIZE*TCP_SYN_BUCKET_SIZE;
int tcp_syn_bucket_limit = 3*TCP_SYN_BUCKET_SIZE;
int tcp_syn_use_limit = 100000;
struct pool syn_cache_pool;
struct syn_cache_set tcp_syn_cache[2];
int tcp_syn_cache_active;
@ -3138,25 +3138,27 @@ syn_cache_rm(struct syn_cache *sc)
TAILQ_REMOVE(&sc->sc_buckethead->sch_bucket, sc, sc_bucketq);
sc->sc_tp = NULL;
LIST_REMOVE(sc, sc_tpq);
refcnt_rele(&sc->sc_refcnt);
sc->sc_buckethead->sch_length--;
timeout_del(&sc->sc_timer);
if (timeout_del(&sc->sc_timer))
refcnt_rele(&sc->sc_refcnt);
sc->sc_set->scs_count--;
}
void
syn_cache_put(struct syn_cache *sc)
{
if (refcnt_rele(&sc->sc_refcnt) == 0)
return;
m_free(sc->sc_ipopts);
if (sc->sc_route4.ro_rt != NULL) {
rtfree(sc->sc_route4.ro_rt);
sc->sc_route4.ro_rt = NULL;
}
timeout_set(&sc->sc_timer, syn_cache_reaper, sc);
timeout_add(&sc->sc_timer, 0);
pool_put(&syn_cache_pool, sc);
}
struct pool syn_cache_pool;
/*
* We don't estimate RTT with SYNs, so each packet starts with the default
* RTT and each timer step has a fixed timeout value.
@ -3166,9 +3168,8 @@ do { \
TCPT_RANGESET((sc)->sc_rxtcur, \
TCPTV_SRTTDFLT * tcp_backoff[(sc)->sc_rxtshift], TCPTV_MIN, \
TCPTV_REXMTMAX); \
if (!timeout_initialized(&(sc)->sc_timer)) \
timeout_set_proc(&(sc)->sc_timer, syn_cache_timer, (sc)); \
timeout_add_msec(&(sc)->sc_timer, (sc)->sc_rxtcur); \
if (timeout_add_msec(&(sc)->sc_timer, (sc)->sc_rxtcur)) \
refcnt_take(&(sc)->sc_refcnt); \
} while (/*CONSTCOND*/0)
void
@ -3306,6 +3307,7 @@ syn_cache_insert(struct syn_cache *sc, struct tcpcb *tp)
SYN_CACHE_TIMER_ARM(sc);
/* Link it from tcpcb entry */
refcnt_take(&sc->sc_refcnt);
LIST_INSERT_HEAD(&tp->t_sc, sc, sc_tpq);
/* Put it into the bucket. */
@ -3336,10 +3338,11 @@ syn_cache_timer(void *arg)
{
struct syn_cache *sc = arg;
uint64_t now;
int lastref;
NET_LOCK();
if (sc->sc_flags & SCF_DEAD)
goto out;
goto freeit;
now = tcp_now();
@ -3364,26 +3367,28 @@ syn_cache_timer(void *arg)
sc->sc_rxtshift++;
SYN_CACHE_TIMER_ARM(sc);
out:
/*
* Decrement reference of this timer. We know there is another timer
* as we just added it. So just deref, free is not necessary.
*/
lastref = refcnt_rele(&sc->sc_refcnt);
KASSERT(lastref == 0);
(void)lastref;
NET_UNLOCK();
return;
dropit:
tcpstat_inc(tcps_sc_timed_out);
syn_cache_rm(sc);
/* Decrement reference of the timer and free object after remove. */
lastref = refcnt_rele(&sc->sc_refcnt);
KASSERT(lastref == 0);
(void)lastref;
freeit:
syn_cache_put(sc);
NET_UNLOCK();
}
void
syn_cache_reaper(void *arg)
{
struct syn_cache *sc = arg;
pool_put(&syn_cache_pool, (sc));
return;
}
/*
* Remove syn cache created by the specified tcb entry,
* because this does not make sense to keep them
@ -3826,6 +3831,8 @@ syn_cache_add(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th,
m_free(ipopts);
return (-1);
}
refcnt_init_trace(&sc->sc_refcnt, DT_REFCNT_IDX_SYNCACHE);
timeout_set_proc(&sc->sc_timer, syn_cache_timer, sc);
/*
* Fill in the cache, and put the necessary IP and TCP

View File

@ -1,4 +1,4 @@
/* $OpenBSD: tcp_var.h,v 1.169 2023/07/06 09:15:24 bluhm Exp $ */
/* $OpenBSD: tcp_var.h,v 1.170 2023/08/28 14:50:02 bluhm Exp $ */
/* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */
/*
@ -236,6 +236,7 @@ union syn_cache_sa {
struct syn_cache {
TAILQ_ENTRY(syn_cache) sc_bucketq; /* link on bucket list */
struct refcnt sc_refcnt; /* ref count list and timer */
struct timeout sc_timer; /* rexmt timer */
union { /* cached route */
struct route route4;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: refcnt.h,v 1.11 2023/07/06 19:46:53 kn Exp $ */
/* $OpenBSD: refcnt.h,v 1.12 2023/08/28 14:50:02 bluhm Exp $ */
/*
* Copyright (c) 2015 David Gwynne <dlg@openbsd.org>
@ -49,7 +49,8 @@ unsigned int refcnt_read(struct refcnt *);
#define DT_REFCNT_IDX_IFMADDR 3
#define DT_REFCNT_IDX_INPCB 4
#define DT_REFCNT_IDX_RTENTRY 5
#define DT_REFCNT_IDX_TDB 6
#define DT_REFCNT_IDX_SYNCACHE 6
#define DT_REFCNT_IDX_TDB 7
#endif /* _KERNEL */

View File

@ -104,6 +104,39 @@ http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.o
This is identical to curve25519-sha256 as later published in RFC8731.
1.9 transport: ping facility
OpenSSH implements a transport level ping message SSH2_MSG_PING
and a corresponding SSH2_MSG_PONG reply.
#define SSH2_MSG_PING 192
#define SSH2_MSG_PONG 193
The ping message is simply:
byte SSH_MSG_PING
string data
The reply copies the data (which may be the empty string) from the
ping:
byte SSH_MSG_PONG
string data
Replies are sent in order. They are sent immediately except when rekeying
is in progress, in which case they are queued until rekeying completes.
The server advertises support for these messages using the
SSH2_MSG_EXT_INFO mechanism (RFC8308), with the following message:
string "ping@openssh.com"
string "0" (version)
The ping/reply message is implemented at the transport layer rather
than as a named global or channel request to allow pings with very
short packet lengths, which would not be possible with other
approaches.
2. Connection protocol changes
2.1. connection: Channel write close extension "eow@openssh.com"
@ -712,4 +745,4 @@ master instance and later clients.
OpenSSH extends the usual agent protocol. These changes are documented
in the PROTOCOL.agent file.
$OpenBSD: PROTOCOL,v 1.48 2022/11/07 01:53:01 dtucker Exp $
$OpenBSD: PROTOCOL,v 1.49 2023/08/28 03:28:43 djm Exp $

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2.c,v 1.166 2023/03/08 04:43:12 guenther Exp $ */
/* $OpenBSD: auth2.c,v 1.167 2023/08/28 09:48:11 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -208,6 +208,7 @@ input_service_request(int type, u_int32_t seq, struct ssh *ssh)
}
#define MIN_FAIL_DELAY_SECONDS 0.005
#define MAX_FAIL_DELAY_SECONDS 5.0
static double
user_specific_delay(const char *user)
{
@ -233,6 +234,12 @@ ensure_minimum_time_since(double start, double seconds)
struct timespec ts;
double elapsed = monotime_double() - start, req = seconds, remain;
if (elapsed > MAX_FAIL_DELAY_SECONDS) {
debug3_f("elapsed %0.3lfms exceeded the max delay "
"requested %0.3lfms)", elapsed*1000, req*1000);
return;
}
/* if we've already passed the requested time, scale up */
while ((remain = seconds - elapsed) < 0.0)
seconds *= 2;
@ -317,7 +324,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
debug2("input_userauth_request: try method %s", method);
authenticated = m->userauth(ssh, method);
}
if (!authctxt->authenticated)
if (!authctxt->authenticated && strcmp(method, "none") != 0)
ensure_minimum_time_since(tstart,
user_specific_delay(authctxt->user));
userauth_finish(ssh, authenticated, method, NULL);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.392 2023/04/03 08:10:54 dtucker Exp $ */
/* $OpenBSD: clientloop.c,v 1.394 2023/08/28 04:06:52 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -498,6 +498,128 @@ server_alive_check(struct ssh *ssh)
schedule_server_alive_check();
}
/* Try to send a dummy keystroke */
static int
send_chaff(struct ssh *ssh)
{
int r;
if ((ssh->kex->flags & KEX_HAS_PING) == 0)
return 0;
/* XXX probabilistically send chaff? */
/*
* a SSH2_MSG_CHANNEL_DATA payload is 9 bytes:
* 4 bytes channel ID + 4 bytes string length + 1 byte string data
* simulate that here.
*/
if ((r = sshpkt_start(ssh, SSH2_MSG_PING)) != 0 ||
(r = sshpkt_put_cstring(ssh, "PING!")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
return 1;
}
/*
* Performs keystroke timing obfuscation. Returns non-zero if the
* output fd should be polled.
*/
static int
obfuscate_keystroke_timing(struct ssh *ssh, struct timespec *timeout)
{
static int active;
static struct timespec next_interval, chaff_until;
struct timespec now, tmp;
int just_started = 0, had_keystroke = 0;
static unsigned long long nchaff;
char *stop_reason = NULL;
long long n;
monotime_ts(&now);
if (options.obscure_keystroke_timing_interval <= 0)
return 1; /* disabled in config */
if (!channel_still_open(ssh) || quit_pending) {
/* Stop if no channels left of we're waiting for one to close */
stop_reason = "no active channels";
} else if (ssh_packet_is_rekeying(ssh)) {
/* Stop if we're rekeying */
stop_reason = "rekeying started";
} else if (!ssh_packet_interactive_data_to_write(ssh) &&
ssh_packet_have_data_to_write(ssh)) {
/* Stop if the output buffer has more than a few keystrokes */
stop_reason = "output buffer filling";
} else if (active && ssh_packet_have_data_to_write(ssh)) {
/* Still in active mode and have a keystroke queued. */
had_keystroke = 1;
} else if (active) {
if (timespeccmp(&now, &chaff_until, >=)) {
/* Stop if there have been no keystrokes for a while */
stop_reason = "chaff time expired";
} else if (timespeccmp(&now, &next_interval, >=)) {
/* Otherwise if we were due to send, then send chaff */
if (send_chaff(ssh))
nchaff++;
}
}
if (stop_reason != NULL) {
active = 0;
debug3_f("stopping: %s (%llu chaff packets sent)",
stop_reason, nchaff);
return 1;
}
/*
* If we're in interactive mode, and only have a small amount
* of outbound data, then we assume that the user is typing
* interactively. In this case, start quantising outbound packets to
* fixed time intervals to hide inter-keystroke timing.
*/
if (!active && ssh_packet_interactive_data_to_write(ssh)) {
debug3_f("starting: interval %d",
options.obscure_keystroke_timing_interval);
just_started = had_keystroke = active = 1;
nchaff = 0;
ms_to_timespec(&tmp, options.obscure_keystroke_timing_interval);
timespecadd(&now, &tmp, &next_interval);
}
/* Don't hold off if obfuscation inactive */
if (!active)
return 1;
if (had_keystroke) {
/*
* Arrange to send chaff packets for a random interval after
* the last keystroke was sent.
*/
ms_to_timespec(&tmp, SSH_KEYSTROKE_CHAFF_MIN_MS +
arc4random_uniform(SSH_KEYSTROKE_CHAFF_RNG_MS));
timespecadd(&now, &tmp, &chaff_until);
}
ptimeout_deadline_monotime_tsp(timeout, &next_interval);
if (just_started)
return 1;
/* Don't arm output fd for poll until the timing interval has elapsed */
if (timespeccmp(&now, &next_interval, <))
return 0;
/* Calculate number of intervals missed since the last check */
n = (now.tv_sec - next_interval.tv_sec) * 1000LL * 1000 * 1000;
n += now.tv_nsec - next_interval.tv_nsec;
n /= options.obscure_keystroke_timing_interval * 1000LL * 1000;
n = (n < 0) ? 1 : n + 1;
/* Advance to the next interval */
ms_to_timespec(&tmp, options.obscure_keystroke_timing_interval * n);
timespecadd(&now, &tmp, &next_interval);
return 1;
}
/*
* Waits until the client can do something (some data becomes available on
* one of the file descriptors).
@ -508,7 +630,7 @@ client_wait_until_can_do_something(struct ssh *ssh, struct pollfd **pfdp,
int *conn_in_readyp, int *conn_out_readyp)
{
struct timespec timeout;
int ret;
int ret, oready;
u_int p;
*conn_in_readyp = *conn_out_readyp = 0;
@ -528,11 +650,14 @@ client_wait_until_can_do_something(struct ssh *ssh, struct pollfd **pfdp,
return;
}
oready = obfuscate_keystroke_timing(ssh, &timeout);
/* Monitor server connection on reserved pollfd entries */
(*pfdp)[0].fd = connection_in;
(*pfdp)[0].events = POLLIN;
(*pfdp)[1].fd = connection_out;
(*pfdp)[1].events = ssh_packet_have_data_to_write(ssh) ? POLLOUT : 0;
(*pfdp)[1].events = (oready && ssh_packet_have_data_to_write(ssh)) ?
POLLOUT : 0;
/*
* Wait for something to happen. This will suspend the process until
@ -549,7 +674,7 @@ client_wait_until_can_do_something(struct ssh *ssh, struct pollfd **pfdp,
ssh_packet_get_rekey_timeout(ssh));
}
ret = poll(*pfdp, *npfd_activep, ptimeout_get_ms(&timeout));
ret = ppoll(*pfdp, *npfd_activep, ptimeout_get_tsp(&timeout), NULL);
if (ret == -1) {
/*

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.c,v 1.180 2023/08/21 21:16:18 tobhe Exp $ */
/* $OpenBSD: kex.c,v 1.181 2023/08/28 03:28:43 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@ -477,12 +477,14 @@ kex_send_ext_info(struct ssh *ssh)
return SSH_ERR_ALLOC_FAIL;
/* XXX filter algs list by allowed pubkey/hostbased types */
if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
(r = sshpkt_put_u32(ssh, 2)) != 0 ||
(r = sshpkt_put_u32(ssh, 3)) != 0 ||
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
(r = sshpkt_put_cstring(ssh, algs)) != 0 ||
(r = sshpkt_put_cstring(ssh,
"publickey-hostbound@openssh.com")) != 0 ||
(r = sshpkt_put_cstring(ssh, "0")) != 0 ||
(r = sshpkt_put_cstring(ssh, "ping@openssh.com")) != 0 ||
(r = sshpkt_put_cstring(ssh, "0")) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
error_fr(r, "compose");
goto out;
@ -512,6 +514,23 @@ kex_send_newkeys(struct ssh *ssh)
return 0;
}
/* Check whether an ext_info value contains the expected version string */
static int
kex_ext_info_check_ver(struct kex *kex, const char *name,
const u_char *val, size_t len, const char *want_ver, u_int flag)
{
if (memchr(val, '\0', len) != NULL) {
error("SSH2_MSG_EXT_INFO: %s value contains nul byte", name);
return SSH_ERR_INVALID_FORMAT;
}
debug_f("%s=<%s>", name, val);
if (strcmp(val, want_ver) == 0)
kex->flags |= flag;
else
debug_f("unsupported version of %s extension", name);
return 0;
}
int
kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
{
@ -542,6 +561,8 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
/* Ensure no \0 lurking in value */
if (memchr(val, '\0', vlen) != NULL) {
error_f("nul byte in %s", name);
free(name);
free(val);
return SSH_ERR_INVALID_FORMAT;
}
debug_f("%s=<%s>", name, val);
@ -549,18 +570,18 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
val = NULL;
} else if (strcmp(name,
"publickey-hostbound@openssh.com") == 0) {
/* XXX refactor */
/* Ensure no \0 lurking in value */
if (memchr(val, '\0', vlen) != NULL) {
error_f("nul byte in %s", name);
return SSH_ERR_INVALID_FORMAT;
if ((r = kex_ext_info_check_ver(kex, name, val, vlen,
"0", KEX_HAS_PUBKEY_HOSTBOUND)) != 0) {
free(name);
free(val);
return r;
}
debug_f("%s=<%s>", name, val);
if (strcmp(val, "0") == 0)
kex->flags |= KEX_HAS_PUBKEY_HOSTBOUND;
else {
debug_f("unsupported version of %s extension",
name);
} else if (strcmp(name, "ping@openssh.com") == 0) {
if ((r = kex_ext_info_check_ver(kex, name, val, vlen,
"0", KEX_HAS_PING)) != 0) {
free(name);
free(val);
return r;
}
} else
debug_f("%s (unrecognised)", name);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.h,v 1.118 2023/03/06 12:14:48 dtucker Exp $ */
/* $OpenBSD: kex.h,v 1.119 2023/08/28 03:28:43 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -104,6 +104,7 @@ enum kex_exchange {
#define KEX_HAS_PUBKEY_HOSTBOUND 0x0004
#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */
#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */
#define KEX_HAS_PING 0x0020
struct sshenc {
char *name;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.186 2023/08/18 01:37:41 djm Exp $ */
/* $OpenBSD: misc.c,v 1.187 2023/08/28 03:31:16 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005-2020 Damien Miller. All rights reserved.
@ -2792,22 +2792,33 @@ ptimeout_deadline_ms(struct timespec *pt, long ms)
ptimeout_deadline_tsp(pt, &p);
}
/* Specify a poll/ppoll deadline at wall clock monotime 'when' (timespec) */
void
ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when)
{
struct timespec now, t;
monotime_ts(&now);
if (timespeccmp(&now, when, >=)) {
/* 'when' is now or in the past. Timeout ASAP */
pt->tv_sec = 0;
pt->tv_nsec = 0;
} else {
timespecsub(when, &now, &t);
ptimeout_deadline_tsp(pt, &t);
}
}
/* Specify a poll/ppoll deadline at wall clock monotime 'when' */
void
ptimeout_deadline_monotime(struct timespec *pt, time_t when)
{
struct timespec now, t;
struct timespec t;
t.tv_sec = when;
t.tv_nsec = 0;
monotime_ts(&now);
if (timespeccmp(&now, &t, >=))
ptimeout_deadline_sec(pt, 0);
else {
timespecsub(&t, &now, &t);
ptimeout_deadline_tsp(pt, &t);
}
ptimeout_deadline_monotime_tsp(pt, &t);
}
/* Get a poll(2) timeout value in milliseconds */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.104 2023/08/18 01:37:41 djm Exp $ */
/* $OpenBSD: misc.h,v 1.105 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -212,6 +212,7 @@ struct timespec;
void ptimeout_init(struct timespec *pt);
void ptimeout_deadline_sec(struct timespec *pt, long sec);
void ptimeout_deadline_ms(struct timespec *pt, long ms);
void ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when);
void ptimeout_deadline_monotime(struct timespec *pt, time_t when);
int ptimeout_get_ms(struct timespec *pt);
struct timespec *ptimeout_get_tsp(struct timespec *pt);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.c,v 1.310 2023/04/06 03:21:31 djm Exp $ */
/* $OpenBSD: packet.c,v 1.312 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1034,6 +1034,8 @@ int
ssh_packet_log_type(u_char type)
{
switch (type) {
case SSH2_MSG_PING:
case SSH2_MSG_PONG:
case SSH2_MSG_CHANNEL_DATA:
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
@ -1654,7 +1656,7 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
goto out;
if (ssh_packet_log_type(*typep))
debug3("receive packet: type %u", *typep);
if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) {
if (*typep < SSH2_MSG_MIN) {
if ((r = sshpkt_disconnect(ssh,
"Invalid ssh2 packet type: %d", *typep)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
@ -1689,6 +1691,8 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
u_int reason, seqnr;
int r;
u_char *msg;
const u_char *d;
size_t len;
for (;;) {
msg = NULL;
@ -1732,6 +1736,21 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
seqnr);
break;
case SSH2_MSG_PING:
if ((r = sshpkt_get_string_direct(ssh, &d, &len)) != 0)
return r;
DBG(debug("Received SSH2_MSG_PING len %zu", len));
if ((r = sshpkt_start(ssh, SSH2_MSG_PONG)) != 0 ||
(r = sshpkt_put_string(ssh, d, len)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
break;
case SSH2_MSG_PONG:
if ((r = sshpkt_get_string_direct(ssh,
NULL, &len)) != 0)
return r;
DBG(debug("Received SSH2_MSG_PONG len %zu", len));
break;
default:
return 0;
}
@ -2041,6 +2060,18 @@ ssh_packet_not_very_much_data_to_write(struct ssh *ssh)
return sshbuf_len(ssh->state->output) < 128 * 1024;
}
/*
* returns true when there are at most a few keystrokes of data to write
* and the connection is in interactive mode.
*/
int
ssh_packet_interactive_data_to_write(struct ssh *ssh)
{
return ssh->state->interactive_mode &&
sshbuf_len(ssh->state->output) < 256;
}
void
ssh_packet_set_tos(struct ssh *ssh, int tos)
{

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.h,v 1.94 2022/01/22 00:49:34 djm Exp $ */
/* $OpenBSD: packet.h,v 1.95 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -139,6 +139,7 @@ int ssh_packet_write_poll(struct ssh *);
int ssh_packet_write_wait(struct ssh *);
int ssh_packet_have_data_to_write(struct ssh *);
int ssh_packet_not_very_much_data_to_write(struct ssh *);
int ssh_packet_interactive_data_to_write(struct ssh *);
int ssh_packet_connection_is_on_socket(struct ssh *);
int ssh_packet_remaining(struct ssh *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.380 2023/07/17 06:16:33 djm Exp $ */
/* $OpenBSD: readconf.c,v 1.381 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -162,7 +162,7 @@ typedef enum {
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
oEnableEscapeCommandline,
oEnableEscapeCommandline, oObscureKeystrokeTiming,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@ -311,6 +311,7 @@ static struct {
{ "knownhostscommand", oKnownHostsCommand },
{ "requiredrsasize", oRequiredRSASize },
{ "enableescapecommandline", oEnableEscapeCommandline },
{ "obscurekeystroketiming", oObscureKeystrokeTiming },
{ NULL, oBadOption }
};
@ -2257,6 +2258,48 @@ parse_pubkey_algos:
intptr = &options->required_rsa_size;
goto parse_int;
case oObscureKeystrokeTiming:
value = -1;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (value != -1) {
error("%s line %d: invalid arguments",
filename, linenum);
goto out;
}
if (strcmp(arg, "yes") == 0 ||
strcmp(arg, "true") == 0)
value = SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
else if (strcmp(arg, "no") == 0 ||
strcmp(arg, "false") == 0)
value = 0;
else if (strncmp(arg, "interval:", 9) == 0) {
if ((errstr = atoi_err(arg + 9,
&value)) != NULL) {
error("%s line %d: integer value %s.",
filename, linenum, errstr);
goto out;
}
if (value <= 0 || value > 1000) {
error("%s line %d: value out of range.",
filename, linenum);
goto out;
}
} else {
error("%s line %d: unsupported argument \"%s\"",
filename, linenum, arg);
goto out;
}
}
if (value == -1) {
error("%s line %d: missing argument",
filename, linenum);
goto out;
}
intptr = &options->obscure_keystroke_timing_interval;
if (*activep && *intptr == -1)
*intptr = value;
break;
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@ -2507,6 +2550,7 @@ initialize_options(Options * options)
options->known_hosts_command = NULL;
options->required_rsa_size = -1;
options->enable_escape_commandline = -1;
options->obscure_keystroke_timing_interval = -1;
options->tag = NULL;
}
@ -2701,6 +2745,10 @@ fill_default_options(Options * options)
options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
if (options->enable_escape_commandline == -1)
options->enable_escape_commandline = 0;
if (options->obscure_keystroke_timing_interval == -1) {
options->obscure_keystroke_timing_interval =
SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
}
/* Expand KEX name lists */
all_cipher = cipher_alg_list(',', 0);
@ -3243,6 +3291,16 @@ lookup_opcode_name(OpCodes code)
static void
dump_cfg_int(OpCodes code, int val)
{
if (code == oObscureKeystrokeTiming) {
if (val == 0) {
printf("%s no\n", lookup_opcode_name(code));
return;
} else if (val == SSH_KEYSTROKE_DEFAULT_INTERVAL_MS) {
printf("%s yes\n", lookup_opcode_name(code));
return;
}
/* FALLTHROUGH */
}
printf("%s %d\n", lookup_opcode_name(code), val);
}
@ -3393,6 +3451,8 @@ dump_client_config(Options *o, const char *host)
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
dump_cfg_int(oObscureKeystrokeTiming,
o->obscure_keystroke_timing_interval);
/* String options */
dump_cfg_string(oBindAddress, o->bind_address);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.151 2023/07/17 04:08:31 djm Exp $ */
/* $OpenBSD: readconf.h,v 1.152 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -180,6 +180,7 @@ typedef struct {
int required_rsa_size; /* minimum size of RSA keys */
int enable_escape_commandline; /* ~C commandline */
int obscure_keystroke_timing_interval;
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;
@ -222,6 +223,11 @@ typedef struct {
#define SSH_STRICT_HOSTKEY_YES 2
#define SSH_STRICT_HOSTKEY_ASK 3
/* ObscureKeystrokes parameters */
#define SSH_KEYSTROKE_DEFAULT_INTERVAL_MS 20
#define SSH_KEYSTROKE_CHAFF_MIN_MS 1024
#define SSH_KEYSTROKE_CHAFF_RNG_MS 2048
const char *kex_default_pk_alg(void);
char *ssh_connection_hash(const char *thishost, const char *host,
const char *portstr, const char *user);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh2.h,v 1.20 2023/08/14 03:37:00 djm Exp $ */
/* $OpenBSD: ssh2.h,v 1.21 2023/08/28 03:28:43 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -108,6 +108,10 @@
#define SSH2_MSG_KEX_ECDH_INIT 30
#define SSH2_MSG_KEX_ECDH_REPLY 31
/* transport layer: OpenSSH extensions */
#define SSH2_MSG_PING 192
#define SSH2_MSG_PONG 193
/* user authentication: generic */
#define SSH2_MSG_USERAUTH_REQUEST 50

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh_config.5,v 1.383 2023/07/17 05:36:14 jsg Exp $
.Dd $Mdocdate: July 17 2023 $
.\" $OpenBSD: ssh_config.5,v 1.386 2023/08/28 09:52:09 djm Exp $
.Dd $Mdocdate: August 28 2023 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
@ -1359,6 +1359,25 @@ or
Specifies the number of password prompts before giving up.
The argument to this keyword must be an integer.
The default is 3.
.It Cm ObscureKeystrokeTiming
Specifies whether
.Xr ssh 1
should try to obscure inter-keystroke timings from passive observers of
network traffic.
If enabled, then for interactive sessions,
.Xr ssh 1
will send keystrokes at fixed intervals of a few tens of milliseconds
and will send fake keystroke packets for some time after typing ceases.
The argument to this keyword must be
.Cm yes ,
.Cm no
or an interval specifier of the form
.Cm interval:milliseconds
(e.g.\&
.Cm interval:80
for 80 milliseconds).
The default is to obscure keystrokes using a 20ms packet interval.
Note that smaller intervals will result in higher fake keystroke packet rates.
.It Cm PasswordAuthentication
Specifies whether to use password authentication.
The argument to this keyword must be