Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
  • Loading branch information...
commit 09e61f6cd8073fbb48eab8523b4bcc4f82dac34d 1 parent 3254d1d
Peter Avalos authored
Showing with 33 additions and 18 deletions.
  1. +5 −4 lib/pam_module/pam_ssh/pam_ssh.8
  2. +28 −14 lib/pam_module/pam_ssh/pam_ssh.c
9 lib/pam_module/pam_ssh/pam_ssh.8
View
@@ -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 ,
42 lib/pam_module/pam_ssh/pam_ssh.c
View
@@ -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 <sys/param.h>
@@ -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);
Please sign in to comment.
Something went wrong with that request. Please try again.