From: Peter Avalos Date: Sat, 24 Dec 2011 21:00:13 +0000 (-0800) Subject: pam_ssh: Don't allow a bogus passphrase for unencrypted keys. X-Git-Tag: v3.0.0~302 X-Git-Url: http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/09e61f6cd8073fbb48eab8523b4bcc4f82dac34d pam_ssh: Don't allow a bogus passphrase for unencrypted keys. key_load_private() ignores the passphrase argument if the private key is unencrypted. This defeats the nullok check, because it means a non-null passphrase will successfully unlock the key. To address this, try at first to load the key without a passphrase. If this succeeds and the user provided a non-empty passphrase *or* nullok is false, reject the key. While I'm here: Load the ECDSA key if there is one. Obtained-from: FreeBSD 227757, 219426, & 226101 --- diff --git a/lib/pam_module/pam_ssh/pam_ssh.8 b/lib/pam_module/pam_ssh/pam_ssh.8 index 1e8a402..3ba9e66 100644 --- a/lib/pam_module/pam_ssh/pam_ssh.8 +++ b/lib/pam_module/pam_ssh/pam_ssh.8 @@ -1,6 +1,6 @@ .\" Copyright (c) 2001 Mark R V Murray -.\" All rights reserved. .\" Copyright (c) 2001-2003 Networks Associates Technology, Inc. +.\" Copyright (c) 2004-2011 Dag-Erling Smørgrav .\" All rights reserved. .\" .\" This software was developed for the FreeBSD Project by ThinkSec AS and @@ -32,10 +32,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libpam/modules/pam_ssh/pam_ssh.8,v 1.14 2005/09/22 05:35:24 des Exp $ -.\" $DragonFly: src/lib/pam_module/pam_ssh/pam_ssh.8,v 1.1 2005/07/12 23:26:49 joerg Exp $ +.\" $FreeBSD: src/lib/libpam/modules/pam_ssh/pam_ssh.8,v 1.15 2011/10/07 12:58:33 des Exp $ .\" -.Dd November 26, 2001 +.Dd December 24, 2011 .Dt PAM_SSH 8 .Os .Sh NAME @@ -136,6 +135,8 @@ SSH1 RSA key SSH2 RSA key .It Pa $HOME/.ssh/id_dsa SSH2 DSA key +.It Pa $HOME/.ssh/id_ecdsa +SSH2 ECDSA key .El .Sh SEE ALSO .Xr ssh-agent 1 , diff --git a/lib/pam_module/pam_ssh/pam_ssh.c b/lib/pam_module/pam_ssh/pam_ssh.c index 2f69c6f..954fb32 100644 --- a/lib/pam_module/pam_ssh/pam_ssh.c +++ b/lib/pam_module/pam_ssh/pam_ssh.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003 Networks Associates Technology, Inc. + * Copyright (c) 2004-2011 Dag-Erling Smørgrav * All rights reserved. * * This software was developed for the FreeBSD Project by ThinkSec AS and @@ -31,7 +32,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libpam/modules/pam_ssh/pam_ssh.c,v 1.45 2007/12/21 12:00:15 des Exp $ + * $FreeBSD: src/lib/libpam/modules/pam_ssh/pam_ssh.c,v 1.49 2011/11/20 15:18:49 des Exp $ */ #include @@ -77,6 +78,7 @@ static const char *pam_ssh_keyfiles[] = { ".ssh/identity", /* SSH1 RSA key */ ".ssh/id_rsa", /* SSH2 RSA key */ ".ssh/id_dsa", /* SSH2 DSA key */ + ".ssh/id_ecdsa", /* SSH2 ECDSA key */ NULL }; @@ -90,7 +92,8 @@ static char *const pam_ssh_agent_envp[] = { NULL }; * struct pam_ssh_key containing the key and its comment. */ static struct pam_ssh_key * -pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase) +pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase, + int nullok) { struct pam_ssh_key *psk; char fn[PATH_MAX]; @@ -100,13 +103,27 @@ pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase) if (snprintf(fn, sizeof(fn), "%s/%s", dir, kfn) > (int)sizeof(fn)) return (NULL); comment = NULL; - key = key_load_private(fn, passphrase, &comment); + /* + * If the key is unencrypted, OpenSSL ignores the passphrase, so + * it will seem like the user typed in the right one. This allows + * a user to circumvent nullok by providing a dummy passphrase. + * Verify that the key really *is* encrypted by trying to load it + * with an empty passphrase, and if the key is not encrypted, + * accept only an empty passphrase. + */ + key = key_load_private(fn, NULL, &comment); + if (key != NULL && !(*passphrase == '\0' && nullok)) { + key_free(key); + return (NULL); + } + if (key == NULL) + key = key_load_private(fn, passphrase, &comment); if (key == NULL) { - openpam_log(PAM_LOG_DEBUG, "failed to load key from %s\n", fn); + openpam_log(PAM_LOG_DEBUG, "failed to load key from %s", fn); return (NULL); } - openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s\n", comment, fn); + openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s", comment, fn); if ((psk = malloc(sizeof(*psk))) == NULL) { key_free(key); free(comment); @@ -167,9 +184,6 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, if (pam_err != PAM_SUCCESS) return (pam_err); - if (*passphrase == '\0' && !nullok) - goto skip_keys; - /* switch to user credentials */ pam_err = openpam_borrow_cred(pamh, pwd); if (pam_err != PAM_SUCCESS) @@ -177,7 +191,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, /* try to load keys from all keyfiles we know of */ for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) { - psk = pam_ssh_load_key(pwd->pw_dir, *kfn, passphrase); + psk = pam_ssh_load_key(pwd->pw_dir, *kfn, passphrase, nullok); if (psk != NULL) { pam_set_data(pamh, *kfn, psk, pam_ssh_free_key); ++nkeys; @@ -187,7 +201,6 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, /* switch back to arbitrator credentials */ openpam_restore_cred(pamh); - skip_keys: /* * If we tried an old token and didn't get anything, and * try_first_pass was specified, try again after prompting the @@ -312,6 +325,7 @@ pam_ssh_add_keys_to_agent(pam_handle_t *pamh) AuthenticationConnection *ac; const struct pam_ssh_key *psk; const char **kfn; + const void *item; char **envlist, **env; int pam_err; @@ -324,16 +338,16 @@ pam_ssh_add_keys_to_agent(pam_handle_t *pamh) /* get a connection to the agent */ if ((ac = ssh_get_authentication_connection()) == NULL) { + openpam_log(PAM_LOG_DEBUG, "failed to connect to the agent"); pam_err = PAM_SYSTEM_ERR; goto end; } /* look for keys to add to it */ for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) { - const void *vp; - pam_err = pam_get_data(pamh, *kfn, &vp); - psk = vp; - if (pam_err == PAM_SUCCESS && psk != NULL) { + pam_err = pam_get_data(pamh, *kfn, &item); + if (pam_err == PAM_SUCCESS && item != NULL) { + psk = item; if (ssh_add_identity(ac, psk->key, psk->comment)) openpam_log(PAM_LOG_DEBUG, "added %s to ssh agent", psk->comment);