summaryrefslogtreecommitdiff
path: root/ssh-agent.c
diff options
context:
space:
mode:
authordtucker@openbsd.org <dtucker@openbsd.org>2015-05-15 05:44:21 +0000
committerDamien Miller <djm@mindrot.org>2015-05-21 14:58:29 +1000
commit9173d0fbe44de7ebcad8a15618e13a8b8d78902e (patch)
tree482505d35ca1340c86ef35fe2e29555224d4d778 /ssh-agent.c
parentd028d5d3a697c71b21e4066d8672cacab3caa0a8 (diff)
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
Diffstat (limited to 'ssh-agent.c')
-rw-r--r--ssh-agent.c53
1 files changed, 40 insertions, 13 deletions
diff --git a/ssh-agent.c b/ssh-agent.c
index c75575f66..9e2a37fae 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-agent.c,v 1.202 2015/04/24 06:26:49 jmc Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.203 2015/05/15 05:44:21 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
@@ -68,6 +68,7 @@
68#include <time.h> 68#include <time.h>
69#include <string.h> 69#include <string.h>
70#include <unistd.h> 70#include <unistd.h>
71#include <util.h>
71 72
72#include "key.h" /* XXX for typedef */ 73#include "key.h" /* XXX for typedef */
73#include "buffer.h" /* XXX for typedef */ 74#include "buffer.h" /* XXX for typedef */
@@ -140,8 +141,12 @@ char socket_name[PATH_MAX];
140char socket_dir[PATH_MAX]; 141char socket_dir[PATH_MAX];
141 142
142/* locking */ 143/* locking */
144#define LOCK_SIZE 32
145#define LOCK_SALT_SIZE 16
146#define LOCK_ROUNDS 1
143int locked = 0; 147int locked = 0;
144char *lock_passwd = NULL; 148char lock_passwd[LOCK_SIZE];
149char lock_salt[LOCK_SALT_SIZE];
145 150
146extern char *__progname; 151extern char *__progname;
147 152
@@ -660,23 +665,45 @@ send:
660static void 665static void
661process_lock_agent(SocketEntry *e, int lock) 666process_lock_agent(SocketEntry *e, int lock)
662{ 667{
663 int r, success = 0; 668 int r, success = 0, delay;
664 char *passwd; 669 char *passwd, passwdhash[LOCK_SIZE];
670 static u_int fail_count = 0;
671 size_t pwlen;
665 672
666 if ((r = sshbuf_get_cstring(e->request, &passwd, NULL)) != 0) 673 if ((r = sshbuf_get_cstring(e->request, &passwd, &pwlen)) != 0)
667 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 674 fatal("%s: buffer error: %s", __func__, ssh_err(r));
668 if (locked && !lock && strcmp(passwd, lock_passwd) == 0) { 675 if (pwlen == 0) {
669 locked = 0; 676 debug("empty password not supported");
670 explicit_bzero(lock_passwd, strlen(lock_passwd)); 677 } else if (locked && !lock) {
671 free(lock_passwd); 678 if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
672 lock_passwd = NULL; 679 passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0)
673 success = 1; 680 fatal("bcrypt_pbkdf");
681 if (timingsafe_bcmp(passwdhash, lock_passwd, LOCK_SIZE) == 0) {
682 debug("agent unlocked");
683 locked = 0;
684 fail_count = 0;
685 explicit_bzero(lock_passwd, sizeof(lock_passwd));
686 success = 1;
687 } else {
688 /* delay in 0.1s increments up to 10s */
689 if (fail_count < 100)
690 fail_count++;
691 delay = 100000 * fail_count;
692 debug("unlock failed, delaying %0.1lf seconds",
693 (double)delay/1000000);
694 usleep(delay);
695 }
696 explicit_bzero(passwdhash, sizeof(passwdhash));
674 } else if (!locked && lock) { 697 } else if (!locked && lock) {
698 debug("agent locked");
675 locked = 1; 699 locked = 1;
676 lock_passwd = xstrdup(passwd); 700 arc4random_buf(lock_salt, sizeof(lock_salt));
701 if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
702 lock_passwd, sizeof(lock_passwd), LOCK_ROUNDS) < 0)
703 fatal("bcrypt_pbkdf");
677 success = 1; 704 success = 1;
678 } 705 }
679 explicit_bzero(passwd, strlen(passwd)); 706 explicit_bzero(passwd, pwlen);
680 free(passwd); 707 free(passwd);
681 send_status(e, success); 708 send_status(e, success);
682} 709}