diff options
author | dtucker@openbsd.org <dtucker@openbsd.org> | 2018-04-13 05:57:26 +0200 |
---|---|---|
committer | Darren Tucker <dtucker@dtucker.net> | 2018-04-13 07:26:11 +0200 |
commit | e9d910b0289c820852f7afa67f584cef1c05fe95 (patch) | |
tree | 207f618329c9df13a2278c71c95b1dc66450bb86 /sshd.c | |
parent | Using "==" in shell tests is not portable. (diff) | |
download | openssh-e9d910b0289c820852f7afa67f584cef1c05fe95.tar.xz openssh-e9d910b0289c820852f7afa67f584cef1c05fe95.zip |
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 '')
-rw-r--r-- | sshd.c | 41 |
1 files changed, 40 insertions, 1 deletions
@@ -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@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@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); |