summaryrefslogtreecommitdiff
path: root/sshd.c
diff options
context:
space:
mode:
authordtucker@openbsd.org <dtucker@openbsd.org>2018-04-13 03:57:26 +0000
committerDarren Tucker <dtucker@dtucker.net>2018-04-13 15:26:11 +1000
commite9d910b0289c820852f7afa67f584cef1c05fe95 (patch)
tree207f618329c9df13a2278c71c95b1dc66450bb86 /sshd.c
parentd97874cbd909eb706886cd0cdd418f812c119ef9 (diff)
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@. OpenBSD-Commit-ID: b7845b355bb7381703339c8fb0e57e81a20ae5ca
Diffstat (limited to 'sshd.c')
-rw-r--r--sshd.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/sshd.c b/sshd.c
index f0ba35074..edbe815c5 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshd.c,v 1.507 2018/04/10 00:10:49 djm Exp $ */ 1/* $OpenBSD: sshd.c,v 1.508 2018/04/13 03:57:26 dtucker Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1413,6 +1413,43 @@ set_process_rdomain(struct ssh *ssh, const char *name)
1413#endif 1413#endif
1414} 1414}
1415 1415
1416static void
1417accumulate_host_timing_secret(struct sshbuf *server_cfg,
1418 const struct sshkey *key)
1419{
1420 static struct ssh_digest_ctx *ctx;
1421 u_char *hash;
1422 size_t len;
1423 struct sshbuf *buf;
1424 int r;
1425
1426 if (ctx == NULL && (ctx = ssh_digest_start(SSH_DIGEST_SHA512)) == NULL)
1427 fatal("%s: ssh_digest_start", __func__);
1428 if (key == NULL) { /* finalize */
1429 /* add server config in case we are using agent for host keys */
1430 if (ssh_digest_update(ctx, sshbuf_ptr(server_cfg),
1431 sshbuf_len(server_cfg)) != 0)
1432 fatal("%s: ssh_digest_update", __func__);
1433 len = ssh_digest_bytes(SSH_DIGEST_SHA512);
1434 hash = xmalloc(len);
1435 if (ssh_digest_final(ctx, hash, len) != 0)
1436 fatal("%s: ssh_digest_final", __func__);
1437 options.timing_secret = PEEK_U64(hash);
1438 freezero(hash, len);
1439 ssh_digest_free(ctx);
1440 ctx = NULL;
1441 return;
1442 }
1443 if ((buf = sshbuf_new()) == NULL)
1444 fatal("%s could not allocate buffer", __func__);
1445 if ((r = sshkey_private_serialize(key, buf)) != 0)
1446 fatal("sshkey_private_serialize: %s", ssh_err(r));
1447 if (ssh_digest_update(ctx, sshbuf_ptr(buf), sshbuf_len(buf)) != 0)
1448 fatal("%s: ssh_digest_update", __func__);
1449 sshbuf_reset(buf);
1450 sshbuf_free(buf);
1451}
1452
1416/* 1453/*
1417 * Main program for the daemon. 1454 * Main program for the daemon.
1418 */ 1455 */
@@ -1728,6 +1765,7 @@ main(int ac, char **av)
1728 keytype = pubkey->type; 1765 keytype = pubkey->type;
1729 } else if (key != NULL) { 1766 } else if (key != NULL) {
1730 keytype = key->type; 1767 keytype = key->type;
1768 accumulate_host_timing_secret(&cfg, key);
1731 } else { 1769 } else {
1732 error("Could not load host key: %s", 1770 error("Could not load host key: %s",
1733 options.host_key_files[i]); 1771 options.host_key_files[i]);
@@ -1753,6 +1791,7 @@ main(int ac, char **av)
1753 key ? "private" : "agent", i, sshkey_ssh_name(pubkey), fp); 1791 key ? "private" : "agent", i, sshkey_ssh_name(pubkey), fp);
1754 free(fp); 1792 free(fp);
1755 } 1793 }
1794 accumulate_host_timing_secret(&cfg, NULL);
1756 if (!sensitive_data.have_ssh2_key) { 1795 if (!sensitive_data.have_ssh2_key) {
1757 logit("sshd: no hostkeys available -- exiting."); 1796 logit("sshd: no hostkeys available -- exiting.");
1758 exit(1); 1797 exit(1);