diff options
author | Darren Tucker <dtucker@cvs.openbsd.org> | 2015-05-15 05:44:22 +0000 |
---|---|---|
committer | Darren Tucker <dtucker@cvs.openbsd.org> | 2015-05-15 05:44:22 +0000 |
commit | 6eb608c1348ca654b1fe4e1c4cbdd390562f1e95 (patch) | |
tree | a3e3103f1cf588e31b200abe627cb8c8a3f443bb | |
parent | f49e632c02b8b98b0a8dd36946c88a7de2e3fd48 (diff) |
Use a salted hash of the lock passphrase instead of plain text and do
constant-time comparisons of it. Should prevent leaking any information about
it via timing, pointed out by Ryan Castellucci. Add a 0.1s incrementing delay
for each failed unlock attempt up to 10s. ok markus@ (earlier version), djm@
-rw-r--r-- | usr.bin/ssh/ssh-agent.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/usr.bin/ssh/ssh-agent.c b/usr.bin/ssh/ssh-agent.c index 73e5e06b8af..cf8493e1811 100644 --- a/usr.bin/ssh/ssh-agent.c +++ b/usr.bin/ssh/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.202 2015/04/24 06:26:49 jmc Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.203 2015/05/15 05:44:21 dtucker Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -57,6 +57,7 @@ #include <limits.h> #include <time.h> #include <unistd.h> +#include <util.h> #include "key.h" /* XXX for typedef */ #include "buffer.h" /* XXX for typedef */ @@ -125,8 +126,12 @@ char socket_name[PATH_MAX]; char socket_dir[PATH_MAX]; /* locking */ +#define LOCK_SIZE 32 +#define LOCK_SALT_SIZE 16 +#define LOCK_ROUNDS 1 int locked = 0; -char *lock_passwd = NULL; +char lock_passwd[LOCK_SIZE]; +char lock_salt[LOCK_SALT_SIZE]; extern char *__progname; @@ -645,23 +650,45 @@ send: static void process_lock_agent(SocketEntry *e, int lock) { - int r, success = 0; - char *passwd; + int r, success = 0, delay; + char *passwd, passwdhash[LOCK_SIZE]; + static u_int fail_count = 0; + size_t pwlen; - if ((r = sshbuf_get_cstring(e->request, &passwd, NULL)) != 0) + if ((r = sshbuf_get_cstring(e->request, &passwd, &pwlen)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); - if (locked && !lock && strcmp(passwd, lock_passwd) == 0) { - locked = 0; - explicit_bzero(lock_passwd, strlen(lock_passwd)); - free(lock_passwd); - lock_passwd = NULL; - success = 1; + if (pwlen == 0) { + debug("empty password not supported"); + } else if (locked && !lock) { + if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt), + passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0) + fatal("bcrypt_pbkdf"); + if (timingsafe_bcmp(passwdhash, lock_passwd, LOCK_SIZE) == 0) { + debug("agent unlocked"); + locked = 0; + fail_count = 0; + explicit_bzero(lock_passwd, sizeof(lock_passwd)); + success = 1; + } else { + /* delay in 0.1s increments up to 10s */ + if (fail_count < 100) + fail_count++; + delay = 100000 * fail_count; + debug("unlock failed, delaying %0.1lf seconds", + (double)delay/1000000); + usleep(delay); + } + explicit_bzero(passwdhash, sizeof(passwdhash)); } else if (!locked && lock) { + debug("agent locked"); locked = 1; - lock_passwd = xstrdup(passwd); + arc4random_buf(lock_salt, sizeof(lock_salt)); + if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt), + lock_passwd, sizeof(lock_passwd), LOCK_ROUNDS) < 0) + fatal("bcrypt_pbkdf"); success = 1; } - explicit_bzero(passwd, strlen(passwd)); + explicit_bzero(passwd, pwlen); free(passwd); send_status(e, success); } |