upstream commit

remember which public keys have been used for
 authentication and refuse to accept previously-used keys.

This allows AuthenticationMethods=publickey,publickey to require
that users authenticate using two _different_ pubkeys.

ok markus@
This commit is contained in:
djm@openbsd.org 2014-12-22 07:51:30 +00:00 committed by Damien Miller
parent 46ac2ed467
commit f69b69b862
4 changed files with 70 additions and 7 deletions

9
auth.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.h,v 1.78 2014/07/03 11:16:55 djm Exp $ */
/* $OpenBSD: auth.h,v 1.79 2014/12/22 07:51:30 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -42,6 +42,8 @@
#include <krb5.h>
#endif
struct sshkey;
typedef struct Authctxt Authctxt;
typedef struct Authmethod Authmethod;
typedef struct KbdintDevice KbdintDevice;
@ -75,6 +77,9 @@ struct Authctxt {
#endif
Buffer *loginmsg;
void *methoddata;
struct sshkey **prev_userkeys;
u_int nprev_userkeys;
};
/*
* Every authentication method has to handle authentication requests for
@ -123,6 +128,8 @@ int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
int user_key_allowed(struct passwd *, Key *);
void pubkey_auth_info(Authctxt *, const Key *, const char *, ...)
__attribute__((__format__ (printf, 3, 4)));
void auth2_record_userkey(Authctxt *, struct sshkey *);
int auth2_userkey_already_used(Authctxt *, struct sshkey *);
struct stat;
int auth_secure_path(const char *, struct stat *, const char *, uid_t,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-pubkey.c,v 1.43 2014/12/21 22:27:56 djm Exp $ */
/* $OpenBSD: auth2-pubkey.c,v 1.44 2014/12/22 07:51:30 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -41,6 +41,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
#include "xmalloc.h"
#include "ssh.h"
@ -122,6 +123,10 @@ userauth_pubkey(Authctxt *authctxt)
"signature scheme");
goto done;
}
if (auth2_userkey_already_used(authctxt, key)) {
logit("refusing previously-used %s key", key_type(key));
goto done;
}
if (have_sig) {
sig = packet_get_string(&slen);
packet_check_eom();
@ -159,8 +164,12 @@ userauth_pubkey(Authctxt *authctxt)
authenticated = 0;
if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
buffer_len(&b))) == 1)
buffer_len(&b))) == 1) {
authenticated = 1;
/* Record the successful key to prevent reuse */
auth2_record_userkey(authctxt, key);
key = NULL; /* Don't free below */
}
buffer_free(&b);
free(sig);
} else {
@ -682,6 +691,35 @@ user_key_allowed(struct passwd *pw, Key *key)
return success;
}
/* Records a public key in the list of previously-successful keys */
void
auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
{
struct sshkey **tmp;
if (authctxt->nprev_userkeys >= INT_MAX ||
(tmp = reallocarray(authctxt->prev_userkeys,
authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL)
fatal("%s: reallocarray failed", __func__);
authctxt->prev_userkeys = tmp;
authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
authctxt->nprev_userkeys++;
}
/* Checks whether a key has already been used successfully for authentication */
int
auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
{
u_int i;
for (i = 0; i < authctxt->nprev_userkeys; i++) {
if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
return 1;
}
}
return 0;
}
Authmethod method_pubkey = {
"publickey",
userauth_pubkey,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor.c,v 1.135 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: monitor.c,v 1.136 2014/12/22 07:51:30 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -1170,6 +1170,7 @@ mm_answer_keyallowed(int sock, Buffer *m)
switch (type) {
case MM_USERKEY:
allowed = options.pubkey_authentication &&
!auth2_userkey_already_used(authctxt, key) &&
user_key_allowed(authctxt->pw, key);
pubkey_auth_info(authctxt, key, NULL);
auth_method = "publickey";
@ -1397,7 +1398,12 @@ mm_answer_keyverify(int sock, Buffer *m)
debug3("%s: key %p signature %s",
__func__, key, (verified == 1) ? "verified" : "unverified");
key_free(key);
/* If auth was successful then record key to ensure it isn't reused */
if (verified == 1)
auth2_record_userkey(authctxt, key);
else
key_free(key);
free(blob);
free(signature);
free(data);

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: sshd_config.5,v 1.184 2014/12/21 23:35:14 jmc Exp $
.Dd $Mdocdate: December 21 2014 $
.\" $OpenBSD: sshd_config.5,v 1.185 2014/12/22 07:51:30 djm Exp $
.Dd $Mdocdate: December 22 2014 $
.Dt SSHD_CONFIG 5
.Os
.Sh NAME
@ -210,6 +210,18 @@ would restrict keyboard interactive authentication to the
.Dq bsdauth
device.
.Pp
If the
.Dq publickey
method is listed more than one,
.Xr sshd 8
verifies that keys that have been used successfully are not reused for
subsequent authentications.
For example, an
.Cm AuthenticationMethods
of
.Dq publickey,publickey
will require successful authentication using two different public keys.
.Pp
This option is only available for SSH protocol 2 and will yield a fatal
error if enabled if protocol 1 is also enabled.
Note that each authentication method listed should also be explicitly enabled