summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarren Tucker <dtucker@cvs.openbsd.org>2015-05-15 05:44:22 +0000
committerDarren Tucker <dtucker@cvs.openbsd.org>2015-05-15 05:44:22 +0000
commit6eb608c1348ca654b1fe4e1c4cbdd390562f1e95 (patch)
treea3e3103f1cf588e31b200abe627cb8c8a3f443bb
parentf49e632c02b8b98b0a8dd36946c88a7de2e3fd48 (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.c53
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);
}