diff options
-rw-r--r-- | auth.h | 9 | ||||
-rw-r--r-- | auth2-pubkey.c | 42 | ||||
-rw-r--r-- | monitor.c | 10 | ||||
-rw-r--r-- | sshd_config.5 | 16 |
4 files changed, 70 insertions, 7 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.h,v 1.78 2014/07/03 11:16:55 djm Exp $ */ | 1 | /* $OpenBSD: auth.h,v 1.79 2014/12/22 07:51:30 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -42,6 +42,8 @@ | |||
42 | #include <krb5.h> | 42 | #include <krb5.h> |
43 | #endif | 43 | #endif |
44 | 44 | ||
45 | struct sshkey; | ||
46 | |||
45 | typedef struct Authctxt Authctxt; | 47 | typedef struct Authctxt Authctxt; |
46 | typedef struct Authmethod Authmethod; | 48 | typedef struct Authmethod Authmethod; |
47 | typedef struct KbdintDevice KbdintDevice; | 49 | typedef struct KbdintDevice KbdintDevice; |
@@ -75,6 +77,9 @@ struct Authctxt { | |||
75 | #endif | 77 | #endif |
76 | Buffer *loginmsg; | 78 | Buffer *loginmsg; |
77 | void *methoddata; | 79 | void *methoddata; |
80 | |||
81 | struct sshkey **prev_userkeys; | ||
82 | u_int nprev_userkeys; | ||
78 | }; | 83 | }; |
79 | /* | 84 | /* |
80 | * Every authentication method has to handle authentication requests for | 85 | * Every authentication method has to handle authentication requests for |
@@ -123,6 +128,8 @@ int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); | |||
123 | int user_key_allowed(struct passwd *, Key *); | 128 | int user_key_allowed(struct passwd *, Key *); |
124 | void pubkey_auth_info(Authctxt *, const Key *, const char *, ...) | 129 | void pubkey_auth_info(Authctxt *, const Key *, const char *, ...) |
125 | __attribute__((__format__ (printf, 3, 4))); | 130 | __attribute__((__format__ (printf, 3, 4))); |
131 | void auth2_record_userkey(Authctxt *, struct sshkey *); | ||
132 | int auth2_userkey_already_used(Authctxt *, struct sshkey *); | ||
126 | 133 | ||
127 | struct stat; | 134 | struct stat; |
128 | int auth_secure_path(const char *, struct stat *, const char *, uid_t, | 135 | int auth_secure_path(const char *, struct stat *, const char *, uid_t, |
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 04b70e362..2b0486222 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.43 2014/12/21 22:27:56 djm Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.44 2014/12/22 07:51:30 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -41,6 +41,7 @@ | |||
41 | #include <string.h> | 41 | #include <string.h> |
42 | #include <time.h> | 42 | #include <time.h> |
43 | #include <unistd.h> | 43 | #include <unistd.h> |
44 | #include <limits.h> | ||
44 | 45 | ||
45 | #include "xmalloc.h" | 46 | #include "xmalloc.h" |
46 | #include "ssh.h" | 47 | #include "ssh.h" |
@@ -122,6 +123,10 @@ userauth_pubkey(Authctxt *authctxt) | |||
122 | "signature scheme"); | 123 | "signature scheme"); |
123 | goto done; | 124 | goto done; |
124 | } | 125 | } |
126 | if (auth2_userkey_already_used(authctxt, key)) { | ||
127 | logit("refusing previously-used %s key", key_type(key)); | ||
128 | goto done; | ||
129 | } | ||
125 | if (have_sig) { | 130 | if (have_sig) { |
126 | sig = packet_get_string(&slen); | 131 | sig = packet_get_string(&slen); |
127 | packet_check_eom(); | 132 | packet_check_eom(); |
@@ -159,8 +164,12 @@ userauth_pubkey(Authctxt *authctxt) | |||
159 | authenticated = 0; | 164 | authenticated = 0; |
160 | if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && | 165 | if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && |
161 | PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), | 166 | PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), |
162 | buffer_len(&b))) == 1) | 167 | buffer_len(&b))) == 1) { |
163 | authenticated = 1; | 168 | authenticated = 1; |
169 | /* Record the successful key to prevent reuse */ | ||
170 | auth2_record_userkey(authctxt, key); | ||
171 | key = NULL; /* Don't free below */ | ||
172 | } | ||
164 | buffer_free(&b); | 173 | buffer_free(&b); |
165 | free(sig); | 174 | free(sig); |
166 | } else { | 175 | } else { |
@@ -682,6 +691,35 @@ user_key_allowed(struct passwd *pw, Key *key) | |||
682 | return success; | 691 | return success; |
683 | } | 692 | } |
684 | 693 | ||
694 | /* Records a public key in the list of previously-successful keys */ | ||
695 | void | ||
696 | auth2_record_userkey(Authctxt *authctxt, struct sshkey *key) | ||
697 | { | ||
698 | struct sshkey **tmp; | ||
699 | |||
700 | if (authctxt->nprev_userkeys >= INT_MAX || | ||
701 | (tmp = reallocarray(authctxt->prev_userkeys, | ||
702 | authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL) | ||
703 | fatal("%s: reallocarray failed", __func__); | ||
704 | authctxt->prev_userkeys = tmp; | ||
705 | authctxt->prev_userkeys[authctxt->nprev_userkeys] = key; | ||
706 | authctxt->nprev_userkeys++; | ||
707 | } | ||
708 | |||
709 | /* Checks whether a key has already been used successfully for authentication */ | ||
710 | int | ||
711 | auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key) | ||
712 | { | ||
713 | u_int i; | ||
714 | |||
715 | for (i = 0; i < authctxt->nprev_userkeys; i++) { | ||
716 | if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) { | ||
717 | return 1; | ||
718 | } | ||
719 | } | ||
720 | return 0; | ||
721 | } | ||
722 | |||
685 | Authmethod method_pubkey = { | 723 | Authmethod method_pubkey = { |
686 | "publickey", | 724 | "publickey", |
687 | userauth_pubkey, | 725 | userauth_pubkey, |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor.c,v 1.135 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: monitor.c,v 1.136 2014/12/22 07:51:30 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -1170,6 +1170,7 @@ mm_answer_keyallowed(int sock, Buffer *m) | |||
1170 | switch (type) { | 1170 | switch (type) { |
1171 | case MM_USERKEY: | 1171 | case MM_USERKEY: |
1172 | allowed = options.pubkey_authentication && | 1172 | allowed = options.pubkey_authentication && |
1173 | !auth2_userkey_already_used(authctxt, key) && | ||
1173 | user_key_allowed(authctxt->pw, key); | 1174 | user_key_allowed(authctxt->pw, key); |
1174 | pubkey_auth_info(authctxt, key, NULL); | 1175 | pubkey_auth_info(authctxt, key, NULL); |
1175 | auth_method = "publickey"; | 1176 | auth_method = "publickey"; |
@@ -1397,7 +1398,12 @@ mm_answer_keyverify(int sock, Buffer *m) | |||
1397 | debug3("%s: key %p signature %s", | 1398 | debug3("%s: key %p signature %s", |
1398 | __func__, key, (verified == 1) ? "verified" : "unverified"); | 1399 | __func__, key, (verified == 1) ? "verified" : "unverified"); |
1399 | 1400 | ||
1400 | key_free(key); | 1401 | /* If auth was successful then record key to ensure it isn't reused */ |
1402 | if (verified == 1) | ||
1403 | auth2_record_userkey(authctxt, key); | ||
1404 | else | ||
1405 | key_free(key); | ||
1406 | |||
1401 | free(blob); | 1407 | free(blob); |
1402 | free(signature); | 1408 | free(signature); |
1403 | free(data); | 1409 | free(data); |
diff --git a/sshd_config.5 b/sshd_config.5 index 938ba2f1a..d2ab28136 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: sshd_config.5,v 1.184 2014/12/21 23:35:14 jmc Exp $ | 36 | .\" $OpenBSD: sshd_config.5,v 1.185 2014/12/22 07:51:30 djm Exp $ |
37 | .Dd $Mdocdate: December 21 2014 $ | 37 | .Dd $Mdocdate: December 22 2014 $ |
38 | .Dt SSHD_CONFIG 5 | 38 | .Dt SSHD_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -210,6 +210,18 @@ would restrict keyboard interactive authentication to the | |||
210 | .Dq bsdauth | 210 | .Dq bsdauth |
211 | device. | 211 | device. |
212 | .Pp | 212 | .Pp |
213 | If the | ||
214 | .Dq publickey | ||
215 | method is listed more than one, | ||
216 | .Xr sshd 8 | ||
217 | verifies that keys that have been used successfully are not reused for | ||
218 | subsequent authentications. | ||
219 | For example, an | ||
220 | .Cm AuthenticationMethods | ||
221 | of | ||
222 | .Dq publickey,publickey | ||
223 | will require successful authentication using two different public keys. | ||
224 | .Pp | ||
213 | This option is only available for SSH protocol 2 and will yield a fatal | 225 | This option is only available for SSH protocol 2 and will yield a fatal |
214 | error if enabled if protocol 1 is also enabled. | 226 | error if enabled if protocol 1 is also enabled. |
215 | Note that each authentication method listed should also be explicitly enabled | 227 | Note that each authentication method listed should also be explicitly enabled |