upstream commit
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@ Upstream-ID: c599fcc325aa1cc65496b25220b622d22208c85f
This commit is contained in:
parent
d028d5d3a6
commit
9173d0fbe4
53
ssh-agent.c
53
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>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -68,6 +68,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
#include "key.h" /* XXX for typedef */
|
#include "key.h" /* XXX for typedef */
|
||||||
#include "buffer.h" /* XXX for typedef */
|
#include "buffer.h" /* XXX for typedef */
|
||||||
|
@ -140,8 +141,12 @@ char socket_name[PATH_MAX];
|
||||||
char socket_dir[PATH_MAX];
|
char socket_dir[PATH_MAX];
|
||||||
|
|
||||||
/* locking */
|
/* locking */
|
||||||
|
#define LOCK_SIZE 32
|
||||||
|
#define LOCK_SALT_SIZE 16
|
||||||
|
#define LOCK_ROUNDS 1
|
||||||
int locked = 0;
|
int locked = 0;
|
||||||
char *lock_passwd = NULL;
|
char lock_passwd[LOCK_SIZE];
|
||||||
|
char lock_salt[LOCK_SALT_SIZE];
|
||||||
|
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
|
|
||||||
|
@ -660,23 +665,45 @@ send:
|
||||||
static void
|
static void
|
||||||
process_lock_agent(SocketEntry *e, int lock)
|
process_lock_agent(SocketEntry *e, int lock)
|
||||||
{
|
{
|
||||||
int r, success = 0;
|
int r, success = 0, delay;
|
||||||
char *passwd;
|
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));
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||||
if (locked && !lock && strcmp(passwd, lock_passwd) == 0) {
|
if (pwlen == 0) {
|
||||||
locked = 0;
|
debug("empty password not supported");
|
||||||
explicit_bzero(lock_passwd, strlen(lock_passwd));
|
} else if (locked && !lock) {
|
||||||
free(lock_passwd);
|
if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
|
||||||
lock_passwd = NULL;
|
passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0)
|
||||||
success = 1;
|
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) {
|
} else if (!locked && lock) {
|
||||||
|
debug("agent locked");
|
||||||
locked = 1;
|
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;
|
success = 1;
|
||||||
}
|
}
|
||||||
explicit_bzero(passwd, strlen(passwd));
|
explicit_bzero(passwd, pwlen);
|
||||||
free(passwd);
|
free(passwd);
|
||||||
send_status(e, success);
|
send_status(e, success);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue