[openssh-commits] [openssh] 01/01: upstream: Defend against user enumeration timing attacks. This

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Apr 13 15:26:49 AEST 2018


This is an automated email from the git hooks/post-receive script.

dtucker pushed a commit to branch master
in repository openssh.

commit e9d910b0289c820852f7afa67f584cef1c05fe95
Author: dtucker at openbsd.org <dtucker at openbsd.org>
Date:   Fri Apr 13 03:57:26 2018 +0000

    upstream: Defend against user enumeration timing attacks. This
    
    establishes a minimum time for each failed authentication attempt (5ms) and
    adds a per-user constant derived from a host secret (0-4ms).  Based on work
    by joona.kannisto at tut.fi, ok markus@ djm at .
    
    OpenBSD-Commit-ID: b7845b355bb7381703339c8fb0e57e81a20ae5ca
---
 auth2.c    | 43 ++++++++++++++++++++++++++++++++++++++++++-
 servconf.h |  3 ++-
 sshd.c     | 41 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/auth2.c b/auth2.c
index e0034229..2246e54d 100644
--- a/auth2.c
+++ b/auth2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.145 2018/03/03 03:15:51 djm Exp $ */
+/* $OpenBSD: auth2.c,v 1.146 2018/04/13 03:57:26 dtucker Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -57,6 +57,7 @@
 #endif
 #include "monitor_wrap.h"
 #include "ssherr.h"
+#include "digest.h"
 
 /* import */
 extern ServerOptions options;
@@ -210,6 +211,42 @@ input_service_request(int type, u_int32_t seq, struct ssh *ssh)
 	return 0;
 }
 
+#define MIN_FAIL_DELAY_SECONDS 0.005
+static double
+user_specific_delay(const char *user)
+{
+	char b[512];
+	size_t len = ssh_digest_bytes(SSH_DIGEST_SHA512);
+	u_char *hash = xmalloc(len);
+	double delay;
+
+	(void)snprintf(b, sizeof b, "%llu%s", options.timing_secret, user);
+	if (ssh_digest_memory(SSH_DIGEST_SHA512, b, strlen(b), hash, len) != 0)
+		fatal("%s: ssh_digest_memory", __func__);
+	/* 0-4.2 ms of delay */
+	delay = (double)PEEK_U32(hash) / 1000 / 1000 / 1000 / 1000;
+	freezero(hash, len);
+	debug3("%s: user specific delay %0.3lfms", __func__, delay/1000);
+	return MIN_FAIL_DELAY_SECONDS + delay;
+}
+
+static void
+ensure_minimum_time_since(double start, double seconds)
+{
+	struct timespec ts;
+	double elapsed = monotime_double() - start, req = seconds, remain;
+
+	/* if we've already passed the requested time, scale up */
+	while ((remain = seconds - elapsed) < 0.0)
+		seconds *= 2;
+
+	ts.tv_sec = remain;
+	ts.tv_nsec = (remain - ts.tv_sec) * 1000000000;
+	debug3("%s: elapsed %0.3lfms, delaying %0.3lfms (requested %0.3lfms)",
+	    __func__, elapsed*1000, remain*1000, req*1000);
+	nanosleep(&ts, NULL);
+}
+
 /*ARGSUSED*/
 static int
 input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
@@ -218,6 +255,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
 	Authmethod *m = NULL;
 	char *user, *service, *method, *style = NULL;
 	int authenticated = 0;
+	double tstart = monotime_double();
 
 	if (authctxt == NULL)
 		fatal("input_userauth_request: no authctxt");
@@ -286,6 +324,9 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
 		debug2("input_userauth_request: try method %s", method);
 		authenticated =	m->userauth(ssh);
 	}
+	if (!authctxt->authenticated)
+		ensure_minimum_time_since(tstart,
+		    user_specific_delay(authctxt->user));
 	userauth_finish(ssh, authenticated, method, NULL);
 
 	free(service);
diff --git a/servconf.h b/servconf.h
index 37a0fb1a..6d2553c3 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.130 2017/10/25 00:19:47 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.131 2018/04/13 03:57:26 dtucker Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -209,6 +209,7 @@ typedef struct {
 
 	int	fingerprint_hash;
 	int	expose_userauth_info;
+	u_int64_t timing_secret;
 }       ServerOptions;
 
 /* Information about the incoming connection as used by Match */
diff --git a/sshd.c b/sshd.c
index f0ba3507..edbe815c 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.507 2018/04/10 00:10:49 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.508 2018/04/13 03:57:26 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -1413,6 +1413,43 @@ set_process_rdomain(struct ssh *ssh, const char *name)
 #endif
 }
 
+static void
+accumulate_host_timing_secret(struct sshbuf *server_cfg,
+    const struct sshkey *key)
+{
+	static struct ssh_digest_ctx *ctx;
+	u_char *hash;
+	size_t len;
+	struct sshbuf *buf;
+	int r;
+
+	if (ctx == NULL && (ctx = ssh_digest_start(SSH_DIGEST_SHA512)) == NULL)
+		fatal("%s: ssh_digest_start", __func__);
+	if (key == NULL) { /* finalize */
+		/* add server config in case we are using agent for host keys */
+		if (ssh_digest_update(ctx, sshbuf_ptr(server_cfg),
+		    sshbuf_len(server_cfg)) != 0)
+			fatal("%s: ssh_digest_update", __func__);
+		len = ssh_digest_bytes(SSH_DIGEST_SHA512);
+		hash = xmalloc(len);
+		if (ssh_digest_final(ctx, hash, len) != 0)
+			fatal("%s: ssh_digest_final", __func__);
+		options.timing_secret = PEEK_U64(hash);
+		freezero(hash, len);
+		ssh_digest_free(ctx);
+		ctx = NULL;
+		return;
+	}
+	if ((buf = sshbuf_new()) == NULL)
+		fatal("%s could not allocate buffer", __func__);
+	if ((r = sshkey_private_serialize(key, buf)) != 0)
+		fatal("sshkey_private_serialize: %s", ssh_err(r));
+	if (ssh_digest_update(ctx, sshbuf_ptr(buf), sshbuf_len(buf)) != 0)
+		fatal("%s: ssh_digest_update", __func__);
+	sshbuf_reset(buf);
+	sshbuf_free(buf);
+}
+
 /*
  * Main program for the daemon.
  */
@@ -1728,6 +1765,7 @@ main(int ac, char **av)
 			keytype = pubkey->type;
 		} else if (key != NULL) {
 			keytype = key->type;
+			accumulate_host_timing_secret(&cfg, key);
 		} else {
 			error("Could not load host key: %s",
 			    options.host_key_files[i]);
@@ -1753,6 +1791,7 @@ main(int ac, char **av)
 		    key ? "private" : "agent", i, sshkey_ssh_name(pubkey), fp);
 		free(fp);
 	}
+	accumulate_host_timing_secret(&cfg, NULL);
 	if (!sensitive_data.have_ssh2_key) {
 		logit("sshd: no hostkeys available -- exiting.");
 		exit(1);

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list