From eb018c057faa9d82cbcc1c4f106f1d32fedcf833 Mon Sep 17 00:00:00 2001 From: djm Date: Mon, 22 Dec 2014 07:51:30 +0000 Subject: [PATCH] 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@ --- usr.bin/ssh/auth.h | 9 +++++++- usr.bin/ssh/auth2-pubkey.c | 42 ++++++++++++++++++++++++++++++++++++-- usr.bin/ssh/monitor.c | 10 +++++++-- usr.bin/ssh/sshd_config.5 | 16 +++++++++++++-- 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/usr.bin/ssh/auth.h b/usr.bin/ssh/auth.h index 5287635fc3a..8a3eb5d77b0 100644 --- a/usr.bin/ssh/auth.h +++ b/usr.bin/ssh/auth.h @@ -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. @@ -37,6 +37,8 @@ #include #endif +struct sshkey; + typedef struct Authctxt Authctxt; typedef struct Authmethod Authmethod; typedef struct KbdintDevice KbdintDevice; @@ -66,6 +68,9 @@ struct Authctxt { char *krb5_ticket_file; #endif void *methoddata; + + struct sshkey **prev_userkeys; + u_int nprev_userkeys; }; /* * Every authentication method has to handle authentication requests for @@ -114,6 +119,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, diff --git a/usr.bin/ssh/auth2-pubkey.c b/usr.bin/ssh/auth2-pubkey.c index 6fec8e5bdfb..f880717d7b4 100644 --- a/usr.bin/ssh/auth2-pubkey.c +++ b/usr.bin/ssh/auth2-pubkey.c @@ -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. * @@ -38,6 +38,7 @@ #include #include #include +#include #include "xmalloc.h" #include "ssh.h" @@ -119,6 +120,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(); @@ -156,8 +161,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 { @@ -679,6 +688,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, diff --git a/usr.bin/ssh/monitor.c b/usr.bin/ssh/monitor.c index fb811861f71..637009c878f 100644 --- a/usr.bin/ssh/monitor.c +++ b/usr.bin/ssh/monitor.c @@ -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 * Copyright 2002 Markus Friedl @@ -884,6 +884,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"; @@ -1111,7 +1112,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); diff --git a/usr.bin/ssh/sshd_config.5 b/usr.bin/ssh/sshd_config.5 index 057eeaf961f..98985c0f7f6 100644 --- a/usr.bin/ssh/sshd_config.5 +++ b/usr.bin/ssh/sshd_config.5 @@ -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 -- 2.20.1