diff options
author | dtucker@openbsd.org <dtucker@openbsd.org> | 2015-05-15 05:44:21 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2015-05-21 14:58:29 +1000 |
commit | 9173d0fbe44de7ebcad8a15618e13a8b8d78902e (patch) | |
tree | 482505d35ca1340c86ef35fe2e29555224d4d778 /ssh-agent.c | |
parent | d028d5d3a697c71b21e4066d8672cacab3caa0a8 (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.c | 53 |
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]; | |||
140 | char socket_dir[PATH_MAX]; | 141 | char 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 | ||
143 | int locked = 0; | 147 | int locked = 0; |
144 | char *lock_passwd = NULL; | 148 | char lock_passwd[LOCK_SIZE]; |
149 | char lock_salt[LOCK_SALT_SIZE]; | ||
145 | 150 | ||
146 | extern char *__progname; | 151 | extern char *__progname; |
147 | 152 | ||
@@ -660,23 +665,45 @@ send: | |||
660 | static void | 665 | static void |
661 | process_lock_agent(SocketEntry *e, int lock) | 666 | process_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 | } |