Ethical Hacking Learn to find vulnerabilities before the bad guys do! Gain real world hands on hacking experience in our state of the art hacking lab. Course designed and taught by expert instructors with years of penetration testing experience. 12 student maximum in every class. Certification attempt included in every package. | Computer Forensics Training at InfoSec Institute Gain the in-demand skills of a certified computer examiner, learn to recover trace data left behind by fraud, theft, and cybercrime perpetrators. Discover the source of computer crime and abuse at your organization so that it never happens again. All of our class sizes are guaranteed to be 12 students or less to facilitate one-on-one interaction with one of our expert instructors. |

| Subject: | *Warning* long post - OpenSSH patch to allow requiring *both* public key and password auth |
|---|---|
| Date: | Thu, 21 Jul 2005 23:26:20 +0300 |
Greetings.
I am submitting this patch to both the OpenBSD tech mailing list and the
OpenSSH mailing list since this is a patch against the OpenBSD 3.7-
stable version of OpenSSH and should interest both groups which might
not have that much overlap.
This is a patch that adds a "RequireBothPasswordAndPubKey" authorization
option to the SSHD server. It is a hack but I tried to keep it as clean
as possible. Owing to the deep dive into the code I had to do to get
this to work, I found that the way that SSHd works is a bit strange to
me, especially with PrivSep active; authentication is done twice, both
in the privileged parent and in the child - I could most likely be
missing something here, but that is the way it seems to me, thus I had
to add my adjustments to two places in the code to get it to work.
This is an attempt to enable SSHd to be able to enforce more of a
paranoid security model in keeping with the classic "who you are"
(biometrics, fingerprints, retina scan, brainwave), "what you know"
(password), and "what you have" (smart card, private key). Since SSH
isn't able to tie into any sort of biometric scanner, as far as I know
(correct me if I'm wrong), two out of three is better than nothing.
This works for me, but I would most appreciate comments on this patch as
well as any other sets of eyes (especially any who have developed SSH!)
to be able to read this patch and let me know if I have created any
gaping security holes or race conditions.
$ diffstat ssh-both-pubkey-passwd.patch
auth.h | 9 +++++++++
auth2-passwd.c | 1 +
auth2-pubkey.c | 1 +
auth2.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
monitor.c | 3 +++
servconf.c | 12 ++++++++++++
servconf.h | 1 +
sshd_config.5 | 14 ++++++++++++++
8 files changed, 85 insertions(+), 1 deletion(-)
$ cd /usr/src
$ export CVSROOT=anoncvs@anoncvs.nyc.openbsd.org:/cvs
$ cvs -q -d$CVSROOT diff -ud -rOPENBSD_3_7 usr.bin/ssh
Index: usr.bin/ssh/auth.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth.h,v
retrieving revision 1.50
diff -u -d -r1.50 auth.h
--- usr.bin/ssh/auth.h 23 May 2004 23:59:53 -0000 1.50
+++ usr.bin/ssh/auth.h 21 Jul 2005 19:27:30 -0000
@@ -68,6 +68,14 @@
char *krb5_ticket_file;
#endif
void *methoddata;
+ union {
+ struct {
+ unsigned passwd : 1;
+ unsigned pubkey : 1;
+ } pubkey_passwd;
+ unsigned flags;
+ } multiple_auth;
+ unsigned multiple_auth_failure : 1;
};
/*
* Every authentication method has to handle authentication requests for
@@ -135,6 +143,7 @@
int auth2_challenge(Authctxt *, char *);
void auth2_challenge_stop(Authctxt *);
+void auth2_multiple_auth(const char *, Authctxt *, int *);
int bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
int bsdauth_respond(void *, u_int, char **);
int skey_query(void *, char **, char **, u_int *, char ***, u_int **);
Index: usr.bin/ssh/auth2-passwd.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth2-passwd.c,v
retrieving revision 1.5
diff -u -d -r1.5 auth2-passwd.c
--- usr.bin/ssh/auth2-passwd.c 31 Dec 2003 00:24:50 -0000 1.5
+++ usr.bin/ssh/auth2-passwd.c 21 Jul 2005 19:27:30 -0000
@@ -59,6 +59,7 @@
authenticated = 1;
memset(password, 0, len);
xfree(password);
+ auth2_multiple_auth("password", authctxt, &authenticated);
return authenticated;
}
Index: usr.bin/ssh/auth2-pubkey.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth2-pubkey.c,v
retrieving revision 1.9
diff -u -d -r1.9 auth2-pubkey.c
--- usr.bin/ssh/auth2-pubkey.c 11 Dec 2004 01:48:56 -0000 1.9
+++ usr.bin/ssh/auth2-pubkey.c 21 Jul 2005 19:27:31 -0000
@@ -129,6 +129,7 @@
authenticated = 1;
buffer_free(&b);
xfree(sig);
+ auth2_multiple_auth("publickey", authctxt, &authenticated);
} else {
debug("test whether pkalg/pkblob are acceptable");
packet_check_eom();
Index: usr.bin/ssh/auth2.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth2.c,v
retrieving revision 1.107
diff -u -d -r1.107 auth2.c
--- usr.bin/ssh/auth2.c 28 Jul 2004 09:40:29 -0000 1.107
+++ usr.bin/ssh/auth2.c 21 Jul 2005 19:27:31 -0000
@@ -210,8 +210,12 @@
/* Log before sending the reply */
auth_log(authctxt, authenticated, method, " ssh2");
- if (authctxt->postponed)
+ if (authctxt->postponed) {
+ if (!authctxt->multiple_auth_failure &&
+ authctxt->multiple_auth.flags)
+ goto fake_auth_failure;
return;
+ }
/* XXX todo: check if multiple auth methods are needed */
if (authenticated == 1) {
@@ -225,6 +229,7 @@
} else {
if (authctxt->failures++ > options.max_authtries)
packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+fake_auth_failure:
methods = authmethods_get();
packet_start(SSH2_MSG_USERAUTH_FAILURE);
packet_put_cstring(methods);
@@ -233,6 +238,44 @@
packet_write_wait();
xfree(methods);
}
+}
+
+void
+auth2_multiple_auth(const char *method, Authctxt *authctxt, int *authenticated)
+{
+ debug3("%s[%d],entry,method %s,auth(%d,%d,%d),*auth %d,postponed %d",
+ __func__, getpid(), method, authctxt->multiple_auth_failure,
+ authctxt->multiple_auth.pubkey_passwd.passwd,
+ authctxt->multiple_auth.pubkey_passwd.pubkey, *authenticated,
+ authctxt->postponed);
+
+ if (options.require_both_password_and_pub_key == 1 &&
+ (!strcasecmp(method, "password") ||
+ !strcasecmp(method, "publickey"))) {
+ if (!*authenticated && !strcasecmp(method, "publickey"))
+ authctxt->multiple_auth_failure = 1;
+ else if (!authctxt->multiple_auth_failure) {
+ if (!strcasecmp(method, "password"))
+ authctxt->
+ multiple_auth.pubkey_passwd.passwd = 1;
+ else if (!strcasecmp(method, "publickey"))
+ authctxt->
+ multiple_auth.pubkey_passwd.pubkey = 1;
+
+ if (!authctxt->multiple_auth.pubkey_passwd.passwd ||
+ !authctxt->multiple_auth.pubkey_passwd.pubkey) {
+ authctxt->postponed = 1;
+ *authenticated = 0;
+ }
+ }
+ else
+ *authenticated = 0;
+ }
+ debug3("%s[%d],exit,multiple_auth (%d,%d,%d),*auth %d,postponed %d",
+ __func__, getpid(), authctxt->multiple_auth_failure,
+ authctxt->multiple_auth.pubkey_passwd.passwd,
+ authctxt->multiple_auth.pubkey_passwd.pubkey, *authenticated,
+ authctxt->postponed);
}
#define DELIM ","
Index: usr.bin/ssh/monitor.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/monitor.c,v
retrieving revision 1.63
diff -u -d -r1.63 monitor.c
--- usr.bin/ssh/monitor.c 10 Mar 2005 22:01:05 -0000 1.63
+++ usr.bin/ssh/monitor.c 21 Jul 2005 19:27:34 -0000
@@ -290,6 +290,9 @@
if (!authenticated)
authctxt->failures++;
}
+ if ((ent->type == MONITOR_REQ_KEYVERIFY ||
+ ent->type == MONITOR_REQ_AUTHPASSWORD))
+ auth2_multiple_auth(auth_method, authctxt,
&authenticated);
}
if (!authctxt->valid)
Index: usr.bin/ssh/servconf.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.c,v
retrieving revision 1.140
diff -u -d -r1.140 servconf.c
--- usr.bin/ssh/servconf.c 10 Mar 2005 22:01:05 -0000 1.140
+++ usr.bin/ssh/servconf.c 21 Jul 2005 19:27:38 -0000
@@ -96,6 +96,7 @@
options->authorized_keys_file = NULL;
options->authorized_keys_file2 = NULL;
options->num_accept_env = 0;
+ options->require_both_password_and_pub_key = -1;
/* Needs to be accessable in many places */
use_privsep = -1;
@@ -219,6 +220,11 @@
}
if (options->authorized_keys_file == NULL)
options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
+ if (options->require_both_password_and_pub_key == -1)
+ options->require_both_password_and_pub_key = 0;
+ else if (options->require_both_password_and_pub_key == 1)
+ options->password_authentication =
+ options->pubkey_authentication = 1;
/* Turn privilege separation on by default */
if (use_privsep == -1)
@@ -249,6 +255,7 @@
sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
sGssAuthentication, sGssCleanupCreds, sAcceptEnv,
sUsePrivilegeSeparation,
+ sRequireBothPasswordAndPubKey,
sDeprecated, sUnsupported
} ServerOpCodes;
@@ -338,6 +345,7 @@
{ "authorizedkeysfile2", sAuthorizedKeysFile2 },
{ "useprivilegeseparation", sUsePrivilegeSeparation},
{ "acceptenv", sAcceptEnv },
+ { "requirebothpasswordandpubkey", sRequireBothPasswordAndPubKey },
{ NULL, sBadOption }
};
@@ -894,6 +902,10 @@
xstrdup(arg);
}
break;
+
+ case sRequireBothPasswordAndPubKey:
+ intptr = &options->require_both_password_and_pub_key;
+ goto parse_flag;
case sDeprecated:
logit("%s line %d: Deprecated option %s",
Index: usr.bin/ssh/servconf.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/servconf.h,v
retrieving revision 1.71
diff -u -d -r1.71 servconf.h
--- usr.bin/ssh/servconf.h 23 Dec 2004 23:11:00 -0000 1.71
+++ usr.bin/ssh/servconf.h 21 Jul 2005 19:27:38 -0000
@@ -93,6 +93,7 @@
* authentication. */
int kbd_interactive_authentication; /* If true, permit */
int challenge_response_authentication;
+ int require_both_password_and_pub_key;
int permit_empty_passwd; /* If false, do not permit empty
* passwords. */
int permit_user_env; /* If true, read ~/.ssh/environment */
Index: usr.bin/ssh/sshd_config.5
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sshd_config.5,v
retrieving revision 1.40
diff -u -d -r1.40 sshd_config.5
--- usr.bin/ssh/sshd_config.5 18 Mar 2005 17:05:00 -0000 1.40
+++ usr.bin/ssh/sshd_config.5 21 Jul 2005 19:27:42 -0000
@@ -566,6 +566,20 @@
The default is
.Dq yes .
Note that this option applies to protocol version 2 only.
+.It Cm RequireBothPasswordAndPubKey
+Specifies whether both password and public key authentication must
+be successful before authentication is allowed. If
+.Dq yes ,
+then this option performs both types of authentication, overriding any
+values for the
+.Cm PubkeyAuthentication
+and
+.Cm PasswordAuthentication
+options, setting both implicitly to
+.Dq yes .
+The default is
+.Dq no .
+This option applies to protocol version 2 only.
.It Cm RhostsRSAAuthentication
Specifies whether rhosts or /etc/hosts.equiv authentication together
with successful RSA host authentication is allowed.
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| ||
| Previous by Date: | Re: Duplicate ssh session, Konrad LUDWIKOWSKI |
|---|---|
| Next by Date: | Oops.. mea culpa..., Stephen Biggs |
| Previous by Thread: | login into specific directory, Guillaume Desmottes |
| Next by Thread: | Oops.. mea culpa..., Stephen Biggs |
| Indexes: | [Date] [Thread] [Top] [All Lists] |